diff options
author | chibash <chiba@javassist.org> | 2017-04-13 03:45:51 +0900 |
---|---|---|
committer | chibash <chiba@javassist.org> | 2017-04-13 03:45:51 +0900 |
commit | 45ce3617423eeedca6c556543329208e540922cb (patch) | |
tree | 7ed91b96009b940de4250b4600212c2d0eb95c45 | |
parent | 6a3ed31976e54f2523a6e41dfee9001b3cce58c8 (diff) | |
download | javassist-45ce3617423eeedca6c556543329208e540922cb.tar.gz javassist-45ce3617423eeedca6c556543329208e540922cb.zip |
modifies to use sun.misc.Unsafe#defineClass so that Javassist can run with jigsaw
-rw-r--r-- | javassist.jar | bin | 722743 -> 724588 bytes | |||
-rw-r--r-- | src/main/javassist/ClassPool.java | 109 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/DefineClassHelper.java | 139 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/FactoryHelper.java | 60 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/ProxyFactory.java | 5 | ||||
-rw-r--r-- | src/test/javassist/JvstTest4.java | 22 |
6 files changed, 211 insertions, 124 deletions
diff --git a/javassist.jar b/javassist.jar Binary files differindex 5083ca75..068a36b7 100644 --- a/javassist.jar +++ b/javassist.jar diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java index 36e0c337..4be35b5f 100644 --- a/src/main/javassist/ClassPool.java +++ b/src/main/javassist/ClassPool.java @@ -70,34 +70,26 @@ import javassist.bytecode.Descriptor; * @see javassist.ClassPath */ public class ClassPool { - // used by toClass(). - private static java.lang.reflect.Method defineClass1, defineClass2; - private static java.lang.reflect.Method definePackage; + private static java.lang.reflect.Method definePackage = null; static { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction(){ - public Object run() throws Exception{ - Class cl = Class.forName("java.lang.ClassLoader"); - defineClass1 = cl.getDeclaredMethod("defineClass", - new Class[] { String.class, byte[].class, - int.class, int.class }); - - defineClass2 = cl.getDeclaredMethod("defineClass", - new Class[] { String.class, byte[].class, - int.class, int.class, ProtectionDomain.class }); - - definePackage = cl.getDeclaredMethod("definePackage", - new Class[] { String.class, String.class, String.class, - String.class, String.class, String.class, - String.class, java.net.URL.class }); - return null; - } - }); - } - catch (PrivilegedActionException pae) { - throw new RuntimeException("cannot initialize ClassPool", pae.getException()); - } + if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) + try { + AccessController.doPrivileged(new PrivilegedExceptionAction(){ + public Object run() throws Exception{ + Class cl = Class.forName("java.lang.ClassLoader"); + definePackage = cl.getDeclaredMethod("definePackage", + new Class[] { String.class, String.class, String.class, + String.class, String.class, String.class, + String.class, java.net.URL.class }); + return null; + } + }); + } + catch (PrivilegedActionException pae) { + throw new RuntimeException("cannot initialize ClassPool", + pae.getException()); + } } /** @@ -1148,46 +1140,14 @@ public class ClassPool { throws CannotCompileException { try { - byte[] b = ct.toBytecode(); - java.lang.reflect.Method method; - Object[] args; - if (domain == null) { - method = defineClass1; - args = new Object[] { ct.getName(), b, Integer.valueOf(0), - Integer.valueOf(b.length)}; - } - else { - method = defineClass2; - args = new Object[] { ct.getName(), b, Integer.valueOf(0), - Integer.valueOf(b.length), domain}; - } - - return (Class)toClass2(method, loader, args); + return javassist.util.proxy.DefineClassHelper.toClass(ct.getName(), + loader, domain, ct.toBytecode()); } - catch (RuntimeException e) { - throw e; - } - catch (java.lang.reflect.InvocationTargetException e) { - throw new CannotCompileException(e.getTargetException()); - } - catch (Exception e) { + catch (IOException e) { throw new CannotCompileException(e); } } - private static synchronized Object toClass2(Method method, - ClassLoader loader, Object[] args) - throws Exception - { - method.setAccessible(true); - try { - return method.invoke(loader, args); - } - finally { - method.setAccessible(false); - } - } - /** * Defines a new package. If the package is already defined, this method * performs nothing. @@ -1195,7 +1155,13 @@ public class ClassPool { * <p>You do not necessarily need to * call this method. If this method is called, then * <code>getPackage()</code> on the <code>Class</code> object returned - * by <code>toClass()</code> will return a non-null object. + * by <code>toClass()</code> will return a non-null object.</p> + * + * <p>The jigsaw module introduced by Java 9 has broken this method. + * In Java 9 or later, the VM argument + * <code>--add-opens java.base/java.lang=ALL-UNNAMED</code> + * has to be given to the JVM so that this method can run. + * </p> * * @param loader the class loader passed to <code>toClass()</code> or * the default one obtained by <code>getClassLoader()</code>. @@ -1204,15 +1170,19 @@ public class ClassPool { * @see #toClass(CtClass) * @see CtClass#toClass() * @since 3.16 + * @deprecated */ public void makePackage(ClassLoader loader, String name) throws CannotCompileException { + if (definePackage == null) + throw new CannotCompileException("give the JVM --add-opens"); + Object[] args = new Object[] { name, null, null, null, null, null, null, null }; Throwable t; try { - toClass2(definePackage, loader, args); + makePackage2(definePackage, loader, args); return; } catch (java.lang.reflect.InvocationTargetException e) { @@ -1231,4 +1201,17 @@ public class ClassPool { throw new CannotCompileException(t); } + + private static synchronized Object makePackage2(Method method, + ClassLoader loader, Object[] args) + throws Exception + { + method.setAccessible(true); + try { + return method.invoke(loader, args); + } + finally { + method.setAccessible(false); + } + } } diff --git a/src/main/javassist/util/proxy/DefineClassHelper.java b/src/main/javassist/util/proxy/DefineClassHelper.java new file mode 100644 index 00000000..c5749925 --- /dev/null +++ b/src/main/javassist/util/proxy/DefineClassHelper.java @@ -0,0 +1,139 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. Alternatively, the contents of this file may be used under + * the terms of the GNU Lesser General Public License Version 2.1 or later, + * or the Apache License Version 2.0. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + */ + +package javassist.util.proxy; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Field; +import java.security.ProtectionDomain; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import sun.misc.Unsafe; + +import javassist.CannotCompileException; +import javassist.bytecode.ClassFile; + +/** + * Helper class for invoking {@link ClassLoader#defineClass(String,byte[],int,int)}. + * + * @since 3.22 + */ +public class DefineClassHelper { + private static java.lang.reflect.Method defineClass1 = null; + private static java.lang.reflect.Method defineClass2 = null; + private static Unsafe sunMiscUnsafe = null; + + static { + if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) + try { + Class<?> cl = Class.forName("java.lang.ClassLoader"); + defineClass1 = SecurityActions.getDeclaredMethod( + cl, + "defineClass", + new Class[] { String.class, byte[].class, + int.class, int.class }); + + defineClass2 = SecurityActions.getDeclaredMethod( + cl, + "defineClass", + new Class[] { String.class, byte[].class, + int.class, int.class, ProtectionDomain.class }); + } + catch (Exception e) { + throw new RuntimeException("cannot initialize"); + } + else + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + sunMiscUnsafe = (sun.misc.Unsafe)theUnsafe.get(null); + } + catch (Throwable t) {} + } + + /** + * Loads a class file by a given class loader. + * + * @param domain if it is null, a default domain is used. + * @since 3.22 + */ + public static Class<?> toClass(String className, ClassLoader loader, + ProtectionDomain domain, byte[] bcode) + throws CannotCompileException + { + if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) + return toClass2(className, loader, domain, bcode); + else { + if (sunMiscUnsafe != null) + try { + return sunMiscUnsafe.defineClass(className, bcode, 0, bcode.length, + loader, domain); + } + catch (Throwable t2) {} + + try { + Lookup lookup = MethodHandles.lookup(); + lookup = lookup.dropLookupMode(java.lang.invoke.MethodHandles.Lookup.PRIVATE); + return lookup.defineClass(bcode); + } + catch (Throwable t) { + throw new CannotCompileException(t); + } + } + } + + private static Class<?> toClass2(String cname, ClassLoader loader, + ProtectionDomain domain, byte[] bcode) + throws CannotCompileException + { + try { + Method method; + Object[] args; + if (domain == null) { + method = defineClass1; + args = new Object[] { cname, bcode, Integer.valueOf(0), + Integer.valueOf(bcode.length) }; + } + else { + method = defineClass2; + args = new Object[] { cname, bcode, Integer.valueOf(0), + Integer.valueOf(bcode.length), domain }; + } + + return toClass3(method, loader, args); + } + catch (RuntimeException e) { + throw e; + } + catch (java.lang.reflect.InvocationTargetException e) { + throw new CannotCompileException(e.getTargetException()); + } + catch (Exception e) { + throw new CannotCompileException(e); + } + } + + private static synchronized + Class<?> toClass3(Method method, ClassLoader loader, Object[] args) + throws Exception + { + SecurityActions.setAccessible(method, true); + Class<?> clazz = (Class<?>)method.invoke(loader, args); + SecurityActions.setAccessible(method, false); + return clazz; + } +} diff --git a/src/main/javassist/util/proxy/FactoryHelper.java b/src/main/javassist/util/proxy/FactoryHelper.java index b17b78ed..39114657 100644 --- a/src/main/javassist/util/proxy/FactoryHelper.java +++ b/src/main/javassist/util/proxy/FactoryHelper.java @@ -16,7 +16,6 @@ package javassist.util.proxy; -import java.lang.reflect.Method; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -35,28 +34,6 @@ import javassist.bytecode.ClassFile; * @see ProxyFactory */ public class FactoryHelper { - private static java.lang.reflect.Method defineClass1, defineClass2; - - static { - try { - Class cl = Class.forName("java.lang.ClassLoader"); - defineClass1 = SecurityActions.getDeclaredMethod( - cl, - "defineClass", - new Class[] { String.class, byte[].class, - int.class, int.class }); - - defineClass2 = SecurityActions.getDeclaredMethod( - cl, - "defineClass", - new Class[] { String.class, byte[].class, - int.class, int.class, ProtectionDomain.class }); - } - catch (Exception e) { - throw new RuntimeException("cannot initialize"); - } - } - /** * Returns an index for accessing arrays in this class. * @@ -144,45 +121,16 @@ public class FactoryHelper { * @since 3.3 */ public static Class toClass(ClassFile cf, ClassLoader loader, ProtectionDomain domain) - throws CannotCompileException + throws CannotCompileException { try { byte[] b = toBytecode(cf); - Method method; - Object[] args; - if (domain == null) { - method = defineClass1; - args = new Object[] { cf.getName(), b, Integer.valueOf(0), - Integer.valueOf(b.length) }; - } - else { - method = defineClass2; - args = new Object[] { cf.getName(), b, Integer.valueOf(0), - Integer.valueOf(b.length), domain }; - } - - return toClass2(method, loader, args); + return DefineClassHelper.toClass(cf.getName(), loader, domain, b); } - catch (RuntimeException e) { - throw e; - } - catch (java.lang.reflect.InvocationTargetException e) { - throw new CannotCompileException(e.getTargetException()); - } - catch (Exception e) { + catch (IOException e) { throw new CannotCompileException(e); } - } - - private static synchronized Class toClass2(Method method, - ClassLoader loader, Object[] args) - throws Exception - { - SecurityActions.setAccessible(method, true); - Class clazz = (Class)method.invoke(loader, args); - SecurityActions.setAccessible(method, false); - return clazz; - } + } private static byte[] toBytecode(ClassFile cf) throws IOException { ByteArrayOutputStream barray = new ByteArrayOutputStream(); diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index a85e8de0..81792585 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -27,7 +27,6 @@ import java.util.*; import java.lang.ref.WeakReference; import javassist.CannotCompileException; -import javassist.NotFoundException; import javassist.bytecode.*; /* @@ -795,7 +794,7 @@ public class ProxyFactory { superClass = OBJECT_TYPE; superName = superClass.getName(); basename = interfaces.length == 0 ? superName - : interfaces[0].getName(); + : interfaces[0].getName(); } else { superName = superClass.getName(); basename = superName; @@ -805,7 +804,7 @@ public class ProxyFactory { throw new RuntimeException(superName + " is final"); if (basename.startsWith("java.")) - basename = "org.javassist.tmp." + basename; + basename = "javassist.util.proxy." + basename.replace('.', '_'); } private void allocateClassName() { diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java index 1fdec977..56a89335 100644 --- a/src/test/javassist/JvstTest4.java +++ b/src/test/javassist/JvstTest4.java @@ -599,11 +599,29 @@ public class JvstTest4 extends JvstTestRoot { }); } + public void testMakePackage() throws Exception { + if (ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9) { + ClassPool pool = ClassPool.getDefault(); + try { + pool.makePackage(pool.getClassLoader(), "test4.pack2"); + fail("makePackage() ran"); + } + catch (CannotCompileException e) {} + } + } + public void testPackage() throws Throwable { // JASSIST-147 String packageName = "test4.pack"; ClassPool pool = ClassPool.getDefault(); - pool.makePackage(pool.getClassLoader(), packageName); - pool.makePackage(pool.getClassLoader(), packageName); + try { + pool.makePackage(pool.getClassLoader(), packageName); + pool.makePackage(pool.getClassLoader(), packageName); + } + catch (CannotCompileException e) { + if (ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9) + return; // makePackage() does not work in Java 9. + } + CtClass ctcl = pool.makeClass("test4.pack.Clazz"); Class cl = ctcl.toClass(); Object obj = cl.getConstructor().newInstance(); |