Java 8 javac wrong return type for a generic method

Mehmet Dogan mehmet at hazelcast.com
Thu Nov 13 12:59:27 UTC 2014


Hi,

I faced a weird compiler issue (or at least I looked weird to me) while
compiling & running a unit test on Java8. It was running on Java 6 & 7
without a problem. Then I created a very basic sample to reproduce it
locally.

Test includes 3 interfaces, 1 implementation and 1 test class.

*public interface ParentA<T> {*
*    T process() throws Exception;*
*}*

*public interface ParentB<T> {*
*    T process() throws Exception;*
*}*

*public interface Child<T> extends ParentA<T>, ParentB<T> {*
*   // **everything works fine **when this line is uncommented *
*   // T process() throws Exception;*
*}*

*public class ChildImpl<T> implements Child<T> {*
*    @Override*
*    public T process() {*
*        return null;*
*    }*
*}*

*public class Test {*
*    public static void main(String[] args) throws Exception {*
*        Child<String> child = new ChildImpl<String>();*
*        String result = child.process();*
*        System.err.println(result);*
*    }*
*}*


1 - When I compile these with javac 8 and run the main method in Test
class, it fails with the following exception:

*Exception in thread "main" java.lang.NoSuchMethodError:
Child.process()Ljava/lang/String;*
* at Test.main(Test.java:5)*


2 - When I uncomment overriding method definition in `*Child*` interface,
then it works fine.

*public interface Child<T> extends ParentA<T>, ParentB<T> {*
*   T process() throws Exception;*
*}*

3 - When I remove `*throws Exception*` declaration from `*process*` method,
then it works fine again.


Then I looked at the disassembled bytecode of the Test.class and saw in
Java 6 and 7 versions there is an additional `checkcast` instruction after
`Child.process()` method call. See;

- *With Java8:*

*public class Test {*
*  public Test();*
*    Code:*
*       0: aload_0*
*       1: invokespecial #1                  // Method
java/lang/Object."<init>":()V*
*       4: return*

*  public static void main(java.lang.String[]) throws java.lang.Exception;*
*    Code:*
*       0: new           #2                  // class ChildImpl*
*       3: dup*
*       4: invokespecial #3                  // Method
ChildImpl."<init>":()V*
*       7: astore_1*
*       8: aload_1*
*       9: invokeinterface #4,  1            // InterfaceMethod
Child.process:()Ljava/lang/String;*
*      14: astore_2*
*      15: getstatic     #5                  // Field
java/lang/System.err:Ljava/io/PrintStream;*
*      18: aload_2*
*      19: invokevirtual #6                  // Method
java/io/PrintStream.println:(Ljava/lang/String;)V*
*      22: return*
*}*

*- With Java7:*

*Compiled from "Test.java"*
*public class Test {*
*  public Test();*
*    Code:*
*       0: aload_0*
*       1: invokespecial #1                  // Method
java/lang/Object."<init>":()V*
*       4: return*

*  public static void main(java.lang.String[]) throws java.lang.Exception;*
*    Code:*
*       0: new           #2                  // class ChildImpl*
*       3: dup*
*       4: invokespecial #3                  // Method
ChildImpl."<init>":()V*
*       7: astore_1*
*       8: aload_1*
*       9: invokeinterface #4,  1            // InterfaceMethod
Child.process:()Ljava/lang/Object;*
*      14: checkcast     #5                  // class java/lang/String*
*      17: astore_2*
*      18: getstatic     #6                  // Field
java/lang/System.err:Ljava/io/PrintStream;*
*      21: aload_2*
*      22: invokevirtual #7                  // Method
java/io/PrintStream.println:(Ljava/lang/String;)V*
*      25: return*
*}*


Javac 8 is expecting to call a method with return type of String
(*InterfaceMethod
Child.process:()Ljava/lang/String)*, but on Java 7 version is expecting a
method with return type of Object (*InterfaceMethod
Child.process:()Ljava/lang/Object*) which is expected because of
type-erasure then it's checking type of returning value with `checkcast`
instruction.


Test environment:

Centos 6.6 & OSX 10.10

javac 1.8.0_25
openjdk version "1.8.0_25"
OpenJDK Runtime Environment (build 1.8.0_25-b17)
OpenJDK 64-Bit Server VM (build 25.20-b23, mixed mode)

javac 1.7.0_71
java version "1.7.0_71"
OpenJDK Runtime Environment (rhel-2.5.3.1.el6-x86_64 u71-b14)
OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)

Is this an expected situation, is there something I'm understanding/using
wrong? Or is this a bug/problem in Java 8 compiler?

Thanks.


*Mehmet Dogan*mehmet at hazelcast.com
@mmdogan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20141113/d1ecaa5a/attachment-0001.html>


More information about the compiler-dev mailing list