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