18

I´m migrating from Java 7 to Java 8 and I have met with this change in the language.

I have a Superinterface with an annotated method:

public interface SuperInterface {

  @X
  SuperInterface getSomething();
}

I have a SubInterface with the same annotated method but returning a sub-interface:

public interface SubInterface extends SuperInterface {

  @X
  SubInterface getSomething();
}

When I run this test, it fails in Java 8 but not in Java 7:

import java.lang.reflect.Method;

public class Test {

  public static void main(String[] args) {
    final Method[] methods = SubInterface.class.getMethods();
    for (Method method : methods) {
      if (method.getAnnotations().length == 0) {
        throw new RuntimeException("No annotations found for " + method);
      }
    }
  }
}

Interface method´s annotations are inherited in Java 7 but not in Java 8, is it true?

@X is defined as:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface X {  
}
leaqui
  • 533
  • 6
  • 22
  • No repro for `javac`/`java` `1.8.0_121`. I do get the error in eclipse though. Which java8 compiler are you using? – Jorn Vernee May 23 '17 at 14:01
  • 2
    Why is the one returning a `SuperInterface` a `default` method? In Java7 they are both `abstract`, but in Java8 that one is `default`. – Shadov May 23 '17 at 14:06
  • I use Java 1.8.0_131 – leaqui May 23 '17 at 14:07
  • 1
    @Shadov yes, in Java 8: public default SuperInterface test.SubInterface.getSomething() but in Java 7: public abstract test.SuperInterface SuperInterface.getSomething() – leaqui May 23 '17 at 14:09
  • What do you mean by “annotations are inherited”? In your example, all methods are annotated explicitly, so none of them would inherit an annotation (and annotations aren’t inherited at all)… – Holger May 23 '17 at 14:12
  • 3
    @Shadov: that’s explained in [getDeclaredMethods() behaving differently in Java 7 vs. Java 8](https://stackoverflow.com/q/27013542/2711488) – Holger May 23 '17 at 14:18
  • @Holger I mean that inherited interface methods doesn´t keep it´s own annotations in sub-interfaces – leaqui May 23 '17 at 14:20
  • 7
    Well, you are actually overriding the method `getSomething()` in `SubInterface`, hence, have no inherited method at all. It’s a technical weakness of pre-Java 8 that you can see the erased method of `SuperInterface` with Reflection. In Java 8 (using `javac`), you don’t see any inherited method, but two methods, the overriding method and a bridge method. The bridge method will have the annotations of the *overriding* method, but not inherit annotations from the `SuperInterface.getSomething()` method. – Holger May 23 '17 at 14:25

2 Answers2

21

As far as I can tell it should work with at least build 94 of java-8, according to this. Thus this is an eclipse compiler bug (I can't reproduce it with javac).

You are using covariance here and as such there will be two methods generated (one is a bridge):

 for (Method method : methods) {
        if (method.getAnnotations().length == 0) {
            System.out.println("Not present " + method.getName() + " isBridge? " + method.isBridge());
        } else {
            System.out.println("Present :" + method.getName() + " isBridge? " + method.isBridge());
        }
    }

But again this should work, since the bug clearly says : Annotation with run-time retention should be copied by javac to bridge methods.

Output with javac:

Present :getSomething isBridge? false
Present :getSomething isBridge? true

Output with eclipse compiler:

Present :getSomething isBridge? false
Not present getSomething isBridge? true
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 2
    OMG, I tested all JDKs between beta132 and update121, to conclude that it can’t be reproduced, but I should have tested versions before beta94… – Holger May 23 '17 at 14:15
  • 3
    @Holger `I tested all JDKs between beta132 and update121` you have all of them on your machine? That is seriously awesome! – Eugene May 23 '17 at 14:37
  • 3
    Maybe “all” was a bit euphemistic. I have all relevant updates, which allow to conclude that code that passes them, will work with (unpublished) in-between versions as well. The update number system makes it look much more than it actually is. The more interesting part are the scripts, which iterate over all of them to compile and run a test program… – Holger May 23 '17 at 14:44
  • 3
    @Holger that is the only thing I could think of since your comment! The scripts!!! I immediately thought of trying to create something like this for myself – Eugene May 23 '17 at 14:45
10

For the Eclipse ecj compiler this looks like Eclipse bug 495396 which references JDK 6695379.

It is marked as targeted for 4.7 but 4.7 is already in release candidate status so I guess it didn't get in.

greg-449
  • 109,219
  • 232
  • 102
  • 145