aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNing Zhang <ning.n.zhang@ericsson.com>2018-11-02 10:11:18 +0800
committerGitHub <noreply@github.com>2018-11-02 10:11:18 +0800
commit10f4eaf582721005fefc77c6d20c91d2c4981629 (patch)
tree3591f42475c4adb55b05f0c581fcde9be59e17d0
parentbca5c7aad8551aebda6039fb74b41c20de3d23d9 (diff)
parentfa3dd56b836208944683de8a50bb36e96b5e001e (diff)
downloadjavassist-10f4eaf582721005fefc77c6d20c91d2c4981629.tar.gz
javassist-10f4eaf582721005fefc77c6d20c91d2c4981629.zip
Merge pull request #1 from jboss-javassist/master
Sync with jboss-javassist/javassist.
-rw-r--r--.gitignore2
-rw-r--r--Readme.html12
-rw-r--r--build.xml10
-rw-r--r--javassist.jarbin759474 -> 766405 bytes
-rw-r--r--pom.xml17
-rw-r--r--src/main/META-INF/MANIFEST.MF3
-rw-r--r--src/main/javassist/ClassPool.java134
-rw-r--r--src/main/javassist/ClassPoolTail.java4
-rw-r--r--src/main/javassist/CtClass.java85
-rw-r--r--src/main/javassist/CtClassType.java4
-rw-r--r--src/main/javassist/Loader.java48
-rw-r--r--src/main/javassist/Modifier.java32
-rw-r--r--src/main/javassist/bytecode/AttributeInfo.java4
-rw-r--r--src/main/javassist/bytecode/NestHostAttribute.java67
-rw-r--r--src/main/javassist/bytecode/NestMembersAttribute.java88
-rw-r--r--src/main/javassist/expr/ExprEditor.java8
-rw-r--r--src/main/javassist/expr/NewArray.java4
-rw-r--r--src/main/javassist/expr/NewExpr.java10
-rw-r--r--src/main/javassist/scopedpool/SoftValueHashMap.java6
-rw-r--r--src/main/javassist/util/proxy/DefineClassHelper.java368
-rw-r--r--src/main/javassist/util/proxy/DefinePackageHelper.java165
-rw-r--r--src/main/javassist/util/proxy/FactoryHelper.java35
-rw-r--r--src/main/javassist/util/proxy/ProxyFactory.java96
-rwxr-xr-xsrc/main/javassist/util/proxy/SecurityActions.java10
-rw-r--r--src/test/DefineClassCapability.java5
-rw-r--r--src/test/javassist/JvstTest.java7
-rw-r--r--src/test/javassist/JvstTest2.java3
-rw-r--r--src/test/javassist/JvstTest3.java8
-rw-r--r--src/test/javassist/JvstTest4.java3
-rw-r--r--src/test/javassist/JvstTest5.java39
-rw-r--r--src/test/javassist/SetterTest.java226
-rw-r--r--src/test/javassist/bytecode/InsertGap0.java4
-rw-r--r--src/test/javassist/tools/CallbackTest.java3
-rw-r--r--src/test/test/javassist/DefineClassCapability.java7
-rw-r--r--src/test/test/javassist/convert/ArrayAccessReplaceTest.java12
-rw-r--r--src/test/test/javassist/proxy/ProxyCacheGCTest.java6
-rw-r--r--src/test/test/javassist/proxy/ProxySimpleTest.java31
-rw-r--r--src/test/test/javassist/proxy/TestSecuredPrivileged.java281
-rw-r--r--src/test/test/javassist/tools/DefineClassCapability.java7
-rw-r--r--src/test/test1/DefineClassCapability.java7
-rw-r--r--src/test/test2/DefineClassCapability.java7
-rw-r--r--src/test/test3/DefineClassCapability.java7
-rw-r--r--src/test/test4/DefineClassCapability.java7
-rw-r--r--src/test/test5/DefineClassCapability.java7
-rw-r--r--src/test/test5/NestHost.java11
-rw-r--r--src/test/test5/NestHost2.java11
46 files changed, 1171 insertions, 740 deletions
diff --git a/.gitignore b/.gitignore
index 73e3f77e..1f83f06e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,4 @@ tmp/
.project
.settings
TestLog.xml
-
+*~
diff --git a/Readme.html b/Readme.html
index c8649848..b89b5b95 100644
--- a/Readme.html
+++ b/Readme.html
@@ -281,9 +281,17 @@ see javassist.Dump.
<h2>Changes</h2>
+<p>-version 3.24 on November 1, 2018
+<ul>
+ <li>Java 11 supports.</li>
+ <li>JIRA JASSIST-267.</li>
+ <li>Github PR #218.</li>
+</ul>
+</p>
+
<p>-version 3.23.1 on July 2, 2018
<ul>
- <li>Github pull issue #171.</li>
+ <li>Github PR #171.</li>
</ul>
</p>
@@ -862,4 +870,4 @@ and all other contributors for their contributions.
(Email: <tt>chiba@javassist.org</tt>)
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/build.xml b/build.xml
index d654536f..ec805b0f 100644
--- a/build.xml
+++ b/build.xml
@@ -6,7 +6,7 @@
<project name="javassist" default="jar" basedir=".">
- <property name="dist-version" value="javassist-3.23.1-GA"/>
+ <property name="dist-version" value="javassist-3.24-GA"/>
<property environment="env"/>
<property name="target.jar" value="javassist.jar"/>
@@ -74,13 +74,13 @@
</javac>
</target>
- <target name="compile16" depends="prepare">
+ <target name="compile18" depends="prepare">
<javac srcdir="${src.dir}"
destdir="${build.classes.dir}"
debug="on"
deprecation="on"
- source="1.6"
- target="1.6"
+ source="1.8"
+ target="1.8"
optimize="off"
includeantruntime="true"
includes="**">
@@ -181,7 +181,7 @@
to ${build.classes.dir}.</echo>
</target>
- <target name="jar" depends="compile16">
+ <target name="jar" depends="compile18">
<jar jarfile="${target.jar}" update="true" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${build.classes.dir}">
<include name="**/*.class"/>
diff --git a/javassist.jar b/javassist.jar
index edf45a97..73e3f0fd 100644
--- a/javassist.jar
+++ b/javassist.jar
Binary files differ
diff --git a/pom.xml b/pom.xml
index adb9c619..c1fc343c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
simple. It is a class library for editing bytecodes in Java.
</description>
- <version>3.23.1-GA</version>
+ <version>3.24.0-GA</version>
<name>Javassist</name>
<url>http://www.javassist.org/</url>
@@ -151,10 +151,10 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
- <source>1.6</source>
- <target>1.6</target>
- <testSource>1.9</testSource>
- <testTarget>1.9</testTarget>
+ <source>1.8</source>
+ <target>1.8</target>
+ <testSource>11</testSource>
+ <testTarget>11</testTarget>
<testCompilerArgument>-parameters</testCompilerArgument>
</configuration>
</plugin>
@@ -202,9 +202,14 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
- <version>3.0.0-M1</version>
+ <version>3.0.1</version>
<configuration>
<attach>true</attach>
+ <excludePackageNames>javassist.compiler:javassist.convert:javassist.scopedpool:javassist.bytecode.stackmap</excludePackageNames>
+ <bottom><![CDATA[<i>Javassist, a Java-bytecode translator toolkit.<br>
+Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
+ <show>public</show>
+ <nohelp>true</nohelp>
</configuration>
</plugin>
<plugin>
diff --git a/src/main/META-INF/MANIFEST.MF b/src/main/META-INF/MANIFEST.MF
index 448c6fca..09bb026c 100644
--- a/src/main/META-INF/MANIFEST.MF
+++ b/src/main/META-INF/MANIFEST.MF
@@ -1,4 +1,5 @@
Specification-Title: Javassist
Specification-Vendor: Shigeru Chiba, www.javassist.org
-Specification-Version: 3.23.1-GA
+Specification-Version: 3.24.0-GA
Main-Class: javassist.CtClass
+Automatic-Module-Name: org.javassist
diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java
index 60055992..37f2acbd 100644
--- a/src/main/javassist/ClassPool.java
+++ b/src/main/javassist/ClassPool.java
@@ -1023,16 +1023,23 @@ public class ClassPool {
* the <code>getClassLoader()</code> method.
* If the program is running on some application
* server, the context class loader might be inappropriate to load the
- * class.
+ * class.</p>
*
* <p>This method is provided for convenience. If you need more
* complex functionality, you should write your own class loader.
*
- * <p><b>Warining:</b> A Class object returned by this method may not
+ * <p><b>Warining:</b>
+ * This method should not be used in Java 11 or later.
+ * Use {@link #toClass(CtClass,Class)}.
+ * </p>
+ *
+ * <p><b>Warining:</b>
+ * A Class object returned by this method may not
* work with a security manager or a signed jar file because a
- * protection domain is not specified.
+ * protection domain is not specified.</p>
*
- * @see #toClass(CtClass, java.lang.ClassLoader, ProtectionDomain)
+ * @see #toClass(CtClass,Class)
+ * @see #toClass(CtClass,Class,java.lang.ClassLoader,ProtectionDomain)
* @see #getClassLoader()
*/
public Class toClass(CtClass clazz) throws CannotCompileException {
@@ -1066,21 +1073,21 @@ public class ClassPool {
/**
* Converts the class to a <code>java.lang.Class</code> object.
* Do not override this method any more at a subclass because
- * <code>toClass(CtClass)</code> never calls this method.
+ * {@link #toClass(CtClass)} will never calls this method.
*
* <p><b>Warining:</b> A Class object returned by this method may not
* work with a security manager or a signed jar file because a
* protection domain is not specified.
*
- * @deprecated Replaced by {@link #toClass(CtClass,ClassLoader,ProtectionDomain)}.
+ * @deprecated Replaced by {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}.
* A subclass of <code>ClassPool</code> that has been
* overriding this method should be modified. It should override
- * {@link #toClass(CtClass,ClassLoader,ProtectionDomain)}.
+ * {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}.
*/
public Class toClass(CtClass ct, ClassLoader loader)
throws CannotCompileException
{
- return toClass(ct, loader, null);
+ return toClass(ct, null, loader, null);
}
/**
@@ -1092,7 +1099,7 @@ public class ClassPool {
* loaded by the given class loader to construct a
* <code>java.lang.Class</code> object. Since a private method
* on the class loader is invoked through the reflection API,
- * the caller must have permissions to do that.
+ * the caller must have permissions to do that.</p>
*
* <p>An easy way to obtain <code>ProtectionDomain</code> object is
* to call <code>getProtectionDomain()</code>
@@ -1100,8 +1107,9 @@ public class ClassPool {
* class belongs to.
*
* <p>This method is provided for convenience. If you need more
- * complex functionality, you should write your own class loader.
+ * complex functionality, you should write your own class loader.</p>
*
+ * @param ct the class converted into {@code java.lang.Class}.
* @param loader the class loader used to load this class.
* For example, the loader returned by
* <code>getClassLoader()</code> can be used
@@ -1112,13 +1120,117 @@ public class ClassPool {
*
* @see #getClassLoader()
* @since 3.3
+ * @deprecated Replaced by {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}.
*/
public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain)
throws CannotCompileException
{
+ return toClass(ct, null, loader, domain);
+ }
+
+ /**
+ * Converts the class to a <code>java.lang.Class</code> object.
+ * Once this method is called, further modifications are not allowed
+ * any more.
+ *
+ * <p>This method is available in Java 9 or later.
+ * It loads the class
+ * by using {@code java.lang.invoke.MethodHandles} with {@code neighbor}.
+ * </p>
+ *
+ * @param ct the class converted into {@code java.lang.Class}.
+ * @param neighbor a class belonging to the same package that
+ * the converted class belongs to.
+ * @since 3.24
+ */
+ public Class<?> toClass(CtClass ct, Class<?> neighbor)
+ throws CannotCompileException
+ {
+ try {
+ return javassist.util.proxy.DefineClassHelper.toClass(neighbor,
+ ct.toBytecode());
+ }
+ catch (IOException e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
+ /**
+ * Converts the class to a <code>java.lang.Class</code> object.
+ * Once this method is called, further modifications are not allowed
+ * any more.
+ *
+ * <p>This method is available in Java 9 or later.
+ * It loads the class
+ * by using the given {@code java.lang.invoke.MethodHandles.Lookup}.
+ * </p>
+ *
+ * @param ct the class converted into {@code java.lang.Class}.
+ * @since 3.24
+ */
+ public Class<?> toClass(CtClass ct,
+ java.lang.invoke.MethodHandles.Lookup lookup)
+ throws CannotCompileException
+ {
+ try {
+ return javassist.util.proxy.DefineClassHelper.toClass(lookup,
+ ct.toBytecode());
+ }
+ catch (IOException e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
+ /**
+ * Converts the class to a <code>java.lang.Class</code> object.
+ * Once this method is called, further modifications are not allowed
+ * any more.
+ *
+ * <p>When the JVM is Java 11 or later, this method loads the class
+ * by using {@code java.lang.invoke.MethodHandles} with {@code neighbor}.
+ * The other arguments {@code loader} and {@code domain} are not used;
+ * so they can be null.
+ * </p>
+ *
+ * <p>Otherwise, or when {@code neighbor} is null,
+ * the class file represented by the given <code>CtClass</code> is
+ * loaded by the given class loader to construct a
+ * <code>java.lang.Class</code> object. Since a private method
+ * on the class loader is invoked through the reflection API,
+ * the caller must have permissions to do that.
+ *
+ * <p>An easy way to obtain <code>ProtectionDomain</code> object is
+ * to call <code>getProtectionDomain()</code>
+ * in <code>java.lang.Class</code>. It returns the domain that the
+ * class belongs to.
+ *
+ * <p>If your program is for only Java 9 or later, don't use this method.
+ * Use {@link #toClass(CtClass,Class)} or
+ * {@link #toClass(CtClass,java.lang.invoke.MethodHandles.Lookup)}.
+ * </p>
+ *
+ * @param ct the class converted into {@code java.lang.Class}.
+ * @param neighbor a class belonging to the same package that
+ * the converted class belongs to.
+ * It can be null.
+ * @param loader the class loader used to load this class.
+ * For example, the loader returned by
+ * <code>getClassLoader()</code> can be used
+ * for this parameter.
+ * @param domain the protection domain for the class.
+ * If it is null, the default domain created
+ * by <code>java.lang.ClassLoader</code> is used.
+ *
+ * @see #getClassLoader()
+ * @since 3.24
+ */
+ public Class toClass(CtClass ct, Class<?> neighbor, ClassLoader loader,
+ ProtectionDomain domain)
+ throws CannotCompileException
+ {
try {
return javassist.util.proxy.DefineClassHelper.toClass(ct.getName(),
- loader, domain, ct.toBytecode());
+ neighbor, loader, domain, ct.toBytecode());
}
catch (IOException e) {
throw new CannotCompileException(e);
diff --git a/src/main/javassist/ClassPoolTail.java b/src/main/javassist/ClassPoolTail.java
index 2ab8ee46..965d72fb 100644
--- a/src/main/javassist/ClassPoolTail.java
+++ b/src/main/javassist/ClassPoolTail.java
@@ -159,7 +159,9 @@ final class JarClassPath implements ClassPath {
URL jarURL = find(classname);
if (null != jarURL)
try {
- return jarURL.openConnection().getInputStream();
+ java.net.URLConnection con = jarURL.openConnection();
+ con.setUseCaches(false);
+ return con.getInputStream();
}
catch (IOException e) {
throw new NotFoundException("broken jar file?: "
diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java
index 375c7ba5..847d9c7b 100644
--- a/src/main/javassist/CtClass.java
+++ b/src/main/javassist/CtClass.java
@@ -69,7 +69,7 @@ public abstract class CtClass {
/**
* The version number of this release.
*/
- public static final String version = "3.23.1-GA";
+ public static final String version = "3.24.0-GA";
/**
* Prints the version number and the copyright notice.
@@ -1261,21 +1261,86 @@ public abstract class CtClass {
* server, the context class loader might be inappropriate to load the
* class.
*
+ * <p><b>Warning:</b> In Java 11 or later, the call to this method will
+ * print a warning message:</p>
+ * <blockquote><pre>
+ * WARNING: An illegal reflective access operation has occurred
+ * WARNING: Illegal reflective access by javassist.util.proxy.SecurityActions$3 ...
+ * WARNING: Please consider reporting this to the maintainers of javassist.util.proxy.SecurityActions$3
+ * WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
+ * WARNING: All illegal access operations will be denied in a future release
+ * </pre></blockquote>
+ * <p>To avoid this message, use {@link #toClass(Class)}
+ * or {@link #toClass(java.lang.invoke.MethodHandles.Lookup)}.
+ * {@link #toClass()} will be unavailable in a future release.
+ * </p>
+ *
+ * <p><b>Warning:</b> A Class object returned by this method may not
+ * work with a security manager or a signed jar file because a
+ * protection domain is not specified.</p>
+ *
+ * <p>Note: this method calls <code>toClass()</code>
+ * in <code>ClassPool</code>.</p>
+ *
+ * @see #toClass(java.lang.invoke.MethodHandles.Lookup)
+ * @see #toClass(Class)
+ * @see ClassPool#toClass(CtClass)
+ */
+ public Class<?> toClass() throws CannotCompileException {
+ return getClassPool().toClass(this);
+ }
+
+ /**
+ * Converts this class to a <code>java.lang.Class</code> object.
+ * Once this method is called, further modifications are not
+ * allowed any more.
+ *
+ * <p>This method is provided for convenience. You should use
+ * {@code toClass(Lookup)} for better compatibility with the
+ * module system.
+ *
+ * <p>Note: this method calls <code>toClass()</code>
+ * in <code>ClassPool</code>.
+ *
+ * <p><b>Warning:</b> A Class object returned by this method may not
+ * work with a security manager or a signed jar file because a
+ * protection domain is not specified.
+ *
+ * @param neighbor A class belonging to the same package that this
+ * class belongs to. It is used to load the class.
+ * @see ClassPool#toClass(CtClass,Class)
+ * @see #toClass(java.lang.invoke.MethodHandles.Lookup)
+ * @since 3.24
+ */
+ public Class<?> toClass(Class<?> neighbor) throws CannotCompileException
+ {
+ return getClassPool().toClass(this, neighbor);
+ }
+
+ /**
+ * Converts this class to a <code>java.lang.Class</code> object.
+ * Once this method is called, further modifications are not
+ * allowed any more.
+ *
* <p>This method is provided for convenience. If you need more
* complex functionality, you should write your own class loader.
*
* <p>Note: this method calls <code>toClass()</code>
* in <code>ClassPool</code>.
*
- * <p><b>Warining:</b> A Class object returned by this method may not
+ * <p><b>Warning:</b> A Class object returned by this method may not
* work with a security manager or a signed jar file because a
* protection domain is not specified.
*
- * @see #toClass(java.lang.ClassLoader,ProtectionDomain)
- * @see ClassPool#toClass(CtClass)
+ * @param lookup used when loading the class. It has to have
+ * an access right to define a new class.
+ * @see ClassPool#toClass(CtClass,java.lang.invoke.MethodHandles.Lookup)
+ * @since 3.24
*/
- public Class<?> toClass() throws CannotCompileException {
- return getClassPool().toClass(this);
+ public Class<?> toClass(java.lang.invoke.MethodHandles.Lookup lookup)
+ throws CannotCompileException
+ {
+ return getClassPool().toClass(this, lookup);
}
/**
@@ -1316,13 +1381,13 @@ public abstract class CtClass {
if (loader == null)
loader = cp.getClassLoader();
- return cp.toClass(this, loader, domain);
+ return cp.toClass(this, null, loader, domain);
}
/**
* Converts this class to a <code>java.lang.Class</code> object.
*
- * <p><b>Warining:</b> A Class object returned by this method may not
+ * <p><b>Warning:</b> A Class object returned by this method may not
* work with a security manager or a signed jar file because a
* protection domain is not specified.
*
@@ -1332,7 +1397,7 @@ public abstract class CtClass {
public final Class<?> toClass(ClassLoader loader)
throws CannotCompileException
{
- return getClassPool().toClass(this, loader);
+ return getClassPool().toClass(this, null, loader, null);
}
/**
@@ -1405,7 +1470,7 @@ public abstract class CtClass {
* @see ClassPool#doPruning
*
* @see #toBytecode()
- * @see #toClass()
+ * @see #toClass(Class)
* @see #writeFile()
* @see #instrument(CodeConverter)
* @see #instrument(ExprEditor)
diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java
index 3791b5fb..ae196c4a 100644
--- a/src/main/javassist/CtClassType.java
+++ b/src/main/javassist/CtClassType.java
@@ -1526,7 +1526,7 @@ class CtClassType extends CtClass {
ClassFile cf = getClassFile2();
ConstPool cp = cf.getConstPool();
List<MethodInfo> methods = cf.getMethods();
- for (MethodInfo minfo:methods)
+ for (MethodInfo minfo: methods.toArray(new MethodInfo[methods.size()]))
converter.doit(this, minfo, cp);
}
@@ -1537,7 +1537,7 @@ class CtClassType extends CtClass {
checkModify();
ClassFile cf = getClassFile2();
List<MethodInfo> methods = cf.getMethods();
- for (MethodInfo minfo:methods)
+ for (MethodInfo minfo: methods.toArray(new MethodInfo[methods.size()]))
editor.doit(this, minfo);
}
diff --git a/src/main/javassist/Loader.java b/src/main/javassist/Loader.java
index 8eb067c4..37f83d68 100644
--- a/src/main/javassist/Loader.java
+++ b/src/main/javassist/Loader.java
@@ -16,11 +16,12 @@
package javassist;
+import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.security.ProtectionDomain;
import java.util.Arrays;
-import java.util.Hashtable;
+import java.util.HashMap;
import java.util.Vector;
import javassist.bytecode.ClassFile;
@@ -138,7 +139,48 @@ import javassist.bytecode.ClassFile;
* @see javassist.Translator
*/
public class Loader extends ClassLoader {
- private Hashtable<String,ClassLoader> notDefinedHere; // must be atomic.
+
+ /**
+ * A simpler class loader.
+ * This is a class loader that exposes the protected {@code defineClass()} method
+ * declared in {@code java.lang.ClassLoader}. It provides a method similar to
+ * {@code CtClass#toClass()}.
+ *
+ * <p>When loading a class, this class loader delegates the work to the
+ * parent class loader unless the loaded classes are explicitly given
+ * by {@link #invokeDefineClass(CtClass)}.
+ * Note that a class {@code Foo} loaded by this class loader is
+ * different from the class with the same name {@code Foo} but loaded by
+ * another class loader. This is Java's naming rule.
+ * </p>
+ *
+ * @since 3.24
+ */
+ public static class Simple extends ClassLoader {
+ /**
+ * Constructs a class loader.
+ */
+ public Simple() {}
+
+ /**
+ * Constructs a class loader.
+ * @param parent the parent class loader.
+ */
+ public Simple(ClassLoader parent) {
+ super(parent);
+ }
+
+ /**
+ * Invokes the protected {@code defineClass()} in {@code ClassLoader}.
+ * It converts the given {@link CtClass} object into a {@code java.lang.Class} object.
+ */
+ public Class<?> invokeDefineClass(CtClass cc) throws IOException, CannotCompileException {
+ byte[] code = cc.toBytecode();
+ return defineClass(cc.getName(), code, 0, code.length);
+ }
+ }
+
+ private HashMap<String,ClassLoader> notDefinedHere; // must be atomic.
private Vector<String> notDefinedPackages; // must be atomic.
private ClassPool source;
private Translator translator;
@@ -186,7 +228,7 @@ public class Loader extends ClassLoader {
}
private void init(ClassPool cp) {
- notDefinedHere = new Hashtable<String,ClassLoader>();
+ notDefinedHere = new HashMap<String,ClassLoader>();
notDefinedPackages = new Vector<String>();
source = cp;
translator = null;
diff --git a/src/main/javassist/Modifier.java b/src/main/javassist/Modifier.java
index fd73c3b3..733cc67b 100644
--- a/src/main/javassist/Modifier.java
+++ b/src/main/javassist/Modifier.java
@@ -46,7 +46,7 @@ public class Modifier {
public static final int ENUM = AccessFlag.ENUM;
/**
- * Returns true if the modifiers include the <tt>public</tt>
+ * Returns true if the modifiers include the <code>public</code>
* modifier.
*/
public static boolean isPublic(int mod) {
@@ -54,7 +54,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>private</tt>
+ * Returns true if the modifiers include the <code>private</code>
* modifier.
*/
public static boolean isPrivate(int mod) {
@@ -62,7 +62,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>protected</tt>
+ * Returns true if the modifiers include the <code>protected</code>
* modifier.
*/
public static boolean isProtected(int mod) {
@@ -71,14 +71,14 @@ public class Modifier {
/**
* Returns true if the modifiers do not include either
- * <tt>public</tt>, <tt>protected</tt>, or <tt>private</tt>.
+ * <code>public</code>, <code>protected</code>, or <code>private</code>.
*/
public static boolean isPackage(int mod) {
return (mod & (PUBLIC | PRIVATE | PROTECTED)) == 0;
}
/**
- * Returns true if the modifiers include the <tt>static</tt>
+ * Returns true if the modifiers include the <code>static</code>
* modifier.
*/
public static boolean isStatic(int mod) {
@@ -86,7 +86,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>final</tt>
+ * Returns true if the modifiers include the <code>final</code>
* modifier.
*/
public static boolean isFinal(int mod) {
@@ -94,7 +94,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>synchronized</tt>
+ * Returns true if the modifiers include the <code>synchronized</code>
* modifier.
*/
public static boolean isSynchronized(int mod) {
@@ -102,7 +102,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>volatile</tt>
+ * Returns true if the modifiers include the <code>volatile</code>
* modifier.
*/
public static boolean isVolatile(int mod) {
@@ -110,7 +110,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>transient</tt>
+ * Returns true if the modifiers include the <code>transient</code>
* modifier.
*/
public static boolean isTransient(int mod) {
@@ -118,7 +118,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>native</tt>
+ * Returns true if the modifiers include the <code>native</code>
* modifier.
*/
public static boolean isNative(int mod) {
@@ -126,7 +126,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>interface</tt>
+ * Returns true if the modifiers include the <code>interface</code>
* modifier.
*/
public static boolean isInterface(int mod) {
@@ -134,7 +134,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>annotation</tt>
+ * Returns true if the modifiers include the <code>annotation</code>
* modifier.
*
* @since 3.2
@@ -144,7 +144,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>enum</tt>
+ * Returns true if the modifiers include the <code>enum</code>
* modifier.
*
* @since 3.2
@@ -154,7 +154,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>abstract</tt>
+ * Returns true if the modifiers include the <code>abstract</code>
* modifier.
*/
public static boolean isAbstract(int mod) {
@@ -162,7 +162,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>strictfp</tt>
+ * Returns true if the modifiers include the <code>strictfp</code>
* modifier.
*/
public static boolean isStrict(int mod) {
@@ -170,7 +170,7 @@ public class Modifier {
}
/**
- * Returns true if the modifiers include the <tt>varargs</tt>
+ * Returns true if the modifiers include the <code>varargs</code>
* (variable number of arguments) modifier.
*/
public static boolean isVarArgs(int mod) {
diff --git a/src/main/javassist/bytecode/AttributeInfo.java b/src/main/javassist/bytecode/AttributeInfo.java
index 4bfd0dbb..be6e2a21 100644
--- a/src/main/javassist/bytecode/AttributeInfo.java
+++ b/src/main/javassist/bytecode/AttributeInfo.java
@@ -108,6 +108,10 @@ public class AttributeInfo {
/* Note that the names of Annotations attributes begin with 'R'. */
if (nameStr.equals(MethodParametersAttribute.tag))
return new MethodParametersAttribute(cp, name, in);
+ else if (nameStr.equals(NestHostAttribute.tag))
+ return new NestHostAttribute(cp, name, in);
+ else if (nameStr.equals(NestMembersAttribute.tag))
+ return new NestMembersAttribute(cp, name, in);
else if (nameStr.equals(AnnotationsAttribute.visibleTag)
|| nameStr.equals(AnnotationsAttribute.invisibleTag))
// RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
diff --git a/src/main/javassist/bytecode/NestHostAttribute.java b/src/main/javassist/bytecode/NestHostAttribute.java
new file mode 100644
index 00000000..28466d56
--- /dev/null
+++ b/src/main/javassist/bytecode/NestHostAttribute.java
@@ -0,0 +1,67 @@
+/*
+ * 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.bytecode;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * <code>NestHost_attribute</code>.
+ * It was introduced by JEP-181. See JVMS 4.7.28 for the specification.
+ *
+ * @since 3.24
+ */
+public class NestHostAttribute extends AttributeInfo {
+ /**
+ * The name of this attribute <code>"NestHost"</code>.
+ */
+ public static final String tag = "NestHost";
+
+ NestHostAttribute(ConstPool cp, int n, DataInputStream in) throws IOException {
+ super(cp, n, in);
+ }
+
+ private NestHostAttribute(ConstPool cp, int hostIndex) {
+ super(cp, tag, new byte[2]);
+ ByteArray.write16bit(hostIndex, get(), 0);
+ }
+
+ /**
+ * Makes a copy. Class names are replaced according to the
+ * given <code>Map</code> object.
+ *
+ * @param newCp the constant pool table used by the new copy.
+ * @param classnames pairs of replaced and substituted
+ * class names.
+ */
+ @Override
+ public AttributeInfo copy(ConstPool newCp, Map<String, String> classnames) {
+ int hostIndex = ByteArray.readU16bit(get(), 0);
+ int newHostIndex = getConstPool().copy(hostIndex, newCp, classnames);
+ return new NestHostAttribute(newCp, newHostIndex);
+ }
+
+ /**
+ * Returns <code>host_class_index</code>. The constant pool entry
+ * at this entry is a <code>CONSTANT_Class_info</code> structure.
+ * @return the value of <code>host_class_index</code>.
+ */
+ public int hostClassIndex() {
+ return ByteArray.readU16bit(info, 0);
+ }
+}
diff --git a/src/main/javassist/bytecode/NestMembersAttribute.java b/src/main/javassist/bytecode/NestMembersAttribute.java
new file mode 100644
index 00000000..a402e26e
--- /dev/null
+++ b/src/main/javassist/bytecode/NestMembersAttribute.java
@@ -0,0 +1,88 @@
+/*
+ * 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.bytecode;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * <code>NestMembers_attribute</code>.
+ * It was introduced by JEP-181. See JVMS 4.7.29 for the specification.
+ *
+ * @since 3.24
+ */
+public class NestMembersAttribute extends AttributeInfo {
+ /**
+ * The name of this attribute <code>"NestMembers"</code>.
+ */
+ public static final String tag = "NestMembers";
+
+ NestMembersAttribute(ConstPool cp, int n, DataInputStream in) throws IOException {
+ super(cp, n, in);
+ }
+
+ private NestMembersAttribute(ConstPool cp, byte[] info) {
+ super(cp, tag, info);
+ }
+
+ /**
+ * Makes a copy. Class names are replaced according to the
+ * given <code>Map</code> object.
+ *
+ * @param newCp the constant pool table used by the new copy.
+ * @param classnames pairs of replaced and substituted
+ * class names.
+ */
+ @Override
+ public AttributeInfo copy(ConstPool newCp, Map<String, String> classnames) {
+ byte[] src = get();
+ byte[] dest = new byte[src.length];
+ ConstPool cp = getConstPool();
+
+ int n = ByteArray.readU16bit(src, 0);
+ ByteArray.write16bit(n, dest, 0);
+
+ for (int i = 0, j = 2; i < n; ++i, j += 2) {
+ int index = ByteArray.readU16bit(src, j);
+ int newIndex = cp.copy(index, newCp, classnames);
+ ByteArray.write16bit(newIndex, dest, j);
+ }
+
+ return new NestMembersAttribute(newCp, dest);
+ }
+
+ /**
+ * Returns <code>number_of_classes</code>.
+ * @return the number of the classes recorded in this attribute.
+ */
+ public int numberOfClasses() {
+ return ByteArray.readU16bit(info, 0);
+ }
+
+ /** Returns <code>classes[index]</code>.
+ *
+ * @param index the index into <code>classes</code>.
+ * @return the value at the given index in the <code>classes</code> array.
+ * It is an index into the constant pool.
+ * The constant pool entry at the returned index is a
+ * <code>CONSTANT_Class_info</code> structure.
+ */
+ public int memberClass(int index) {
+ return ByteArray.readU16bit(info, index * 2 + 2);
+ }
+}
diff --git a/src/main/javassist/expr/ExprEditor.java b/src/main/javassist/expr/ExprEditor.java
index 0b3f934e..0f9bedce 100644
--- a/src/main/javassist/expr/ExprEditor.java
+++ b/src/main/javassist/expr/ExprEditor.java
@@ -35,7 +35,7 @@ import javassist.bytecode.Opcode;
* <p>If <code>instrument()</code> is called in
* <code>CtMethod</code>, the method body is scanned from the beginning
* to the end.
- * Whenever an expression, such as a method call and a <tt>new</tt>
+ * Whenever an expression, such as a method call and a <code>new</code>
* expression (object creation),
* is found, <code>edit()</code> is called in <code>ExprEdit</code>.
* <code>edit()</code> can inspect and modify the given expression.
@@ -259,10 +259,10 @@ public class ExprEditor {
}
/**
- * Edits a <tt>new</tt> expression (overridable).
+ * Edits a <code>new</code> expression (overridable).
* The default implementation performs nothing.
*
- * @param e the <tt>new</tt> expression creating an object.
+ * @param e the <code>new</code> expression creating an object.
*/
public void edit(NewExpr e) throws CannotCompileException {}
@@ -270,7 +270,7 @@ public class ExprEditor {
* Edits an expression for array creation (overridable).
* The default implementation performs nothing.
*
- * @param a the <tt>new</tt> expression for creating an array.
+ * @param a the <code>new</code> expression for creating an array.
* @throws CannotCompileException
*/
public void edit(NewArray a) throws CannotCompileException {}
diff --git a/src/main/javassist/expr/NewArray.java b/src/main/javassist/expr/NewArray.java
index 70d74afd..df30e26f 100644
--- a/src/main/javassist/expr/NewArray.java
+++ b/src/main/javassist/expr/NewArray.java
@@ -92,9 +92,9 @@ public class NewArray extends Expr {
/**
* Returns the type of array components. If the created array is
- * a two-dimensional array of <tt>int</tt>,
+ * a two-dimensional array of <code>int</code>,
* the type returned by this method is
- * not <tt>int[]</tt> but <tt>int</tt>.
+ * not <code>int[]</code> but <code>int</code>.
*/
public CtClass getComponentType() throws NotFoundException {
if (opcode == Opcode.NEWARRAY) {
diff --git a/src/main/javassist/expr/NewExpr.java b/src/main/javassist/expr/NewExpr.java
index 6b28475b..3171fc3f 100644
--- a/src/main/javassist/expr/NewExpr.java
+++ b/src/main/javassist/expr/NewExpr.java
@@ -38,7 +38,7 @@ import javassist.compiler.ProceedHandler;
import javassist.compiler.ast.ASTList;
/**
- * Object creation (<tt>new</tt> expression).
+ * Object creation (<code>new</code> expression).
*/
public class NewExpr extends Expr {
String newTypeName;
@@ -69,7 +69,7 @@ public class NewExpr extends Expr {
} */
/**
- * Returns the method or constructor containing the <tt>new</tt>
+ * Returns the method or constructor containing the <code>new</code>
* expression represented by this object.
*/
@Override
@@ -77,7 +77,7 @@ public class NewExpr extends Expr {
/**
* Returns the line number of the source line containing the
- * <tt>new</tt> expression.
+ * <code>new</code> expression.
*
* @return -1 if this information is not available.
*/
@@ -87,7 +87,7 @@ public class NewExpr extends Expr {
}
/**
- * Returns the source file containing the <tt>new</tt> expression.
+ * Returns the source file containing the <code>new</code> expression.
*
* @return null if this information is not available.
*/
@@ -173,7 +173,7 @@ public class NewExpr extends Expr {
}
/**
- * Replaces the <tt>new</tt> expression with the bytecode derived from
+ * Replaces the <code>new</code> expression with the bytecode derived from
* the given source text.
*
* <p>$0 is available but the value is null.
diff --git a/src/main/javassist/scopedpool/SoftValueHashMap.java b/src/main/javassist/scopedpool/SoftValueHashMap.java
index 1154e62e..01d8498a 100644
--- a/src/main/javassist/scopedpool/SoftValueHashMap.java
+++ b/src/main/javassist/scopedpool/SoftValueHashMap.java
@@ -31,7 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
* This Map will remove entries when the value in the map has been cleaned from
* garbage collection
*
- * @version <tt>$Revision: 1.4 $</tt>
+ * @version <code>$Revision: 1.4 $</code>
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
*/
public class SoftValueHashMap<K,V> implements Map<K,V> {
@@ -133,10 +133,10 @@ public class SoftValueHashMap<K,V> implements Map<K,V> {
/**
* Constructs a new <code>WeakHashMap</code> with the same mappings as the
- * specified <tt>Map</tt>. The <code>WeakHashMap</code> is created with
+ * specified <code>Map</code>. The <code>WeakHashMap</code> is created with
* an initial capacity of twice the number of mappings in the specified map
* or 11 (whichever is greater), and a default load factor, which is
- * <tt>0.75</tt>.
+ * <code>0.75</code>.
*
* @param t the map whose mappings are to be placed in this map.
*/
diff --git a/src/main/javassist/util/proxy/DefineClassHelper.java b/src/main/javassist/util/proxy/DefineClassHelper.java
index b367931a..96ade4aa 100644
--- a/src/main/javassist/util/proxy/DefineClassHelper.java
+++ b/src/main/javassist/util/proxy/DefineClassHelper.java
@@ -31,199 +31,214 @@ import javassist.bytecode.ClassFile;
*
* @since 3.22
*/
-public class DefineClassHelper
-{
+public class DefineClassHelper {
- private static enum SecuredPrivileged
- {
- JAVA_9 {
- final class ReferencedUnsafe
- {
- private final SecurityActions.TheUnsafe sunMiscUnsafeTheUnsafe;
- private final MethodHandle defineClass;
-
- ReferencedUnsafe(SecurityActions.TheUnsafe usf, MethodHandle meth)
- {
- this.sunMiscUnsafeTheUnsafe = usf;
- this.defineClass = meth;
- }
+ private static abstract class Helper {
+ abstract Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError, CannotCompileException;
+ }
- Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader, ProtectionDomain protectionDomain)
- throws ClassFormatError {
- try {
- if (getCallerClass.invoke(stack) != SecuredPrivileged.JAVA_9.getClass())
- throw new IllegalAccessError("Access denied for caller.");
- } catch (Exception e) {
- throw new RuntimeException("cannot initialize", e);
- }
- try {
- return (Class<?>) defineClass.invokeWithArguments(
- sunMiscUnsafeTheUnsafe.theUnsafe,
- name, b, off, len, loader, protectionDomain);
- } catch (Throwable e) {
- if (e instanceof RuntimeException) throw (RuntimeException) e;
- if (e instanceof ClassFormatError) throw (ClassFormatError) e;
- throw new ClassFormatError(e.getMessage());
- }
- }
+ private static class Java11 extends JavaOther {
+ Class<?> defineClass(String name, byte[] bcode, int off, int len, Class<?> neighbor,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError, CannotCompileException
+ {
+ if (neighbor != null)
+ return toClass(neighbor, bcode);
+ else {
+ // Lookup#defineClass() is not available. So fallback to invoking defineClass on
+ // ClassLoader, which causes a warning message.
+ return super.defineClass(name, bcode, off, len, neighbor, loader, protectionDomain);
}
- private final Object stack;
- private final Method getCallerClass;
- {
- Class<?> stackWalkerClass = null;
- try {
- stackWalkerClass = Class.forName("java.lang.StackWalker");
- } catch (ClassNotFoundException e) {
- // Skip initialization when the class doesn't exist i.e. we are on JDK < 9
- }
- if (stackWalkerClass != null) {
- try {
- Class<?> optionClass = Class.forName("java.lang.StackWalker$Option");
- stack = stackWalkerClass.getMethod("getInstance", optionClass)
- // The first one is RETAIN_CLASS_REFERENCE
- .invoke(null, optionClass.getEnumConstants()[0]);
- getCallerClass = stackWalkerClass.getMethod("getCallerClass");
- } catch (Throwable e) {
- throw new RuntimeException("cannot initialize", e);
- }
- } else {
- stack = null;
- getCallerClass = null;
- }
+ }
+ }
+
+ private static class Java9 extends Helper {
+ final class ReferencedUnsafe {
+ private final SecurityActions.TheUnsafe sunMiscUnsafeTheUnsafe;
+ private final MethodHandle defineClass;
+
+ ReferencedUnsafe(SecurityActions.TheUnsafe usf, MethodHandle meth) {
+ this.sunMiscUnsafeTheUnsafe = usf;
+ this.defineClass = meth;
}
- private final ReferencedUnsafe sunMiscUnsafe = getReferencedUnsafe();
- private final ReferencedUnsafe getReferencedUnsafe()
+
+ Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError
{
try {
- if (null != SecuredPrivileged.JAVA_9
- && getCallerClass.invoke(stack) != this.getClass())
+ if (getCallerClass.invoke(stack) != Java9.class)
throw new IllegalAccessError("Access denied for caller.");
} catch (Exception e) {
throw new RuntimeException("cannot initialize", e);
}
try {
- SecurityActions.TheUnsafe usf = SecurityActions.getSunMiscUnsafeAnonymously();
- List<Method> defineClassMethod = usf.methods.get("defineClass");
- // On Java 11+ the defineClass method does not exist anymore
- if (null == defineClassMethod)
- return null;
- MethodHandle meth = MethodHandles.lookup()
- .unreflect(defineClassMethod.get(0));
- return new ReferencedUnsafe(usf, meth);
+ return (Class<?>) defineClass.invokeWithArguments(
+ sunMiscUnsafeTheUnsafe.theUnsafe,
+ name, b, off, len, loader, protectionDomain);
} catch (Throwable e) {
- throw new RuntimeException("cannot initialize", e);
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+ throw new ClassFormatError(e.getMessage());
}
}
+ }
- @Override
- public Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader, ProtectionDomain protectionDomain)
- throws ClassFormatError
- {
+ private final Object stack;
+ private final Method getCallerClass;
+ private final ReferencedUnsafe sunMiscUnsafe = getReferencedUnsafe();
+
+ Java9 () {
+ Class<?> stackWalkerClass = null;
+ try {
+ stackWalkerClass = Class.forName("java.lang.StackWalker");
+ } catch (ClassNotFoundException e) {
+ // Skip initialization when the class doesn't exist i.e. we are on JDK < 9
+ }
+ if (stackWalkerClass != null) {
try {
- if (getCallerClass.invoke(stack) != DefineClassHelper.class)
- throw new IllegalAccessError("Access denied for caller.");
- } catch (Exception e) {
+ Class<?> optionClass = Class.forName("java.lang.StackWalker$Option");
+ stack = stackWalkerClass.getMethod("getInstance", optionClass)
+ // The first one is RETAIN_CLASS_REFERENCE
+ .invoke(null, optionClass.getEnumConstants()[0]);
+ getCallerClass = stackWalkerClass.getMethod("getCallerClass");
+ } catch (Throwable e) {
throw new RuntimeException("cannot initialize", e);
}
- return sunMiscUnsafe.defineClass(name, b, off, len, loader,
- protectionDomain);
+ } else {
+ stack = null;
+ getCallerClass = null;
}
- },
- JAVA_7 {
- private final SecurityActions stack = SecurityActions.stack;
- private final MethodHandle defineClass = getDefineClassMethodHandle();
- private final MethodHandle getDefineClassMethodHandle()
- {
- if (null != SecuredPrivileged.JAVA_7
- && stack.getCallerClass() != this.getClass())
+ }
+
+ private final ReferencedUnsafe getReferencedUnsafe() {
+ try {
+ if (privileged != null && getCallerClass.invoke(stack) != this.getClass())
throw new IllegalAccessError("Access denied for caller.");
- try {
- return SecurityActions.getMethodHandle(ClassLoader.class,
- "defineClass", new Class[] {
+ } catch (Exception e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
+ try {
+ SecurityActions.TheUnsafe usf = SecurityActions.getSunMiscUnsafeAnonymously();
+ List<Method> defineClassMethod = usf.methods.get("defineClass");
+ // On Java 11+ the defineClass method does not exist anymore
+ if (null == defineClassMethod)
+ return null;
+ MethodHandle meth = MethodHandles.lookup().unreflect(defineClassMethod.get(0));
+ return new ReferencedUnsafe(usf, meth);
+ } catch (Throwable e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
+ }
+
+ @Override
+ Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError
+ {
+ try {
+ if (getCallerClass.invoke(stack) != DefineClassHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ } catch (Exception e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
+ return sunMiscUnsafe.defineClass(name, b, off, len, loader,
+ protectionDomain);
+ }
+ }
+
+ private static class Java7 extends Helper {
+ private final SecurityActions stack = SecurityActions.stack;
+ private final MethodHandle defineClass = getDefineClassMethodHandle();
+ private final MethodHandle getDefineClassMethodHandle() {
+ if (privileged != null && stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getMethodHandle(ClassLoader.class, "defineClass",
+ new Class[] {
String.class, byte[].class, int.class, int.class,
ProtectionDomain.class
});
} catch (NoSuchMethodException e) {
throw new RuntimeException("cannot initialize", e);
}
- }
+ }
- @Override
- protected Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError
- {
- if (stack.getCallerClass() != DefineClassHelper.class)
- throw new IllegalAccessError("Access denied for caller.");
- try {
- return (Class<?>) defineClass.invokeWithArguments(
+ @Override
+ Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError
+ {
+ if (stack.getCallerClass() != DefineClassHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return (Class<?>) defineClass.invokeWithArguments(
loader, name, b, off, len, protectionDomain);
- } catch (Throwable e) {
- if (e instanceof RuntimeException) throw (RuntimeException) e;
- if (e instanceof ClassFormatError) throw (ClassFormatError) e;
- throw new ClassFormatError(e.getMessage());
- }
+ } catch (Throwable e) {
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+ throw new ClassFormatError(e.getMessage());
}
- },
- JAVA_OTHER {
- private final Method defineClass = getDefineClassMethod();
- private final SecurityActions stack = SecurityActions.stack;
- private final Method getDefineClassMethod() {
- if (null != SecuredPrivileged.JAVA_OTHER
- && stack.getCallerClass() != this.getClass())
- throw new IllegalAccessError("Access denied for caller.");
- try {
- return SecurityActions.getDeclaredMethod(ClassLoader.class,
- "defineClass", new Class[] {
+ }
+ }
+
+ private static class JavaOther extends Helper {
+ private final Method defineClass = getDefineClassMethod();
+ private final SecurityActions stack = SecurityActions.stack;
+
+ private final Method getDefineClassMethod() {
+ if (privileged != null && stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getDeclaredMethod(ClassLoader.class, "defineClass",
+ new Class[] {
String.class, byte[].class, int.class, int.class, ProtectionDomain.class
});
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("cannot initialize", e);
- }
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
}
+ }
- @Override
- protected Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError
- {
- if (stack.getCallerClass() != DefineClassHelper.class)
- throw new IllegalAccessError("Access denied for caller.");
- try {
- SecurityActions.setAccessible(defineClass, true);
- return (Class<?>) defineClass.invoke(loader, new Object[] {
+ @Override
+ Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError, CannotCompileException
+ {
+ Class<?> klass = stack.getCallerClass();
+ if (klass != DefineClassHelper.class && klass != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ SecurityActions.setAccessible(defineClass, true);
+ return (Class<?>) defineClass.invoke(loader, new Object[] {
name, b, off, len, protectionDomain
- });
- } catch (Throwable e) {
- if (e instanceof ClassFormatError) throw (ClassFormatError) e;
- if (e instanceof RuntimeException) throw (RuntimeException) e;
- throw new ClassFormatError(e.getMessage());
- }
- finally {
- SecurityActions.setAccessible(defineClass, false);
- }
+ });
+ } catch (Throwable e) {
+ if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ throw new CannotCompileException(e);
}
-
- };
-
- protected abstract Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError;
+ finally {
+ SecurityActions.setAccessible(defineClass, false);
+ }
+ }
}
// Java 11+ removed sun.misc.Unsafe.defineClass, so we fallback to invoking defineClass on
// ClassLoader until we have an implementation that uses MethodHandles.Lookup.defineClass
- private static final SecuredPrivileged privileged = ClassFile.MAJOR_VERSION > ClassFile.JAVA_10
- ? SecuredPrivileged.JAVA_OTHER
+ private static final Helper privileged = ClassFile.MAJOR_VERSION > ClassFile.JAVA_10
+ ? new Java11()
: ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
- ? SecuredPrivileged.JAVA_9
- : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7
- ? SecuredPrivileged.JAVA_7
- : SecuredPrivileged.JAVA_OTHER;
+ ? new Java9()
+ : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7 ? new Java7() : new JavaOther();
/**
* Loads a class file by a given class loader.
*
- * <p>This first tries to use {@code sun.misc.Unsafe} to load a class.
+ * <p>This first tries to use {@code java.lang.invoke.MethodHandle} to load a class.
+ * Otherwise, or if {@code neighbor} is null,
+ * this tries to use {@code sun.misc.Unsafe} to load a class.
* Then it tries to use a {@code protected} method in {@code java.lang.ClassLoader}
* via {@code PrivilegedAction}. Since the latter approach is not available
* any longer by default in Java 9 or later, the JVM argument
@@ -232,19 +247,28 @@ public class DefineClassHelper
* should be used instead.
* </p>
*
+ * @param className the name of the loaded class.
+ * @param neighbor the class contained in the same package as the loaded class.
+ * @param loader the class loader. It can be null if {@code neighbor} is not null
+ * and the JVM is Java 11 or later.
* @param domain if it is null, a default domain is used.
+ * @param bcode the bytecode for the loaded class.
* @since 3.22
*/
- public static Class<?> toClass(String className, ClassLoader loader,
+ public static Class<?> toClass(String className, Class<?> neighbor, ClassLoader loader,
ProtectionDomain domain, byte[] bcode)
throws CannotCompileException
{
try {
- return privileged.defineClass(className, bcode, 0, bcode.length, loader, domain);
+ return privileged.defineClass(className, bcode, 0, bcode.length,
+ neighbor, loader, domain);
}
catch (RuntimeException e) {
throw e;
}
+ catch (CannotCompileException e) {
+ throw e;
+ }
catch (ClassFormatError e) {
Throwable t = e.getCause();
throw new CannotCompileException(t == null ? e : t);
@@ -254,6 +278,48 @@ public class DefineClassHelper
}
}
+
+ /**
+ * Loads a class file by {@code java.lang.invoke.MethodHandles.Lookup}.
+ * It is obtained by using {@code neighbor}.
+ *
+ * @param neighbor a class belonging to the same package that the loaded
+ * class belogns to.
+ * @param bcode the bytecode.
+ * @since 3.24
+ */
+ public static Class<?> toClass(Class<?> neighbor, byte[] bcode)
+ throws CannotCompileException
+ {
+ try {
+ DefineClassHelper.class.getModule().addReads(neighbor.getModule());
+ Lookup lookup = MethodHandles.lookup();
+ Lookup prvlookup = MethodHandles.privateLookupIn(neighbor, lookup);
+ return prvlookup.defineClass(bcode);
+ } catch (IllegalAccessException | IllegalArgumentException e) {
+ throw new CannotCompileException(e.getMessage() + ": " + neighbor.getName()
+ + " has no permission to define the class");
+ }
+ }
+
+ /**
+ * Loads a class file by {@code java.lang.invoke.MethodHandles.Lookup}.
+ * It can be obtained by {@code MethodHandles.lookup()} called from
+ * somewhere in the package that the loaded class belongs to.
+ *
+ * @param bcode the bytecode.
+ * @since 3.24
+ */
+ public static Class<?> toClass(Lookup lookup, byte[] bcode)
+ throws CannotCompileException
+ {
+ try {
+ return lookup.defineClass(bcode);
+ } catch (IllegalAccessException | IllegalArgumentException e) {
+ throw new CannotCompileException(e.getMessage());
+ }
+ }
+
/**
* Loads a class file by {@code java.lang.invoke.MethodHandles.Lookup}.
*
diff --git a/src/main/javassist/util/proxy/DefinePackageHelper.java b/src/main/javassist/util/proxy/DefinePackageHelper.java
index 2124eebe..8a91eb28 100644
--- a/src/main/javassist/util/proxy/DefinePackageHelper.java
+++ b/src/main/javassist/util/proxy/DefinePackageHelper.java
@@ -32,110 +32,113 @@ import javassist.bytecode.ClassFile;
*/
public class DefinePackageHelper
{
-
- private static enum SecuredPrivileged
- {
- JAVA_9 {
- // definePackage has been discontinued for JAVA 9
- @Override
- protected Package definePackage(ClassLoader loader, String name, String specTitle,
+ private static abstract class Helper {
+ abstract Package definePackage(ClassLoader loader, String name, String specTitle,
+ String specVersion, String specVendor, String implTitle, String implVersion,
+ String implVendor, URL sealBase)
+ throws IllegalArgumentException;
+ }
+
+ private static class Java9 extends Helper {
+ // definePackage has been discontinued for JAVA 9
+ @Override
+ Package definePackage(ClassLoader loader, String name, String specTitle,
String specVersion, String specVendor, String implTitle, String implVersion,
- String implVendor, URL sealBase) throws IllegalArgumentException
- {
- throw new RuntimeException("define package has been disabled for jigsaw");
- }
- },
- JAVA_7 {
- private final SecurityActions stack = SecurityActions.stack;
- private final MethodHandle definePackage = getDefinePackageMethodHandle();
- private MethodHandle getDefinePackageMethodHandle()
- {
- if (stack.getCallerClass() != this.getClass())
- throw new IllegalAccessError("Access denied for caller.");
- try {
- return SecurityActions.getMethodHandle(ClassLoader.class,
+ String implVendor, URL sealBase)
+ throws IllegalArgumentException
+ {
+ throw new RuntimeException("define package has been disabled for jigsaw");
+ }
+ };
+
+ private static class Java7 extends Helper {
+ private final SecurityActions stack = SecurityActions.stack;
+ private final MethodHandle definePackage = getDefinePackageMethodHandle();
+
+ private MethodHandle getDefinePackageMethodHandle() {
+ if (stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getMethodHandle(ClassLoader.class,
"definePackage", new Class[] {
String.class, String.class, String.class, String.class,
String.class, String.class, String.class, URL.class
});
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("cannot initialize", e);
- }
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
}
+ }
- @Override
- protected Package definePackage(ClassLoader loader, String name, String specTitle,
+ @Override
+ Package definePackage(ClassLoader loader, String name, String specTitle,
String specVersion, String specVendor, String implTitle, String implVersion,
- String implVendor, URL sealBase) throws IllegalArgumentException {
- if (stack.getCallerClass() != DefinePackageHelper.class)
- throw new IllegalAccessError("Access denied for caller.");
- try {
- return (Package) definePackage.invokeWithArguments(loader, name, specTitle,
+ String implVendor, URL sealBase)
+ throws IllegalArgumentException
+ {
+ if (stack.getCallerClass() != DefinePackageHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return (Package) definePackage.invokeWithArguments(loader, name, specTitle,
specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
- } catch (Throwable e) {
- if (e instanceof IllegalArgumentException) throw (IllegalArgumentException) e;
- if (e instanceof RuntimeException) throw (RuntimeException) e;
- }
- return null;
+ } catch (Throwable e) {
+ if (e instanceof IllegalArgumentException) throw (IllegalArgumentException) e;
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
}
- },
- JAVA_OTHER {
- private final SecurityActions stack = SecurityActions.stack;
- private final Method definePackage = getDefinePackageMethod();
- private Method getDefinePackageMethod()
- {
- if (stack.getCallerClass() != this.getClass())
- throw new IllegalAccessError("Access denied for caller.");
- try {
- return SecurityActions.getDeclaredMethod(ClassLoader.class,
+ return null;
+ }
+ }
+
+ private static class JavaOther extends Helper {
+ private final SecurityActions stack = SecurityActions.stack;
+ private final Method definePackage = getDefinePackageMethod();
+
+ private Method getDefinePackageMethod() {
+ if (stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getDeclaredMethod(ClassLoader.class,
"definePackage", new Class[] {
String.class, String.class, String.class, String.class,
String.class, String.class, String.class, URL.class
});
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("cannot initialize", e);
- }
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
}
+ }
- @Override
- protected Package definePackage(ClassLoader loader, String name, String specTitle,
+ @Override
+ Package definePackage(ClassLoader loader, String name, String specTitle,
String specVersion, String specVendor, String implTitle, String implVersion,
- String implVendor, URL sealBase) throws IllegalArgumentException
- {
- if (stack.getCallerClass() != DefinePackageHelper.class)
- throw new IllegalAccessError("Access denied for caller.");
- try {
- definePackage.setAccessible(true);
- return (Package) definePackage.invoke(loader, new Object[] {
+ String implVendor, URL sealBase)
+ throws IllegalArgumentException
+ {
+ if (stack.getCallerClass() != DefinePackageHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ definePackage.setAccessible(true);
+ return (Package) definePackage.invoke(loader, new Object[] {
name, specTitle, specVersion, specVendor, implTitle,
implVersion, implVendor, sealBase
});
- } catch (Throwable e) {
- if (e instanceof InvocationTargetException) {
- Throwable t = ((InvocationTargetException) e).getTargetException();
- if (t instanceof IllegalArgumentException)
- throw (IllegalArgumentException) t;
- }
- if (e instanceof RuntimeException) throw (RuntimeException) e;
- }
- finally {
- definePackage.setAccessible(false);
+ } catch (Throwable e) {
+ if (e instanceof InvocationTargetException) {
+ Throwable t = ((InvocationTargetException) e).getTargetException();
+ if (t instanceof IllegalArgumentException)
+ throw (IllegalArgumentException) t;
}
- return null;
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
}
- };
-
- protected abstract Package definePackage(ClassLoader loader, String name, String specTitle,
- String specVersion, String specVendor, String implTitle, String implVersion,
- String implVendor, URL sealBase) throws IllegalArgumentException;
- }
-
- private static final SecuredPrivileged privileged = ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
- ? SecuredPrivileged.JAVA_9
- : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7
- ? SecuredPrivileged.JAVA_7
- : SecuredPrivileged.JAVA_OTHER;
+ finally {
+ definePackage.setAccessible(false);
+ }
+ return null;
+ }
+ };
+ private static final Helper privileged
+ = ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
+ ? new Java9() : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7
+ ? new Java7() : new JavaOther();
/**
* Defines a new package. If the package is already defined, this method
diff --git a/src/main/javassist/util/proxy/FactoryHelper.java b/src/main/javassist/util/proxy/FactoryHelper.java
index 1fb63b65..1928fdd5 100644
--- a/src/main/javassist/util/proxy/FactoryHelper.java
+++ b/src/main/javassist/util/proxy/FactoryHelper.java
@@ -104,28 +104,55 @@ public class FactoryHelper {
* This method uses a default protection domain for the class
* but it may not work with a security manager or a signed jar file.
*
- * @see #toClass(ClassFile,ClassLoader,ProtectionDomain)
+ * @see #toClass(ClassFile,Class,ClassLoader,ProtectionDomain)
+ * @deprecated
*/
public static Class<?> toClass(ClassFile cf, ClassLoader loader)
throws CannotCompileException
{
- return toClass(cf, loader, null);
+ return toClass(cf, null, loader, null);
}
/**
* Loads a class file by a given class loader.
*
+ * @param neighbor a class belonging to the same package that
+ * the loaded class belongs to.
+ * It can be null.
+ * @param loader The class loader. It can be null if {@code neighbor}
+ * is not null.
* @param domain if it is null, a default domain is used.
* @since 3.3
*/
- public static Class<?> toClass(ClassFile cf, ClassLoader loader, ProtectionDomain domain)
+ public static Class<?> toClass(ClassFile cf, Class<?> neighbor,
+ ClassLoader loader, ProtectionDomain domain)
throws CannotCompileException
{
try {
byte[] b = toBytecode(cf);
if (ProxyFactory.onlyPublicMethods)
return DefineClassHelper.toPublicClass(cf.getName(), b);
- return DefineClassHelper.toClass(cf.getName(), loader, domain, b);
+ else
+ return DefineClassHelper.toClass(cf.getName(), neighbor,
+ loader, domain, b);
+ }
+ catch (IOException e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
+ /**
+ * Loads a class file by a given lookup.
+ *
+ * @param lookup used to define the class.
+ * @since 3.24
+ */
+ public static Class<?> toClass(ClassFile cf, java.lang.invoke.MethodHandles.Lookup lookup)
+ throws CannotCompileException
+ {
+ try {
+ byte[] b = toBytecode(cf);
+ return DefineClassHelper.toClass(lookup, b);
}
catch (IOException e) {
throw new CannotCompileException(e);
diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java
index 646bbcc4..0c39a508 100644
--- a/src/main/javassist/util/proxy/ProxyFactory.java
+++ b/src/main/javassist/util/proxy/ProxyFactory.java
@@ -35,6 +35,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.lang.invoke.MethodHandles.Lookup;
import javassist.CannotCompileException;
import javassist.bytecode.AccessFlag;
@@ -213,7 +214,7 @@ public class ProxyFactory {
*
* <p>The default value is {@code false}.</p>
*
- * @see DefineClassHelper#toClass(String, ClassLoader, ProtectionDomain, byte[])
+ * @see DefineClassHelper#toClass(String, Class, ClassLoader, ProtectionDomain, byte[])
* @since 3.22
*/
public static boolean onlyPublicMethods = false;
@@ -436,43 +437,92 @@ public class ProxyFactory {
/**
* Generates a proxy class using the current filter.
+ * The module or package where a proxy class is created
+ * has to be opened to this package or the Javassist module.
+ *
+ * @see #createClass(Lookup)
*/
public Class<?> createClass() {
if (signature == null) {
computeSignature(methodFilter);
}
- return createClass1();
+ return createClass1(null);
}
/**
* Generates a proxy class using the supplied filter.
+ * The module or package where a proxy class is created
+ * has to be opened to this package or the Javassist module.
*/
public Class<?> createClass(MethodFilter filter) {
computeSignature(filter);
- return createClass1();
+ return createClass1(null);
}
/**
* Generates a proxy class with a specific signature.
* access is package local so ProxyObjectInputStream can use this
* @param signature
- * @return
*/
Class<?> createClass(byte[] signature)
{
installSignature(signature);
- return createClass1();
+ return createClass1(null);
+ }
+
+ /**
+ * Generates a proxy class using the current filter.
+ *
+ * @param lookup used for loading the proxy class.
+ * It needs an appropriate right to invoke {@code defineClass}
+ * for the proxy class.
+ * @since 3.24
+ */
+ public Class<?> createClass(Lookup lookup) {
+ if (signature == null) {
+ computeSignature(methodFilter);
+ }
+ return createClass1(lookup);
+ }
+
+ /**
+ * Generates a proxy class using the supplied filter.
+ *
+ * @param lookup used for loading the proxy class.
+ * It needs an appropriate right to invoke {@code defineClass}
+ * for the proxy class.
+ * @param filter the filter.
+ * @since 3.24
+ */
+ public Class<?> createClass(Lookup lookup, MethodFilter filter) {
+ computeSignature(filter);
+ return createClass1(lookup);
}
- private Class<?> createClass1() {
+ /**
+ * Generates a proxy class with a specific signature.
+ * access is package local so ProxyObjectInputStream can use this.
+ *
+ * @param lookup used for loading the proxy class.
+ * It needs an appropriate right to invoke {@code defineClass}
+ * for the proxy class.
+ * @param signature the signature.
+ */
+ Class<?> createClass(Lookup lookup, byte[] signature)
+ {
+ installSignature(signature);
+ return createClass1(lookup);
+ }
+
+ private Class<?> createClass1(Lookup lookup) {
Class<?> result = thisClass;
if (result == null) {
ClassLoader cl = getClassLoader();
synchronized (proxyCache) {
if (factoryUseCache)
- createClass2(cl);
+ createClass2(cl, lookup);
else
- createClass3(cl);
+ createClass3(cl, lookup);
result = thisClass;
// don't retain any unwanted references
@@ -512,7 +562,7 @@ public class ProxyFactory {
return sbuf.toString();
}
- private void createClass2(ClassLoader cl) {
+ private void createClass2(ClassLoader cl, Lookup lookup) {
String key = getKey(superClass, interfaces, signature, factoryWriteReplace);
/*
* Excessive concurrency causes a large memory footprint and slows the
@@ -534,13 +584,13 @@ public class ProxyFactory {
return;
}
}
- createClass3(cl);
+ createClass3(cl, lookup);
details = new ProxyDetails(signature, thisClass, factoryWriteReplace);
cacheForTheLoader.put(key, details);
// }
}
- private void createClass3(ClassLoader cl) {
+ private void createClass3(ClassLoader cl, Lookup lookup) {
// we need a new class so we need a new class name
allocateClassName();
@@ -549,7 +599,11 @@ public class ProxyFactory {
if (writeDirectory != null)
FactoryHelper.writeFile(cf, writeDirectory);
- thisClass = FactoryHelper.toClass(cf, cl, getDomain());
+ if (lookup == null)
+ thisClass = FactoryHelper.toClass(cf, getClassInTheSamePackage(), cl, getDomain());
+ else
+ thisClass = FactoryHelper.toClass(cf, lookup);
+
setField(FILTER_SIGNATURE_FIELD, signature);
// legacy behaviour : we only set the default interceptor static field if we are not using the cache
if (!factoryUseCache) {
@@ -562,6 +616,20 @@ public class ProxyFactory {
}
+ /**
+ * Obtains a class belonging to the same package that the created
+ * proxy class belongs to. It is used to obtain an appropriate
+ * {@code java.lang.invoke.MethodHandles.Lookup}.
+ */
+ private Class<?> getClassInTheSamePackage() {
+ if (superClass != null && superClass != OBJECT_TYPE)
+ return superClass;
+ else if (interfaces != null && interfaces.length > 0)
+ return interfaces[0];
+ else
+ return this.getClass(); // maybe wrong?
+ }
+
private void setField(String fieldName, Object value) {
if (thisClass != null && value != null)
try {
@@ -1186,8 +1254,8 @@ public class ProxyFactory {
// put the method to the cache, retrieve previous definition (if any)
Method oldMethod = hash.put(key, m);
- // JIRA JASSIST-244
- // ignore a bridge method with the same signature that the overridden one has.
+ // JIRA JASSIST-244, 267
+ // ignore a bridge method to a method declared in a non-public class.
if (null != oldMethod && isBridge(m)
&& !Modifier.isPublic(oldMethod.getDeclaringClass().getModifiers())
&& !Modifier.isAbstract(oldMethod.getModifiers()) && !isDuplicated(i, methods))
diff --git a/src/main/javassist/util/proxy/SecurityActions.java b/src/main/javassist/util/proxy/SecurityActions.java
index acb89c8d..c940561b 100755
--- a/src/main/javassist/util/proxy/SecurityActions.java
+++ b/src/main/javassist/util/proxy/SecurityActions.java
@@ -36,6 +36,7 @@ import javassist.bytecode.ClassFile;
class SecurityActions extends SecurityManager
{
public static final SecurityActions stack = new SecurityActions();
+
/**
* Since Java 9 abruptly removed <code>Reflection.getCallerClass()</code>
* in favour of <code>StackWalker</code> we are left having to find a
@@ -46,14 +47,13 @@ class SecurityActions extends SecurityManager
* functional across all versions, for now.
*
* @return represents the declaring class of the method that invoked
- * the method that called this or idx 2 on the stack trace.
- * @since 3.23 */
- public Class<?> getCallerClass()
- {
+ * the method that called this or index 2 on the stack trace.
+ * @since 3.23
+ */
+ public Class<?> getCallerClass() {
return getClassContext()[2];
}
-
static Method[] getDeclaredMethods(final Class<?> clazz)
{
if (System.getSecurityManager() == null)
diff --git a/src/test/DefineClassCapability.java b/src/test/DefineClassCapability.java
new file mode 100644
index 00000000..c6dec200
--- /dev/null
+++ b/src/test/DefineClassCapability.java
@@ -0,0 +1,5 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+public class DefineClassCapability {
+}
diff --git a/src/test/javassist/JvstTest.java b/src/test/javassist/JvstTest.java
index e2f9211f..aab0b907 100644
--- a/src/test/javassist/JvstTest.java
+++ b/src/test/javassist/JvstTest.java
@@ -1,6 +1,8 @@
package javassist;
import junit.framework.*;
+import test1.DefineClassCapability;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@@ -743,8 +745,8 @@ public class JvstTest extends JvstTestRoot {
ctInterface.stopPruning(true);
ctInterface.writeFile();
- ctInterface.toClass();
- targetCtClass.toClass();
+ ctInterface.toClass(DefineClassCapability.class);
+ targetCtClass.toClass(DefineClassCapability.class);
}
public void testDispatch() throws Exception {
@@ -1161,6 +1163,7 @@ public class JvstTest extends JvstTestRoot {
suite.addTestSuite(javassist.SetterTest.class);
suite.addTestSuite(javassist.bytecode.InsertGap0.class);
suite.addTestSuite(javassist.tools.reflect.LoaderTest.class);
+ suite.addTestSuite(javassist.tools.CallbackTest.class);
suite.addTestSuite(testproxy.ProxyTester.class);
suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class); // remove?
suite.addTestSuite(javassist.proxyfactory.ProxyFactoryTest.class);
diff --git a/src/test/javassist/JvstTest2.java b/src/test/javassist/JvstTest2.java
index 117560c0..0ea4571b 100644
--- a/src/test/javassist/JvstTest2.java
+++ b/src/test/javassist/JvstTest2.java
@@ -9,6 +9,7 @@ import org.junit.runners.MethodSorters;
import java.lang.reflect.Method;
import javassist.expr.*;
+import test2.DefineClassCapability;
@SuppressWarnings({"rawtypes","unused"})
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -709,7 +710,7 @@ public class JvstTest2 extends JvstTestRoot {
public void testToClass() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.makeClass("test2.ToClassTest");
- Class c = cc.toClass();
+ Class c = cc.toClass(DefineClassCapability.class);
assertEquals(getClass().getClassLoader(), c.getClassLoader());
}
diff --git a/src/test/javassist/JvstTest3.java b/src/test/javassist/JvstTest3.java
index 47131a93..46f06b16 100644
--- a/src/test/javassist/JvstTest3.java
+++ b/src/test/javassist/JvstTest3.java
@@ -340,7 +340,7 @@ public class JvstTest3 extends JvstTestRoot {
System.out.println("Num Annotation : " +ans.length);
// c.debugWriteFile();
- Class newclass = c.toClass();
+ Class newclass = c.toClass(DefineClassCapability.class);
java.lang.annotation.Annotation[] anns = newclass.getAnnotations();
System.out.println("Num NewClass Annotation : " +anns.length);
assertEquals(ans.length, anns.length);
@@ -737,7 +737,7 @@ public class JvstTest3 extends JvstTestRoot {
CtMethod m2 = cc2.getDeclaredMethod("getX");
copyAnnotations(m1, m2);
cc2.getClassFile();
- Class clazz = cc2.toClass();
+ Class clazz = cc2.toClass(DefineClassCapability.class);
java.lang.reflect.Method m = clazz.getDeclaredMethod("getX", new Class[0]);
assertEquals(1, m.getAnnotations().length);
test3.VisibleAnno a = m.getAnnotation(test3.VisibleAnno.class);
@@ -790,7 +790,7 @@ public class JvstTest3 extends JvstTestRoot {
cc.addField(fobj, CtField.Initializer.constant("bar"));
cc.writeFile();
- Class clazz = cc.toClass();
+ Class clazz = cc.toClass(DefineClassCapability.class);
assertEquals(2L, clazz.getField("j").getLong(null));
assertEquals(3, clazz.getField("i").getInt(null));
assertEquals(4, clazz.getField("s").getShort(null));
@@ -1108,7 +1108,7 @@ public class JvstTest3 extends JvstTestRoot {
sb.append("}");
ctc.addMethod(CtNewMethod.make(sb.toString(), ctc));
ctc.debugWriteFile();
- ctc.toClass().getConstructor().newInstance();
+ ctc.toClass(DefineClassCapability.class).getConstructor().newInstance();
}
// JIRA-83
diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java
index 187abb3d..7c8c7457 100644
--- a/src/test/javassist/JvstTest4.java
+++ b/src/test/javassist/JvstTest4.java
@@ -1054,7 +1054,7 @@ public class JvstTest4 extends JvstTestRoot {
addDeadCode(newClass, "public boolean evaluate7(){ return !true; }");
newClass.debugWriteFile();
- Class<?> cClass = newClass.toClass();
+ Class<?> cClass = newClass.toClass(test4.DefineClassCapability.class);
Object o = cClass.getConstructor().newInstance();
java.lang.reflect.Method m = cClass.getMethod("evaluate");
m.invoke(o);
@@ -1112,6 +1112,7 @@ public class JvstTest4 extends JvstTestRoot {
attr.setAnnotation(a);
m.getMethodInfo().addAttribute(attr);
cc.writeFile();
+ anno.toClass(test4.DefineClassCapability.class);
Class<?> rc = ((java.lang.annotation.Annotation)m.getAnnotations()[0]).annotationType();
assertEquals(anno.getName(), rc.getName());
}
diff --git a/src/test/javassist/JvstTest5.java b/src/test/javassist/JvstTest5.java
index 6f6eb075..c5eff4d1 100644
--- a/src/test/javassist/JvstTest5.java
+++ b/src/test/javassist/JvstTest5.java
@@ -9,6 +9,8 @@ import javassist.bytecode.AttributeInfo;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.InnerClassesAttribute;
+import javassist.bytecode.NestHostAttribute;
+import javassist.bytecode.NestMembersAttribute;
import javassist.expr.ExprEditor;
import javassist.expr.Handler;
import javassist.expr.MethodCall;
@@ -221,7 +223,7 @@ public class JvstTest5 extends JvstTestRoot {
"}");
System.out.println(src);
badClass.addMethod(CtMethod.make(src, badClass));
- Class clazzz = badClass.toClass();
+ Class clazzz = badClass.toClass(Class.forName("DefineClassCapability"));
Object obj = clazzz.getConstructor().newInstance(); // <-- falls here
}
@@ -416,4 +418,39 @@ public class JvstTest5 extends JvstTestRoot {
Object obj = make(cc.getName());
assertEquals(1, invoke(obj, "test"));
}
+
+ public void testNestHostAttribute() throws Exception {
+ CtClass cc = sloader.get("test5.NestHost$Foo");
+ ClassFile cf = cc.getClassFile();
+ NestHostAttribute attr = (NestHostAttribute)cf.getAttribute(NestHostAttribute.tag);
+ assertEquals(test5.NestHost.class.getName(),
+ cf.getConstPool().getClassInfo(attr.hostClassIndex()));
+ }
+
+ public void testNestMembersAttribute() throws Exception {
+ CtClass cc = sloader.get("test5.NestHost");
+ ClassFile cf = cc.getClassFile();
+ NestMembersAttribute attr = (NestMembersAttribute)cf.getAttribute(NestMembersAttribute.tag);
+ assertEquals(2, attr.numberOfClasses());
+ String[] names = new String[2];
+ for (int i = 0; i < 2; i++)
+ names[i] = cf.getConstPool().getClassInfo(attr.memberClass(i));
+
+ assertFalse(names[0].equals(names[1]));
+ assertTrue(names[0].equals("test5.NestHost$Foo") || names[0].equals("test5.NestHost$Bar"));
+ assertTrue(names[1].equals("test5.NestHost$Foo") || names[1].equals("test5.NestHost$Bar"));
+ }
+
+ public void testNestMembersAttributeCopy() throws Exception {
+ CtClass cc = sloader.get("test5.NestHost2");
+ cc.getClassFile().compact();
+ cc.writeFile();
+ make(cc.getName());
+ }
+
+ public void testNestHostAttributeCopy() throws Exception {
+ CtClass cc = sloader.get("test5.NestHost2$Foo");
+ cc.getClassFile().compact();
+ cc.toClass(test5.DefineClassCapability.class);
+ }
}
diff --git a/src/test/javassist/SetterTest.java b/src/test/javassist/SetterTest.java
index 44eec140..a76b2a30 100644
--- a/src/test/javassist/SetterTest.java
+++ b/src/test/javassist/SetterTest.java
@@ -1,112 +1,114 @@
-package javassist;
-import java.lang.reflect.Method;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings({"rawtypes","unchecked"})
-public class SetterTest extends TestCase {
-
- ClassPool pool;
-
- public SetterTest(String name) {
- super(name);
- }
-
- protected void setUp() throws Exception {
- super.setUp();
- pool = ClassPool.getDefault();
- }
-
- /**
- * Tests a getter only on a field without a Modifier.
- *
- * @throws Exception
- */
- public void testFieldGetter() throws Exception {
- CtClass clazz = pool.makeClass("HasFieldGetter");
- clazz.setSuperclass(pool.get("java.lang.Object"));
- CtField field = new CtField(CtClass.booleanType, "broken", clazz);
- clazz.addField(field, "true");
- clazz.addMethod(CtNewMethod.getter("isBroken", field));
- Class _class = clazz.toClass();
-
- Object object = _class.getConstructor().newInstance();
- check(_class, object, true);
- }
-
- /**
- * Tests a getter and a setter on a field without a Modifier.
- *
- * @throws Exception
- */
- public void testFieldGetterSetter() throws Exception {
- CtClass clazz = pool.makeClass("HasFieldGetterSetter");
- clazz.setSuperclass(pool.get("java.lang.Object"));
- CtField field = new CtField(CtClass.booleanType, "broken", clazz);
- clazz.addField(field, "true");
- clazz.addMethod(CtNewMethod.getter("isBroken", field));
- clazz.addMethod(CtNewMethod.setter("setBroken", field));
- Class _class = clazz.toClass();
-
- Object object = _class.getConstructor().newInstance();
-
- set(_class, object, false);
- check(_class, object, false);
- }
-
- /**
- * Tests a getter only on a field with Modifier.STATIC.
- *
- * @throws Exception
- */
- public void testStaticFieldGetter() throws Exception {
- CtClass clazz = pool.makeClass("HasStaticFieldGetter");
- clazz.setSuperclass(pool.get("java.lang.Object"));
- CtField field = new CtField(CtClass.booleanType, "broken", clazz);
- field.setModifiers(Modifier.STATIC);
- clazz.addField(field, "true");
- clazz.addMethod(CtNewMethod.getter("isBroken", field));
- Class _class = clazz.toClass();
-
- Object object = _class.getConstructor().newInstance();
- check(_class, object, true);
- }
-
- /**
- * Tests a getter and setter on a field with Modifier.STATIC.
- *
- * @throws Exception
- */
- public void testStaticFieldGetterSetter() throws Exception {
- CtClass clazz = pool.makeClass("HasStaticFieldGetterSetter");
- clazz.setSuperclass(pool.get("java.lang.Object"));
- CtField field = new CtField(CtClass.booleanType, "broken", clazz);
- field.setModifiers(Modifier.STATIC);
- clazz.addField(field, "true");
- clazz.addMethod(CtNewMethod.getter("isBroken", field));
- clazz.addMethod(CtNewMethod.setter("setBroken", field));
- Class _class = clazz.toClass();
-
- Object object = _class.getConstructor().newInstance();
-
- set(_class, object, false);
- check(_class, object, false);
- }
-
- private void check(Class _class, Object object, boolean shouldBe)
- throws Exception
- {
- Method method = _class.getMethod("isBroken", new Class[] {});
- Boolean result = (Boolean) method.invoke(object, new Object[] {});
- assertEquals("boolean is wrong value",
- shouldBe, result.booleanValue());
- }
-
- private void set(Class _class, Object object, boolean willBe)
- throws Exception
- {
- Method method = _class.getMethod("setBroken",
- new Class[] {Boolean.TYPE});
- method.invoke(object, new Object[] { Boolean.valueOf(willBe)});
- }
-}
+package javassist;
+import java.lang.reflect.Method;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings({"rawtypes","unchecked"})
+public class SetterTest extends TestCase {
+
+ ClassPool pool;
+ Class<?> capability;
+
+ public SetterTest(String name) {
+ super(name);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ pool = ClassPool.getDefault();
+ capability = Class.forName("DefineClassCapability");
+ }
+
+ /**
+ * Tests a getter only on a field without a Modifier.
+ *
+ * @throws Exception
+ */
+ public void testFieldGetter() throws Exception {
+ CtClass clazz = pool.makeClass("HasFieldGetter");
+ clazz.setSuperclass(pool.get("java.lang.Object"));
+ CtField field = new CtField(CtClass.booleanType, "broken", clazz);
+ clazz.addField(field, "true");
+ clazz.addMethod(CtNewMethod.getter("isBroken", field));
+ Class _class = clazz.toClass(capability);
+
+ Object object = _class.getConstructor().newInstance();
+ check(_class, object, true);
+ }
+
+ /**
+ * Tests a getter and a setter on a field without a Modifier.
+ *
+ * @throws Exception
+ */
+ public void testFieldGetterSetter() throws Exception {
+ CtClass clazz = pool.makeClass("HasFieldGetterSetter");
+ clazz.setSuperclass(pool.get("java.lang.Object"));
+ CtField field = new CtField(CtClass.booleanType, "broken", clazz);
+ clazz.addField(field, "true");
+ clazz.addMethod(CtNewMethod.getter("isBroken", field));
+ clazz.addMethod(CtNewMethod.setter("setBroken", field));
+ Class _class = clazz.toClass(capability);
+
+ Object object = _class.getConstructor().newInstance();
+
+ set(_class, object, false);
+ check(_class, object, false);
+ }
+
+ /**
+ * Tests a getter only on a field with Modifier.STATIC.
+ *
+ * @throws Exception
+ */
+ public void testStaticFieldGetter() throws Exception {
+ CtClass clazz = pool.makeClass("HasStaticFieldGetter");
+ clazz.setSuperclass(pool.get("java.lang.Object"));
+ CtField field = new CtField(CtClass.booleanType, "broken", clazz);
+ field.setModifiers(Modifier.STATIC);
+ clazz.addField(field, "true");
+ clazz.addMethod(CtNewMethod.getter("isBroken", field));
+ Class _class = clazz.toClass(capability);
+
+ Object object = _class.getConstructor().newInstance();
+ check(_class, object, true);
+ }
+
+ /**
+ * Tests a getter and setter on a field with Modifier.STATIC.
+ *
+ * @throws Exception
+ */
+ public void testStaticFieldGetterSetter() throws Exception {
+ CtClass clazz = pool.makeClass("HasStaticFieldGetterSetter");
+ clazz.setSuperclass(pool.get("java.lang.Object"));
+ CtField field = new CtField(CtClass.booleanType, "broken", clazz);
+ field.setModifiers(Modifier.STATIC);
+ clazz.addField(field, "true");
+ clazz.addMethod(CtNewMethod.getter("isBroken", field));
+ clazz.addMethod(CtNewMethod.setter("setBroken", field));
+ Class _class = clazz.toClass(capability);
+
+ Object object = _class.getConstructor().newInstance();
+
+ set(_class, object, false);
+ check(_class, object, false);
+ }
+
+ private void check(Class _class, Object object, boolean shouldBe)
+ throws Exception
+ {
+ Method method = _class.getMethod("isBroken", new Class[] {});
+ Boolean result = (Boolean) method.invoke(object, new Object[] {});
+ assertEquals("boolean is wrong value",
+ shouldBe, result.booleanValue());
+ }
+
+ private void set(Class _class, Object object, boolean willBe)
+ throws Exception
+ {
+ Method method = _class.getMethod("setBroken",
+ new Class[] {Boolean.TYPE});
+ method.invoke(object, new Object[] { Boolean.valueOf(willBe)});
+ }
+}
diff --git a/src/test/javassist/bytecode/InsertGap0.java b/src/test/javassist/bytecode/InsertGap0.java
index 824b9305..425f12d7 100644
--- a/src/test/javassist/bytecode/InsertGap0.java
+++ b/src/test/javassist/bytecode/InsertGap0.java
@@ -175,7 +175,7 @@ public final class InsertGap0 extends JvstTestRoot {
cc.addField(new CtField(CtClass.intType, "i", cc), "++counter");
boolean p = cc.stopPruning(true);
cc.writeFile();
- Class c = cc.toClass();
+ Class c = cc.toClass(ClassFile.class);
cc.stopPruning(p);
Object obj = c.getConstructor().newInstance();
@@ -194,7 +194,7 @@ public final class InsertGap0 extends JvstTestRoot {
cc.addField(new CtField(CtClass.intType, "i", cc), "++counter");
boolean p = cc.stopPruning(true);
cc.writeFile();
- Class c = cc.toClass();
+ Class c = cc.toClass(ClassFile.class);
cc.stopPruning(p);
Object obj = c.getConstructor().newInstance();
diff --git a/src/test/javassist/tools/CallbackTest.java b/src/test/javassist/tools/CallbackTest.java
index 96632bda..f5861ceb 100644
--- a/src/test/javassist/tools/CallbackTest.java
+++ b/src/test/javassist/tools/CallbackTest.java
@@ -3,6 +3,7 @@ package javassist.tools;
import javassist.*;
import junit.framework.TestCase;
import test.javassist.tools.DummyClass;
+import test.javassist.tools.DefineClassCapability;
import static javassist.tools.Callback.*;
@@ -34,7 +35,7 @@ public class CallbackTest extends TestCase {
});
// Change class and invoke method;
- classToChange.toClass();
+ classToChange.toClass(DefineClassCapability.class);
new DummyClass().dummyMethod();
}
}
diff --git a/src/test/test/javassist/DefineClassCapability.java b/src/test/test/javassist/DefineClassCapability.java
new file mode 100644
index 00000000..e6a0fd51
--- /dev/null
+++ b/src/test/test/javassist/DefineClassCapability.java
@@ -0,0 +1,7 @@
+package test.javassist;
+
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+public class DefineClassCapability {
+}
diff --git a/src/test/test/javassist/convert/ArrayAccessReplaceTest.java b/src/test/test/javassist/convert/ArrayAccessReplaceTest.java
index d81f220d..cebd1853 100644
--- a/src/test/test/javassist/convert/ArrayAccessReplaceTest.java
+++ b/src/test/test/javassist/convert/ArrayAccessReplaceTest.java
@@ -1,7 +1,5 @@
package test.javassist.convert;
-import java.net.URL;
-import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
@@ -11,7 +9,7 @@ import javassist.CtClass;
import junit.framework.TestCase;
public class ArrayAccessReplaceTest extends TestCase {
- private static SimpleInterface simple;
+ private static SimpleInterface simple = null;
public void setUp() throws Exception {
ClassPool pool = new ClassPool(true);
@@ -21,7 +19,9 @@ public class ArrayAccessReplaceTest extends TestCase {
converter.replaceArrayAccess(echoClass, new CodeConverter.DefaultArrayAccessReplacementMethodNames());
simpleClass.instrument(converter);
//simpleClass.writeFile("/tmp");
- simple = (SimpleInterface) simpleClass.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).getConstructor().newInstance();
+
+ simple = (SimpleInterface)new javassist.Loader.Simple().invokeDefineClass(simpleClass)
+ .getConstructor().newInstance();
}
public void testComplex() throws Exception {
@@ -31,7 +31,9 @@ public class ArrayAccessReplaceTest extends TestCase {
CodeConverter converter = new CodeConverter();
converter.replaceArrayAccess(clazz, new CodeConverter.DefaultArrayAccessReplacementMethodNames());
clazz.instrument(converter);
- ComplexInterface instance = (ComplexInterface) clazz.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).getConstructor().newInstance();
+ ComplexInterface instance
+ = (ComplexInterface)new javassist.Loader.Simple().invokeDefineClass(clazz)
+ .getConstructor().newInstance();
assertEquals(Integer.valueOf(5), instance.complexRead(4));
}
diff --git a/src/test/test/javassist/proxy/ProxyCacheGCTest.java b/src/test/test/javassist/proxy/ProxyCacheGCTest.java
index 97b7281d..e47c4383 100644
--- a/src/test/test/javassist/proxy/ProxyCacheGCTest.java
+++ b/src/test/test/javassist/proxy/ProxyCacheGCTest.java
@@ -90,9 +90,9 @@ public class ProxyCacheGCTest extends TestCase
// now create a proxyfactory and use it to create a proxy
ProxyFactory factory = new ProxyFactory();
- Class javaTargetClass = classPool.toClass(ctTargetClass);
- Class javaHandlerClass = classPool.toClass(ctHandlerClass);
- Class javaFilterClass = classPool.toClass(ctFilterClass);
+ Class javaTargetClass = classPool.toClass(ctTargetClass, test.javassist.DefineClassCapability.class);
+ Class javaHandlerClass = classPool.toClass(ctHandlerClass, test.javassist.DefineClassCapability.class);
+ Class javaFilterClass = classPool.toClass(ctFilterClass, test.javassist.DefineClassCapability.class);
MethodHandler handler= (MethodHandler)javaHandlerClass.getConstructor().newInstance();
MethodFilter filter = (MethodFilter)javaFilterClass.getConstructor().newInstance();
diff --git a/src/test/test/javassist/proxy/ProxySimpleTest.java b/src/test/test/javassist/proxy/ProxySimpleTest.java
index 76178a7e..63298501 100644
--- a/src/test/test/javassist/proxy/ProxySimpleTest.java
+++ b/src/test/test/javassist/proxy/ProxySimpleTest.java
@@ -330,5 +330,36 @@ public class ProxySimpleTest extends TestCase {
public static class Extended267 extends Base267 {
public String base(Integer i) { return "extended" + i + i; }
}
+
+ String value267b;
+ public void testJIRA267b() throws Exception {
+ Extended267b extended267 = new Extended267b();
+ ProxyFactory factory = new ProxyFactory();
+ factory.setSuperclass(Extended267b.class);
+ Extended267b e = (Extended267b)factory.create(null, null, new MethodHandler() {
+ @Override
+ public Object invoke(Object self, Method thisMethod,
+ Method proceed, Object[] args) throws Throwable {
+ value267b += thisMethod.getDeclaringClass().getName();
+ value267b += ";" + thisMethod.getReturnType().getName();
+ return proceed.invoke(self, args);
+ }
+ });
+
+ value267b = "";
+ assertEquals("extended", e.base());
+ System.out.println(value267b);
+ assertEquals(Extended267b.class.getName() + ";" + String.class.getName(), value267b);
+ }
+
+ public static class Base267b {
+ public Object base() { return "base"; }
+ }
+
+ // Extended267b has a bridge method for base():Object,
+ // since Extended267b#base() is covariant.
+ public static class Extended267b extends Base267b {
+ public String base() { return "extended"; }
+ }
}
diff --git a/src/test/test/javassist/proxy/TestSecuredPrivileged.java b/src/test/test/javassist/proxy/TestSecuredPrivileged.java
deleted file mode 100644
index c51555f5..00000000
--- a/src/test/test/javassist/proxy/TestSecuredPrivileged.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package test.javassist.proxy;
-import static org.hamcrest.Matchers.arrayWithSize;
-import static org.hamcrest.Matchers.both;
-import static org.hamcrest.Matchers.endsWith;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.startsWith;
-import static org.hamcrest.Matchers.stringContainsInOrder;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.security.ProtectionDomain;
-import java.util.Arrays;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.util.proxy.DefineClassHelper;
-
-public class TestSecuredPrivileged {
-
- public TestSecuredPrivileged() {
- }
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
- /**
- * Test proves that you cannot even access members with
- * private static and final modifiers. */
- @Test
- public void testDefinedHelperPrivilegedFieldVisibility() {
- try {
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- assertTrue(Modifier.isStatic(privi.getModifiers()));
- thrown.expectCause(instanceOf(IllegalAccessException.class));
- thrown.expectMessage(both(stringContainsInOrder(Arrays.asList("cannot access a member")))
- .and(stringContainsInOrder(Arrays.asList("with modifiers \"private static final".split("", 1)))));
-
- privi.get(null);
- } catch(Throwable t) {
- throw new RuntimeException(t);
- }
- }
- /**
- * Test proves that the default enum constant is a class and specifically
- * auto selected for Java 9. */
- @Test
- public void testDefinedHelperPrivilegedField() {
- try {
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- assertTrue(Modifier.isStatic(privi.getModifiers()));
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- DefineClassHelper inst = con.newInstance();
- assertThat(inst, instanceOf(DefineClassHelper.class));
- privi.setAccessible(true);
- Object p = privi.get(inst);
- assertThat(""+p, equalTo("JAVA_9"));
- assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$1"));
- } catch(Throwable t) {
- throw new RuntimeException(t);
- }
- }
- /**
- * Test proves that caller class security is enforced and works
- * as expected. */
- @Test
- public void testDefinedHelperPrivilegedFieldMethodAccessDenied() {
- try {
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- DefineClassHelper inst = con.newInstance();
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- privi.setAccessible(true);
- Object priviInst = privi.get(inst);
- Method defineClass = priviInst.getClass().getDeclaredMethod(
- "defineClass", new Class[] {
- String.class, byte[].class, int.class, int.class,
- ClassLoader.class, ProtectionDomain.class
- });
-
- assertThat(defineClass, notNullValue());
- defineClass.setAccessible(true);
- assertThat(defineClass.getName(), equalTo("defineClass"));
- assertTrue(defineClass.canAccess(priviInst));
- ClassPool cp = ClassPool.getDefault();
- CtClass c = cp.makeClass("a.b.C");
- byte[] bc = c.toBytecode();
-
- thrown.expectCause(instanceOf(IllegalAccessError.class));
- thrown.expectMessage(equalTo("java.lang.IllegalAccessError: Access denied for caller."));
-
- @SuppressWarnings("unused")
- Object res = defineClass.invoke(priviInst, new Object[] {
- c.getName(), bc, 0, bc.length, new ClassLoader() {},
- ClassLoader.class.getProtectionDomain()
- });
- } catch(InvocationTargetException t) {
- throw new RuntimeException(t.getTargetException());
- } catch(Throwable t) { throw new RuntimeException(t); }
- }
- /**
- * Test proves that we do have 3 enum constants in the private static
- * inner class. */
- @Test
- public void testDefinedHelperEnumClass() {
- try {
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- assertThat(DefineClassHelper.class.getDeclaredClasses(), arrayWithSize(1));
- Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
- assertTrue(secPriv.isEnum());
- assertThat(secPriv.getEnumConstants(), arrayWithSize(3));
- assertThat(""+secPriv.getEnumConstants()[0], equalTo("JAVA_9"));
- assertThat(""+secPriv.getEnumConstants()[1], equalTo("JAVA_7"));
- assertThat(""+secPriv.getEnumConstants()[2], equalTo("JAVA_OTHER"));
-
- } catch (Throwable t) {t.printStackTrace();}
-
- }
- /**
- * Test proves that you cannot modify private static final reference even
- * with setAccessible(true). */
- @Test
- public void testDefinedHelperCannotSetPrivileged() {
- try {
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- DefineClassHelper inst = con.newInstance();
- Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
- Object J7 = secPriv.getEnumConstants()[1];
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- privi.setAccessible(true);
- thrown.expectCause(instanceOf(IllegalAccessException.class));
- thrown.expectMessage(startsWith("java.lang.IllegalAccessException: Can not set static final"));
- privi.set(inst, J7);
-
- } catch (Throwable t) {throw new RuntimeException(t);}
-
- }
- /**
- * Test proves that you can achieve the impossible and modify private
- * static final class reference without an instance. Now we can Mock
- * test JDK 6 to 8 functionality */
- @Test
- public void testDefinedHelperSetPrivilegedToJava7() {
- try {
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- DefineClassHelper inst = con.newInstance();
- Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
- Object J9 = secPriv.getEnumConstants()[0];
- Object J7 = secPriv.getEnumConstants()[1];
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- privi.setAccessible(true);
- Object privInst = privi.get(inst);
- Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
- unsf.setAccessible(true);
- Object refu = unsf.get(privInst);
- Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
- tuf.setAccessible(true);
- Object tu = tuf.get(refu);
- Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
- tu_call.setAccessible(true);
- long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
- tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J7}});
-
- Object p = privi.get(inst);
- assertThat(""+p, equalTo("JAVA_7"));
- assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$2"));
-
- tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
-
- } catch (Throwable t) {t.printStackTrace();}
-
- }
- /**
- * Test proves that Java 7+ MethodHandle defineClass (or DefineClassHelper.toClass)
- * works as expected. */
- @Test
- public void testDefinedHelperJava7ToClass() {
- try {
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- DefineClassHelper inst = con.newInstance();
- Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
- Object J9 = secPriv.getEnumConstants()[0];
- Object J7 = secPriv.getEnumConstants()[1];
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- privi.setAccessible(true);
- Object privInst = privi.get(inst);
- Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
- unsf.setAccessible(true);
- Object refu = unsf.get(privInst);
- Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
- tuf.setAccessible(true);
- Object tu = tuf.get(refu);
- Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
- tu_call.setAccessible(true);
- long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
- tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J7}});
-
- ClassPool cp = ClassPool.getDefault();
- CtClass c = cp.makeClass("a.b.J7");
- byte[] bc = c.toBytecode();
- Class<?> bcCls = DefineClassHelper.toClass("a.b.J7", new ClassLoader() {}, null, bc);
- assertThat(bcCls.getName(), equalTo("a.b.J7"));
- assertThat(bcCls.getDeclaredConstructor().newInstance(),
- not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
-
- tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
-
- } catch (Throwable t) {t.printStackTrace();}
-
- }
- /**
- * Test proves that Java 6 reflection method defineClass (or DefineClassHelper.toClass)
- * works as expected. */
- @Test
- public void testDefinedHelperJavaOtherToClass() {
- try {
- Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
- con.setAccessible(true);
- DefineClassHelper inst = con.newInstance();
- Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
- Object J9 = secPriv.getEnumConstants()[0];
- Object JO = secPriv.getEnumConstants()[2];
- Field privi = DefineClassHelper.class.getDeclaredField("privileged");
- privi.setAccessible(true);
- Object privInst = privi.get(inst);
- Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
- unsf.setAccessible(true);
- Object refu = unsf.get(privInst);
- Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
- tuf.setAccessible(true);
- Object tu = tuf.get(refu);
- Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
- tu_call.setAccessible(true);
- long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
- tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, JO}});
-
- ClassPool cp = ClassPool.getDefault();
- CtClass c = cp.makeClass("a.b.JO");
- byte[] bc = c.toBytecode();
- Class<?> bcCls = DefineClassHelper.toClass("a.b.JO", new ClassLoader() {}, null, bc);
- assertThat(bcCls.getName(), equalTo("a.b.JO"));
- assertThat(bcCls.getDeclaredConstructor().newInstance(),
- not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
-
- tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
-
- } catch (Throwable t) {t.printStackTrace();}
-
- }
- /**
- * Test proves that default Java 9 defineClass (or DefineClassHelper.toClass)
- * works as expected. */
- @Test
- public void testDefinedHelperDefaultToClass() {
- try {
- ClassPool cp = ClassPool.getDefault();
- CtClass c = cp.makeClass("a.b.D");
- byte[] bc = c.toBytecode();
- Class<?> bcCls = DefineClassHelper.toClass("a.b.D", new ClassLoader() {}, null, bc);
- assertThat(bcCls.getName(), equalTo("a.b.D"));
- assertThat(bcCls.getDeclaredConstructor().newInstance(),
- not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
- } catch (Throwable t) {t.printStackTrace();}
-
- }
-}
diff --git a/src/test/test/javassist/tools/DefineClassCapability.java b/src/test/test/javassist/tools/DefineClassCapability.java
new file mode 100644
index 00000000..fc3dc4e4
--- /dev/null
+++ b/src/test/test/javassist/tools/DefineClassCapability.java
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test.javassist.tools;
+
+public class DefineClassCapability {
+}
diff --git a/src/test/test1/DefineClassCapability.java b/src/test/test1/DefineClassCapability.java
new file mode 100644
index 00000000..fe386f06
--- /dev/null
+++ b/src/test/test1/DefineClassCapability.java
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test1;
+
+public class DefineClassCapability {
+}
diff --git a/src/test/test2/DefineClassCapability.java b/src/test/test2/DefineClassCapability.java
new file mode 100644
index 00000000..303ffcc7
--- /dev/null
+++ b/src/test/test2/DefineClassCapability.java
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test2;
+
+public class DefineClassCapability {
+}
diff --git a/src/test/test3/DefineClassCapability.java b/src/test/test3/DefineClassCapability.java
new file mode 100644
index 00000000..60b91835
--- /dev/null
+++ b/src/test/test3/DefineClassCapability.java
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test3;
+
+public class DefineClassCapability {
+}
diff --git a/src/test/test4/DefineClassCapability.java b/src/test/test4/DefineClassCapability.java
new file mode 100644
index 00000000..d0bef62e
--- /dev/null
+++ b/src/test/test4/DefineClassCapability.java
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test4;
+
+public class DefineClassCapability {
+}
diff --git a/src/test/test5/DefineClassCapability.java b/src/test/test5/DefineClassCapability.java
new file mode 100644
index 00000000..1bb573c8
--- /dev/null
+++ b/src/test/test5/DefineClassCapability.java
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test5;
+
+public class DefineClassCapability {
+}
diff --git a/src/test/test5/NestHost.java b/src/test/test5/NestHost.java
new file mode 100644
index 00000000..045d9d30
--- /dev/null
+++ b/src/test/test5/NestHost.java
@@ -0,0 +1,11 @@
+package test5;
+
+public class NestHost {
+ private int value;
+ public class Foo {
+ int foo() { return value++; }
+ }
+ public class Bar {
+ int bar() { return value++; }
+ }
+}
diff --git a/src/test/test5/NestHost2.java b/src/test/test5/NestHost2.java
new file mode 100644
index 00000000..571059be
--- /dev/null
+++ b/src/test/test5/NestHost2.java
@@ -0,0 +1,11 @@
+package test5;
+
+public class NestHost2 {
+ private int value;
+ public class Foo {
+ int foo() { return value++; }
+ }
+ public class Bar {
+ int bar() { return value++; }
+ }
+}