Search code examples
javarefactoringimplementsautomated-refactoringfunctional-interface

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.


Solution

  • 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: