diff --git a/README.md b/README.md index 49734a34..89afd6a3 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,12 @@ package-private. Version History --------------- +### Upcoming + +- Fixed a crash when trying backport classes that are part of the JRE, but + the JRE's class differs from the class being backported + ([Issue #29](https://github.com/orfjackal/retrolambda/issues/29)) + ### Retrolambda 1.6.0 (2014-08-20) - Does not anymore require the use of a Java agent diff --git a/end-to-end-tests/src/test/java/com/sun/javafx/application/LauncherImpl.java b/end-to-end-tests/src/test/java/com/sun/javafx/application/LauncherImpl.java new file mode 100644 index 00000000..73bca7c7 --- /dev/null +++ b/end-to-end-tests/src/test/java/com/sun/javafx/application/LauncherImpl.java @@ -0,0 +1,19 @@ +// Copyright © 2013-2014 Esko Luontola +// This software is released under the Apache License 2.0. +// The license text is at http://www.apache.org/licenses/LICENSE-2.0 + +package com.sun.javafx.application; + +import net.orfjackal.retrolambda.test.ClasspathTest; + +/** + * @see ClasspathTest#prefers_classes_in_explicit_classpath_over_classes_in_the_JRE + */ +@SuppressWarnings("UnusedDeclaration") +public class LauncherImpl { + + public Runnable foo() { + return () -> { + }; + } +} diff --git a/end-to-end-tests/src/test/java/net/orfjackal/retrolambda/test/ClasspathTest.java b/end-to-end-tests/src/test/java/net/orfjackal/retrolambda/test/ClasspathTest.java index 9e33c5df..876cefff 100644 --- a/end-to-end-tests/src/test/java/net/orfjackal/retrolambda/test/ClasspathTest.java +++ b/end-to-end-tests/src/test/java/net/orfjackal/retrolambda/test/ClasspathTest.java @@ -11,6 +11,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertNotNull; public class ClasspathTest { @@ -45,4 +46,15 @@ public Runnable foo() { } new RequiresMainClassesInTestClasspath().foo(); } + + /** + * This is to reproduce a bug where trying to backport a development + * version of JavaFX classes fails because the same classes also exist in + * the JRE's extension directory and Retrolambda accidentally loads the + * old built-in class instead of the new class that is being transformed. + */ + @Test + public void prefers_classes_in_explicit_classpath_over_classes_in_the_JRE() { + assertNotNull(getClass().getResource("/com/sun/javafx/application/LauncherImpl$$Lambda$1.class")); + } } diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/NonDelegatingClassLoader.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/NonDelegatingClassLoader.java new file mode 100644 index 00000000..edfc58e4 --- /dev/null +++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/NonDelegatingClassLoader.java @@ -0,0 +1,27 @@ +// Copyright © 2013-2014 Esko Luontola +// This software is released under the Apache License 2.0. +// The license text is at http://www.apache.org/licenses/LICENSE-2.0 + +package net.orfjackal.retrolambda; + +import java.net.*; + +public class NonDelegatingClassLoader extends URLClassLoader { + + public NonDelegatingClassLoader(URL[] urls) { + super(urls); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + Class c = findLoadedClass(name); + if (c != null) { + return c; + } + try { + return findClass(name); + } catch (ClassNotFoundException e) { + return super.loadClass(name); + } + } +} diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java index 5f2f0de3..06ddc0be 100644 --- a/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java +++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java @@ -30,7 +30,7 @@ public static void run(Config config) throws Throwable { return; } - Thread.currentThread().setContextClassLoader(new URLClassLoader(asUrls(classpath))); + Thread.currentThread().setContextClassLoader(new NonDelegatingClassLoader(asUrls(classpath))); try (LambdaClassDumper dumper = new LambdaClassDumper(new LambdaClassSaver(outputDir, bytecodeVersion))) { if (!PreMain.isAgentLoaded()) {