aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchibash <chiba@javassist.org>2017-04-13 03:45:51 +0900
committerchibash <chiba@javassist.org>2017-04-13 03:45:51 +0900
commit45ce3617423eeedca6c556543329208e540922cb (patch)
tree7ed91b96009b940de4250b4600212c2d0eb95c45
parent6a3ed31976e54f2523a6e41dfee9001b3cce58c8 (diff)
downloadjavassist-45ce3617423eeedca6c556543329208e540922cb.tar.gz
javassist-45ce3617423eeedca6c556543329208e540922cb.zip
modifies to use sun.misc.Unsafe#defineClass so that Javassist can run with jigsaw
-rw-r--r--javassist.jarbin722743 -> 724588 bytes
-rw-r--r--src/main/javassist/ClassPool.java109
-rw-r--r--src/main/javassist/util/proxy/DefineClassHelper.java139
-rw-r--r--src/main/javassist/util/proxy/FactoryHelper.java60
-rw-r--r--src/main/javassist/util/proxy/ProxyFactory.java5
-rw-r--r--src/test/javassist/JvstTest4.java22
6 files changed, 211 insertions, 124 deletions
diff --git a/javassist.jar b/javassist.jar
index 5083ca75..068a36b7 100644
--- a/javassist.jar
+++ b/javassist.jar
Binary files differ
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();