[shadowloader] Fix for lombok v1.16.0 no longer working in eclipses that use -target 1.4 style class files (such as eclipse indigo). It’s a doozy.

This commit is contained in:
Reinier Zwitserloot committed 2015-02-08 14:18:34 +01:00
1 parent fd12196eea
commit 65de4693eb
5 files changed
+160 -67

No files matched your search

+18
View File
@@ -173,6 +173,23 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<fileset dir="build/lombok-utils" />
</copy>
<mkdir dir="build/transformedSources" />
<copy todir="build/transformedSources">
<fileset dir="src/eclipseAgent">
<include name="**/*Transplants.java" />
</fileset>
<filterchain>
<lineContainsRegExp negate="true">
<regexp pattern="^\s*@SuppressWarnings.*$" />
</lineContainsRegExp>
</filterchain>
</copy>
<ivy:compile destdir="build/lombok" source="1.4" target="1.4" includeantruntime="false">
<compilerarg value="-Xbootclasspath/p:build/stubs${path.separator}lib/openJDK6Environment/rt-openjdk6.jar" />
<src path="build/transformedSources" />
</ivy:compile>
<ivy:compile destdir="build/lombok" source="1.5" target="1.5" includeantruntime="false">
<compilerarg value="-Xbootclasspath/p:build/stubs${path.separator}lib/openJDK6Environment/rt-openjdk6.jar" />
<src path="src/launch" />
@@ -180,6 +197,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<src path="src/installer" />
<src path="src/eclipseAgent" />
<exclude name="lombok/javac/**" />
<exclude name="**/*Transplants.java" />
<classpath location="build/lombok" />
<classpath refid="build.path" />
</ivy:compile>
+1
View File
@@ -7,6 +7,7 @@ Lombok Changelog
* BUGFIX: The ant `delombok` task was broken starting with v1.16.0. Note that the task def class has been changed; taskdef `lombok.delombok.ant.Tasks$Delombok` instead of the old `lombok.delombok.ant.DelombokTask`. [Issue #775](https://code.google.com/p/projectlombok/issues/detail?id=775).
* BUGFIX: `val` in javac would occasionally fail if used inside inner classes. This is (probably) fixed. [Issue #694](https://code.google.com/p/projectlombok/issues/detail?id=694).
* BUGFIX: Starting with v1.16.0, lombok would fail to execute as an executable jar if it was in a path was spaced in it. [Issue #777](https://code.google.com/p/projectlombok/issues/detail?id=777).
* BUGFIX: v1.16.0 did not work in old eclipse versions (such as eclipse indigo).
### v1.16.0 "Candid Duck" (January 26th, 2015)
* BUGFIX: `@ExtensionMethod` was broken in Eclipse using java 8. [Issue #742](https://code.google.com/p/projectlombok/issues/detail?id=742), [Issue #747](https://code.google.com/p/projectlombok/issues/detail?id=747)
@@ -1,13 +1,26 @@
/*
* Copyright (C) 2015 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.eclipse.agent;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import lombok.patcher.ClassRootFinder;
import lombok.patcher.Hook;
import lombok.patcher.MethodTarget;
@@ -16,62 +29,7 @@ import lombok.patcher.StackRequest;
import lombok.patcher.scripts.ScriptBuilder;
public class EclipseLoaderPatcher {
public static boolean overrideLoadDecide(ClassLoader original, String name, boolean resolve) {
return name.startsWith("lombok.");
}
public static Class<?> overrideLoadResult(ClassLoader original, String name, boolean resolve) throws ClassNotFoundException {
try {
Field shadowLoaderField = original.getClass().getField("lombok$shadowLoader");
ClassLoader shadowLoader = (ClassLoader) shadowLoaderField.get(original);
if (shadowLoader == null) {
String jarLoc = (String) original.getClass().getField("lombok$location").get(null);
JarFile jf = new JarFile(jarLoc);
InputStream in = null;
try {
ZipEntry entry = jf.getEntry("lombok/launch/ShadowClassLoader.class");
in = jf.getInputStream(entry);
byte[] bytes = new byte[65536];
int len = 0;
while (true) {
int r = in.read(bytes, len, bytes.length - len);
if (r == -1) break;
len += r;
if (len == bytes.length) throw new IllegalStateException("lombok.launch.ShadowClassLoader too large.");
}
in.close();
Class<?> shadowClassLoaderClass; {
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
shadowClassLoaderClass = (Class<?>) defineClassMethod.invoke(original, "lombok.launch.ShadowClassLoader", bytes, 0, len);
}
Constructor<?> constructor = shadowClassLoaderClass.getDeclaredConstructor(ClassLoader.class, String.class, String.class, String[].class);
constructor.setAccessible(true);
shadowLoader = (ClassLoader) constructor.newInstance(original, "lombok", jarLoc, new String[] {"lombok."});
shadowLoaderField.set(original, shadowLoader);
} finally {
if (in != null) in.close();
jf.close();
}
}
if (resolve) {
Method m = shadowLoader.getClass().getDeclaredMethod("loadClass", String.class, boolean.class);
m.setAccessible(true);
return (Class<?>) m.invoke(shadowLoader, name, true);
} else {
return shadowLoader.loadClass(name);
}
} catch (Exception ex) {
Throwable t = ex;
if (t instanceof InvocationTargetException) t = t.getCause();
if (t instanceof RuntimeException) throw (RuntimeException) t;
if (t instanceof Error) throw (Error) t;
throw new RuntimeException(t);
}
}
private static final String SELF_NAME = "lombok.eclipse.agent.EclipseLoaderPatcher";
private static final String TRANSPLANTS_CLASS_NAME = "lombok.eclipse.agent.EclipseLoaderPatcherTransplants";
public static void patchEquinoxLoaders(ScriptManager sm, Class<?> launchingContext) {
sm.addScript(ScriptBuilder.exitEarly()
@@ -81,8 +39,8 @@ public class EclipseLoaderPatcher {
"java.lang.Class", "java.lang.String", "boolean"))
.target(new MethodTarget("org.eclipse.osgi.internal.loader.ModuleClassLoader", "loadClass",
"java.lang.Class", "java.lang.String", "boolean"))
.decisionMethod(new Hook(SELF_NAME, "overrideLoadDecide", "boolean", "java.lang.ClassLoader", "java.lang.String", "boolean"))
.valueMethod(new Hook(SELF_NAME, "overrideLoadResult", "java.lang.Class", "java.lang.ClassLoader", "java.lang.String", "boolean"))
.decisionMethod(new Hook(TRANSPLANTS_CLASS_NAME, "overrideLoadDecide", "boolean", "java.lang.ClassLoader", "java.lang.String", "boolean"))
.valueMethod(new Hook(TRANSPLANTS_CLASS_NAME, "overrideLoadResult", "java.lang.Class", "java.lang.ClassLoader", "java.lang.String", "boolean"))
.transplant()
.request(StackRequest.THIS, StackRequest.PARAM1, StackRequest.PARAM2).build());
@@ -0,0 +1,117 @@
/*
* Copyright (C) 2015 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.eclipse.agent;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
/**
* Contains all the code to be transplanted into eclipse.
*
* Do not use:
*
* * Annotations
* * Generics
* * Varargs
* * Auto (un)boxing
* * class literals
*
* The above because this code is compiled with -source 1.4, and is transplanted.
*
* NB: The suppress warnings will be stripped out before compilation.
*/
@SuppressWarnings("all")
public class EclipseLoaderPatcherTransplants {
public static boolean overrideLoadDecide(ClassLoader original, String name, boolean resolve) {
return name.startsWith("lombok.");
}
public static Class overrideLoadResult(ClassLoader original, String name, boolean resolve) throws ClassNotFoundException {
try {
Field shadowLoaderField = original.getClass().getField("lombok$shadowLoader");
ClassLoader shadowLoader = (ClassLoader) shadowLoaderField.get(original);
if (shadowLoader == null) {
String jarLoc = (String) original.getClass().getField("lombok$location").get(null);
JarFile jf = new JarFile(jarLoc);
InputStream in = null;
try {
ZipEntry entry = jf.getEntry("lombok/launch/ShadowClassLoader.class");
in = jf.getInputStream(entry);
byte[] bytes = new byte[65536];
int len = 0;
while (true) {
int r = in.read(bytes, len, bytes.length - len);
if (r == -1) break;
len += r;
if (len == bytes.length) throw new IllegalStateException("lombok.launch.ShadowClassLoader too large.");
}
in.close();
Class classLoaderClass = Class.forName("java.lang.ClassLoader");
Class shadowClassLoaderClass; {
Class[] paramTypes = new Class[4];
paramTypes[0] = "".getClass();
paramTypes[1] = new byte[0].getClass();
paramTypes[2] = Integer.TYPE;
paramTypes[3] = paramTypes[2];
Method defineClassMethod = classLoaderClass.getDeclaredMethod("defineClass", paramTypes);
defineClassMethod.setAccessible(true);
shadowClassLoaderClass = (Class) defineClassMethod.invoke(original, new Object[] {"lombok.launch.ShadowClassLoader", bytes, new Integer(0), new Integer(len)});
}
Class[] paramTypes = new Class[4];
paramTypes[0] = classLoaderClass;
paramTypes[1] = "".getClass();
paramTypes[2] = paramTypes[1];
paramTypes[3] = new String[0].getClass();
Constructor constructor = shadowClassLoaderClass.getDeclaredConstructor(paramTypes);
constructor.setAccessible(true);
shadowLoader = (ClassLoader) constructor.newInstance(new Object[] {original, "lombok", jarLoc, new String[] {"lombok."}});
shadowLoaderField.set(original, shadowLoader);
} finally {
if (in != null) in.close();
jf.close();
}
}
if (resolve) {
Class[] paramTypes = new Class[2];
paramTypes[0] = "".getClass();
paramTypes[1] = Boolean.TYPE;
Method m = shadowLoader.getClass().getDeclaredMethod("loadClass", new Class[] {String.class, boolean.class});
m.setAccessible(true);
return (Class) m.invoke(shadowLoader, new Object[] {name, Boolean.TRUE});
} else {
return shadowLoader.loadClass(name);
}
} catch (Exception ex) {
Throwable t = ex;
if (t instanceof InvocationTargetException) t = t.getCause();
if (t instanceof RuntimeException) throw (RuntimeException) t;
if (t instanceof Error) throw (Error) t;
throw new RuntimeException(t);
}
}
}
@@ -29,7 +29,6 @@ import java.util.Collections;
import java.util.List;
import lombok.core.AgentLauncher;
import lombok.patcher.Hook;
import lombok.patcher.MethodTarget;
import lombok.patcher.ScriptManager;