Search code examples
javainterfacecode-generation

Is there a way to check if some generated code adheres to an interface when its not using the implements keyword?


I have some generated code that I can't modify. This also means, I can't add the implements keyword to the class declaration.

I want to implement a method that can take an instance of that class and assumes a number of methods are implemented there. Ideally, this should be enforced by the compiler

I could do this at runtime using reflection. But I'm trying to avoid it, because of the disadvantages of using reflection (performance, readability, ...). I'd also have to deal with runtime errors instead of compiler errors in case a class doesn't adhere to an interface.

Example:

  public interface Foo {
    boolean foo();
  }

  public class Bar {
    // Doesn't implement Foo interface but adheres to it
    boolean foo() {
      return true;
    }
  }

  public class Bar2 {
    // Doesn't implement or adhere to interface
    boolean bar() {
      return false;
    }
  }

Now I have some method:

  public someMethod(Foo foo) {
    System.out.println(foo.foo());
  }

That I could call like this:

  someMethod(new Bar()); // I want something similar to this that compiles, Bar adheres to Foo
  someMethod(new Bar2()); // I'd like to have a compile-time error, Bar2 doesn't adhere to Foo

Is this possible in Java?


Solution

  • Wrap them in a delegating class which does implement the interface.

    class NiceFoo implements Bar {
        private final Foo delegate;
    
        NiceFoo(final Foo delegate) {
            this.delegate = delegate;
        }
    
        @Override
        void bar() {
            delegate.bar();
        }
    }
    

    If you can't be bothered with the boilerplate, Lombok to the rescue. This is fully equivalent to the above, and will automatically delegate any methods added to Bar. If Foo doesn't have the relevant method, you'll get a compile-time error.

    @AllArgsConstructor
    class NiceFoo implements Bar {
        @Delegate(types = Bar.class)
        private final Foo foo;
    }