Annotations on return-overridden methods also end up on bridge methods

Vicente-Arturo Romero-Zaldivar vicente.romero at oracle.com
Thu Nov 21 03:20:37 PST 2013


Hi Charles,

Comments below.

On 21/11/13 08:16, Charles Oliver Nutter wrote:
> Hey there!
>
> Sorry if this has been asked before, but I've been trying to get JRuby
> to compile properly on JDK8 javac and noticed a change.
>
> JDK8 generates bridge methods in cases where a child class overrides a
> superclass method with a more specific return type. This may have been
> present in JDK7 and lower, I'm not sure.
>
> What does seem to be different is that annotations attached to the
> hand-written override are also being attached to the bridge method.
>
> An example from JRuby...
>
> RubyBasicObject defines op_equal:
>
> public class RubyBasicObject ... {
> ...
>      @Override
>      public IRubyObject op_equal(ThreadContext context, IRubyObject obj) {
>          return op_equal_19(context, obj);
>      }
> ...
> }
>
> RubyMethod extends RubyObject which extends RubyBasicObject, and it
> also overrides op_equal with a more specific return type:
>
> public class RubyMethod extends RubyObject {
> ...
>      @JRubyMethod(name = "==", required = 1)
>      @Override
>      public RubyBoolean op_equal(ThreadContext context, IRubyObject other) {
> ...
> }
>
> We use the JRubyMethod annotation to generate stubs for binding the
> Ruby class's methods at boot time. These stubs are generated by
> walking declared methods looking for the JRubyMethod annotation.
>
> However, on JDK8, we get an error like this:
>
> Exception in thread "main" java.lang.ClassFormatError: Duplicate
> method name&signature in class file
> org/jruby/RubyMethod$INVOKER$i$op_equal
>
> This is because JDK8's generated IRubyObject-returning bridge method
> also has the JRubyMethod annotation.
>
> Here's the relevant entry in the constant pool:
>
> system ~/projects/jruby $ javap -v -cp core/target/classes/ org.jruby.RubyMethod
> Classfile /Users/headius/projects/jruby/core/target/classes/org/jruby/RubyMethod.class
> ...
>    #122 = Utf8               RuntimeVisibleAnnotations
>    #123 = Utf8               Lorg/jruby/anno/JRubyMethod;
>    #124 = Utf8               name
>
> Here's the hand-written method plus RuntimeVisibleAnnotations:
>
>    public org.jruby.RubyBoolean
> op_equal(org.jruby.runtime.ThreadContext,
> org.jruby.runtime.builtin.IRubyObject);
>      descriptor:
> (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/RubyBoolean;
>      ...
>      RuntimeVisibleAnnotations:
>        0: #123(#124=[s#149],#150=I#137)
>
> And here's the bridge method, which also acquires this annotation:
>
>            public org.jruby.runtime.builtin.IRubyObject
> op_equal(org.jruby.runtime.ThreadContext,
> org.jruby.runtime.builtin.IRubyObject);
>              descriptor:
> (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;
>              flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
>              ...
>              RuntimeVisibleAnnotations:
>                0: #123(#124=[s#149],#150=I#137)
>
> I'm not arguing that this is correct or incorrect behavior...merely
> that it is a change, and it may bite others the same way it has bitten
> us. I have patched our stub generator to skip bridge methods, but it
> feels kinda wrong.

This is not a bug but intended behavior, I implemented this as a feature 
request, see [1]. Some users asked this as a nice to have feature :)

[1] https://bugs.openjdk.java.net/browse/JDK-6695379

>
> - Charlie



More information about the compiler-dev mailing list