Stefan Dollase Stefan Dollase - 26 days ago 8
Java Question

Annotation to support refactoring of a functional interface

Consider the following example:

public interface Greeter {
String greet();
}

public class ExplicitGreeterImpl implements Greeter {
@Override
public String greet() {
return "Hello World!";
}
}

public class ImplicitGreeterImpl {
public String doTheGreeting() {
return "Hello World!";
}
}

private void run() {
System.out.println(new ExplicitGreeterImpl().greet());

Greeter foo = new ImplicitGreeterImpl()::doTheGreeting;
System.out.println(foo.greet());
}


The functional interface
Greeter
has two implementations.
ExplicitGreeterImpl
implements
Greeter
using the
implements
clause, while
ImplicitGreeterImpl::doTheGreeting
implements
Greeter
without it. Nevertheless,
ImplicitGreeterImpl::doTheGreeting
is designed to implement
Greeter
, just like
ExplicitGreeterImpl
.

Now, I want to refactor the
Greeter
interface, so I can pass a name to it:

public interface Greeter {
String greet(String name);
}


I can do this with the Change Method Signature refactoring provided by Eclipse (I am sure other IDEs have a similar refactoring). This automatically updates all implementations and usages of the
Greeter
interface. Implementations receive the new parameter, while usages pass a configurable default value. This works fine for the
ExplicitGreeterImpl
, however the refactoring does not touch the
ImplicitGreeterImpl::doTheGreeting
method. Thus, the assignment

Greeter foo = new ImplicitGreeterImpl()::doTheGreeting;


becomes a compile-time error. To fix this, I have to manually adjust the signature of the method
ImplicitGreeterImpl::doTheGreeting
.

Now, I understand that it is undesirable in many cases to automatically adjust the signature of
ImplicitGreeterImpl::doTheGreeting
. However, I feel that the current workflow can be improved:


  • Eclipse does not display a warning in the refactoring preview that suggests that there will be a compile-time error.

  • It should be possible to annotate the method to clarify that it is supposed to implement a given functional interface.



For example,
ImplicitGreeterImpl
could look like this:

public class ImplicitGreeterImpl {
@Implements(Greeter.class)
public String doTheGreeting() {
return "Hello World!";
}
}


Now, refactoring tools could be sure that
ImplicitGreeterImpl::doTheGreeting
is supposed to implement
Greeter
and thus, they can automatically change its signature.

Thus, my question is: Is there a way to tell refactoring tools that a given method is supposed to implement a given functional interface? I searched for the annotation proposed above, but I did not find anything useful.

Answer

I kept searching for an answer, but there does not seem to be a solution that uses an annotation. However, when asking the question I had a specific use case in mind: I want to write down many different implementations of the same functional interface in a single file. Indeed, there is a solution for this problem, which also works great with automatic refactoring tools:

public interface Greeter {
    String greet();
}

public enum EnumGreeterImpl implements Greeter {
    GREETER1 {
        @Override
        public String greet() {
            return "Hello World!";
        }
    },
    GREETER2 {
        @Override
        public String greet() {
            return "Foo bar";
        }
    },
}

private void run() {
    Greeter foo = EnumGreeterImpl.GREETER1;
    System.out.println(foo.greet());
}

See also:

Comments