<div dir="ltr"><div>Hi,</div><div><br></div><div>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. </div><div><br></div><div>Test includes 3 interfaces, 1 implementation and 1 test class. </div><div><br></div><div><div><i>public interface ParentA<T> {</i></div><div><i>    T process() throws Exception;</i></div><div><i>}</i></div></div><div><i><br></i></div><div><div><i>public interface ParentB<T> {</i></div><div><i>    T process() throws Exception;</i></div><div><i>}</i></div></div><div><br></div><div><div><i>public interface Child<T> extends ParentA<T>, ParentB<T> {</i></div><div><i> <b>  // </b></i><i><b>everything works fine </b></i><i><b>when this line is uncommented </b></i></div><div><i>   // T process() throws Exception;</i></div><div><i>}</i></div></div><div><i><br></i></div><div><div><i>public class ChildImpl<T> implements Child<T> {</i></div><div><i>    @Override</i></div><div><i>    public T process() {</i></div><div><i>        return null;</i></div><div><i>    }</i></div><div><i>}</i></div></div><div><i><br></i></div><div><div><i>public class Test {</i></div><div><i>    public static void main(String[] args) throws Exception {</i></div><div><i>        Child<String> child = new ChildImpl<String>();</i></div><div><i>        String result = child.process();</i></div><div><i>        System.err.println(result);</i></div><div><i>    }</i></div><div><i>}</i></div></div><div><br></div><div><br></div><div>1 - When I compile these with javac 8 and run the main method in Test class, it fails with the following exception:</div><div><br></div><div><div><i>Exception in thread "main" java.lang.NoSuchMethodError: Child.process()Ljava/lang/String;</i></div><div><i><span class="" style="white-space:pre">  </span>at Test.main(Test.java:5)</i></div></div><div><br></div><div><br></div><div>2 - When I uncomment overriding method definition in `<i>Child</i>` interface, then it works fine.</div><div><div><i><br></i></div><div><i>public interface Child<T> extends ParentA<T>, ParentB<T> {</i></div><div><i>   T process() throws Exception;</i></div><div><i>}</i></div></div><div><br></div><div>3 - When I remove `<i>throws Exception</i>` declaration from `<i>process</i>` method, then it works fine again.</div><div><br></div><div><br></div><div>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;</div><div><br></div><div>- <b>With Java8:</b> </div><div><br></div><div><div><i>public class Test {</i></div><div><i>  public Test();</i></div><div><i>    Code:</i></div><div><i>       0: aload_0</i></div><div><i>       1: invokespecial #1                  // Method java/lang/Object."<init>":()V</i></div><div><i>       4: return</i></div><div><i><br></i></div><div><i>  public static void main(java.lang.String[]) throws java.lang.Exception;</i></div><div><i>    Code:</i></div><div><i>       0: new           #2                  // class ChildImpl</i></div><div><i>       3: dup</i></div><div><i>       4: invokespecial #3                  // Method ChildImpl."<init>":()V</i></div><div><i>       7: astore_1</i></div><div><i>       8: aload_1</i></div><div><i><b>       9: invokeinterface #4,  1            // InterfaceMethod Child.process:()Ljava/lang/String;</b></i></div><div><i>      14: astore_2</i></div><div><i>      15: getstatic     #5                  // Field java/lang/System.err:Ljava/io/PrintStream;</i></div><div><i>      18: aload_2</i></div><div><i>      19: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V</i></div><div><i>      22: return</i></div><div><i>}</i></div></div><div><br></div><div><b>- With Java7:</b></div><div><i><br></i></div><div><div><i>Compiled from "Test.java"</i></div><div><i>public class Test {</i></div><div><i>  public Test();</i></div><div><i>    Code:</i></div><div><i>       0: aload_0</i></div><div><i>       1: invokespecial #1                  // Method java/lang/Object."<init>":()V</i></div><div><i>       4: return</i></div><div><i><br></i></div><div><i>  public static void main(java.lang.String[]) throws java.lang.Exception;</i></div><div><i>    Code:</i></div><div><i>       0: new           #2                  // class ChildImpl</i></div><div><i>       3: dup</i></div><div><i>       4: invokespecial #3                  // Method ChildImpl."<init>":()V</i></div><div><i>       7: astore_1</i></div><div><i>       8: aload_1</i></div><div><i><b>       9: invokeinterface #4,  1            // InterfaceMethod Child.process:()Ljava/lang/Object;</b></i></div><div><i><b>      14: checkcast     #5                  // class java/lang/String</b></i></div><div><i>      17: astore_2</i></div><div><i>      18: getstatic     #6                  // Field java/lang/System.err:Ljava/io/PrintStream;</i></div><div><i>      21: aload_2</i></div><div><i>      22: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V</i></div><div><i>      25: return</i></div><div><i>}</i></div></div><div><br></div><div><br></div><div>Javac 8 is expecting to call a method with return type of String (<i>InterfaceMethod Child.process:()Ljava/lang/String)</i>, but on Java 7 version is expecting a method with return type of Object (<i>InterfaceMethod Child.process:()Ljava/lang/Object</i>) which is expected because of type-erasure then it's checking type of returning value with `checkcast` instruction.</div><div><br></div><div><br></div><div>Test environment: </div><div><br></div><div>Centos 6.6 & OSX 10.10</div><div><br></div><div>javac 1.8.0_25<br></div><div><div>openjdk version "1.8.0_25"</div><div>OpenJDK Runtime Environment (build 1.8.0_25-b17)</div><div>OpenJDK 64-Bit Server VM (build 25.20-b23, mixed mode)</div></div><div><br></div><div>javac 1.7.0_71<br></div><div><div>java version "1.7.0_71"</div><div>OpenJDK Runtime Environment (rhel-2.5.3.1.el6-x86_64 u71-b14)</div><div>OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)</div></div><div><br></div><div>Is this an expected situation, is there something I'm understanding/using wrong? Or is this a bug/problem in Java 8 compiler?</div><div><br></div><div>Thanks.</div><div><br></div><div><div class="gmail_signature"><div dir="ltr"><div><font color="#888888"><b>Mehmet Dogan<br></b></font><font color="#888888"><a href="mailto:mehmet@hazelcast.com" style="color:rgb(17,85,204)" target="_blank">mehmet@hazelcast.com</a> <br>@mmdogan</font><br></div></div></div></div>
</div>