Skip to content

Java 9 question & issue #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
csoroiu opened this issue Jan 11, 2017 · 9 comments
Closed

Java 9 question & issue #119

csoroiu opened this issue Jan 11, 2017 · 9 comments

Comments

@csoroiu
Copy link
Contributor

csoroiu commented Jan 11, 2017

Are there any plans to support java 9, meaning that the generated bytecode should be compatible with java 9, right?

I'm asking this because I encountered an interesting issue:

I have a project lambdamatchers which has some lambdas based on Stream class, which I agree they are not supposed to work on Java < 8.

I run retrolambda on the classes and after I run unit tests using Java 8, it works fine with the code created by retrolambda (using as a target 1.5, 1.6, 1.7 and even 1.8), but when running the unit tests using Java 9 i get the IncompatibleClassChangeError:

java.lang.IncompatibleClassChangeError: Method java.util.stream.Stream.of([Ljava/lang/Object;)Ljava/util/stream/Stream; must be InterfaceMethodref constant
    at ro.derbederos.hamcrest.StreamTest.streamOf(StreamTest.java:32)
...

This can be easily reproduced with:

public class StreamTest {
    @Test
    public void streamIsEmpty() {
        Stream.empty();
    }
}

Stream::empty is a static interface method, maybe the way they are invoked is the issue.

Also, running unit tests with Java 9 without retrolambda-ing the project does not reproduce the issue.
I'm not 100% sure, but this might to be an issue with the jvm.

Note: This is not a real issue, I observed it during some tests, but I can work around it, as only the test code had issues, but I wanted to bring it into attention. Hopefully this does not cause problems for anybody. The test code in my case can be read as "the client code" and the client should not use retrolambda if the target is Java >= 8.

@luontola
Copy link
Owner

luontola commented Jan 11, 2017

This seems to be a case of Java 9 having better bytecode validation than Java 8. Retrolambda is unable to backport calls to default methods in foreign APIs (JDK or third-party libraries), so the results are undefined. Retrolambda needs to change invokestatic instructions to refer to normal method references instead of interface method references for them to work on Java < 8: https://github.com/orfjackal/retrolambda/blob/master/retrolambda/src/main/java/net/orfjackal/retrolambda/interfaces/FixInvokeStaticOnInterfaceMethod.java#L32

@luontola
Copy link
Owner

Here is the javap output of the method in question. The diff is between before running Retrolambda (-) and after running it (+).

   public void streamIsEmpty();
     descriptor: ()V
     flags: ACC_PUBLIC
     Code:
       stack=1, locals=1, args_size=1
-         0: invokestatic  #2                  // InterfaceMethod java/util/stream/Stream.empty:()Ljava/util/stream/Stream;
+         0: invokestatic  #19                 // Method java/util/stream/Stream.empty:()Ljava/util/stream/Stream;
          3: pop
          4: return

@luontola
Copy link
Owner

If the code produced by Retrolambda can be run on Java 7, then it should also run on Java 8 and 9. There are no guarantees for code which uses APIs that don't exist on Java 7.

@csoroiu
Copy link
Contributor Author

csoroiu commented Jan 11, 2017

Thanks, so as I suspected, the Java 9 byte-code verifier got better.

@MastaP
Copy link

MastaP commented Sep 22, 2017

My maven build fails with when compiling with Java 9
[ERROR] Failed to execute goal net.orfjackal.retrolambda:retrolambda-maven-plugin:2.5.0:process-main (default) on project xhub-agent-pom: Failed to run Retrolambda: Method java.util.stream.Stream.of([Ljava/lang/Object;)Ljava/util/stream/Stream; must be InterfaceMethodref constant -> [Help 1]

Caused by: java.lang.IncompatibleClassChangeError: Method java.util.stream.Stream.of([Ljava/lang/Object;)Ljava/util/stream/Stream; must be InterfaceMethodref constant at net.orfjackal.retrolambda.SystemPropertiesConfig.parsePathList(SystemPropertiesConfig.java:158) at net.orfjackal.retrolambda.SystemPropertiesConfig.getClasspath(SystemPropertiesConfig.java:148) at net.orfjackal.retrolambda.Retrolambda.run(Retrolambda.java:25) at net.orfjackal.retrolambda.maven.ProcessClassesMojo.processClassesInCurrentProcess(ProcessClassesMojo.java:143) ... 31 more

is there a way to workaround this?

@luontola
Copy link
Owner

luontola commented Sep 22, 2017

Are you using java.util.stream.Stream? Retrolambda is unable to backport the usage of Java 8+ APIs. You can use for example https://sourceforge.net/projects/streamsupport/ instead.

@luontola
Copy link
Owner

luontola commented Sep 22, 2017

Hmm, now that I look at the stack trace more closely, it's coming from Retrolambda's code (it's the commandline parsing which happens before your code is even loaded). Please create a new issue. Preferrably with a sample project for reproducing the issue (http://sscce.org/).

@luontola
Copy link
Owner

As a workaround you could try configuring <fork>true</fork> for the Maven plugin, possibly also configuring java8home to point to a Java 8 installation.
http://orfjackal.github.io/retrolambda/retrolambda-maven-plugin/process-main-mojo.html#fork
http://orfjackal.github.io/retrolambda/retrolambda-maven-plugin/process-main-mojo.html#java8home

@MastaP
Copy link

MastaP commented Sep 22, 2017

Fails with
[ERROR] Failed to execute goal net.orfjackal.retrolambda:retrolambda-maven-plugin:2.5.1:process-main (default) on project xhub-mappings: Unable to execute mojo: An Ant BuildException has occured: exec returned: 1 [ERROR] around Ant part ...<exec failonerror="true" executable="/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/java">... @ 4:115 in /Users/pavelg/zt/pacman/xhub-agent/xhub-mappings/target/antrun/build-main.xml [ERROR] -> [Help 1] org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal net.orfjackal.retrolambda:retrolambda-maven-plugin:2.5.1:process-main (default) on project xhub-mappings: Unable to execute mojo at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212) ...
Caused by: org.apache.maven.plugin.MojoExecutionException: Unable to execute mojo at org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo(MojoExecutor.java:96) at net.orfjackal.retrolambda.maven.ProcessClassesMojo.processClassesInForkedProcess(ProcessClassesMojo.java:158) at net.orfjackal.retrolambda.maven.ProcessClassesMojo.execute(ProcessClassesMojo.java:112) at net.orfjackal.retrolambda.maven.ProcessMainClassesMojo.execute(ProcessMainClassesMojo.java:17) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)

also, specifying java8home on all environments is not convenient. I'll try to come up with SSCCE later, if still needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants