diff --git a/build.xml b/build.xml index 5bf1b0a051..802c0335b4 100644 --- a/build.xml +++ b/build.xml @@ -173,6 +173,23 @@ the common tasks and can be called on to run the main aspects of all the sub-scr + + + + + + + + + + + + + + + + + @@ -180,6 +197,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr + diff --git a/doc/changelog.markdown b/doc/changelog.markdown index f8ea277426..3e12adee7b 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -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) diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java index 0d21c2120c..8616e9bc79 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcher.java @@ -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.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 static void patchEquinoxLoaders(ScriptManager sm, Class launchingConte "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()); diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcherTransplants.java b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcherTransplants.java new file mode 100644 index 0000000000..f50e6987fa --- /dev/null +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipseLoaderPatcherTransplants.java @@ -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); + } + } +} diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index efc7ce9415..b8e3a95578 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -29,7 +29,6 @@ import java.util.List; import lombok.core.AgentLauncher; - import lombok.patcher.Hook; import lombok.patcher.MethodTarget; import lombok.patcher.ScriptManager;