]> source.dussan.org Git - javassist.git/commitdiff
changes CtClass#toClass() and ClassPool#toClass() etc. to support Java 11,
authorchibash <chiba@javassist.org>
Sat, 8 Sep 2018 06:47:38 +0000 (15:47 +0900)
committerchibash <chiba@javassist.org>
Sat, 8 Sep 2018 06:47:38 +0000 (15:47 +0900)
in other words, java.lang.invoke.MethodHandles.Lookup.

27 files changed:
.gitignore
Readme.html
src/main/javassist/ClassPool.java
src/main/javassist/CtClass.java
src/main/javassist/Loader.java
src/main/javassist/util/proxy/DefineClassHelper.java
src/main/javassist/util/proxy/FactoryHelper.java
src/main/javassist/util/proxy/ProxyFactory.java
src/test/DefineClassCapability.java [new file with mode: 0644]
src/test/javassist/JvstTest.java
src/test/javassist/JvstTest2.java
src/test/javassist/JvstTest3.java
src/test/javassist/JvstTest4.java
src/test/javassist/JvstTest5.java
src/test/javassist/SetterTest.java
src/test/javassist/bytecode/InsertGap0.java
src/test/javassist/tools/CallbackTest.java
src/test/test/javassist/DefineClassCapability.java [new file with mode: 0644]
src/test/test/javassist/convert/ArrayAccessReplaceTest.java
src/test/test/javassist/proxy/ProxyCacheGCTest.java
src/test/test/javassist/proxy/TestSecuredPrivileged.java [deleted file]
src/test/test/javassist/tools/DefineClassCapability.java [new file with mode: 0644]
src/test/test1/DefineClassCapability.java [new file with mode: 0644]
src/test/test2/DefineClassCapability.java [new file with mode: 0644]
src/test/test3/DefineClassCapability.java [new file with mode: 0644]
src/test/test4/DefineClassCapability.java [new file with mode: 0644]
src/test/test5/DefineClassCapability.java [new file with mode: 0644]

index 73e3f77ecf2408f18c7317f9f69dbae5ed3df8c1..1f83f06e3a83f9b19342b0905f93eeb3b43ca23d 100644 (file)
@@ -12,4 +12,4 @@ tmp/
 .project
 .settings
 TestLog.xml
-
+*~
index b1ff16ff4b70e023da23b7595d12f71ddfc74b82..1fc89e241366b1ce1a5edd5fc0943d325c948013 100644 (file)
@@ -283,6 +283,7 @@ see javassist.Dump.
 
 <p>-version 3.24
 <ul>
+       <li>Java 11 supports.</li>
     <li>JIRA JASSIST-267.</li>
     <li>Github PR #218.</li>
 </ul>
index 600559923bf2ffebf3ec225153d5944601d90a6f..100afbe58460fc11717109fe49b0ad751e9e22a6 100644 (file)
@@ -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 #toCalss(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)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);
index 4f8eb2695830b08bfe08c23c91a8f420b6f1e651..333a17d46bb999cbcc4d9148c44014ca55715c50 100644 (file)
@@ -1271,13 +1271,65 @@ public abstract class CtClass {
      * work with a security manager or a signed jar file because a
      * protection domain is not specified.
      *
-     * @see #toClass(java.lang.ClassLoader,ProtectionDomain)
+     * @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.  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
+     * 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)
+     * @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
+     * work with a security manager or a signed jar file because a
+     * protection domain is not specified.
+     *
+     * @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(java.lang.invoke.MethodHandles.Lookup lookup)
+        throws CannotCompileException
+    {
+        return getClassPool().toClass(this, lookup);
+    }
+
     /**
      * Converts this class to a <code>java.lang.Class</code> object.
      * Once this method is called, further modifications are not allowed
@@ -1316,7 +1368,7 @@ public abstract class CtClass {
         if (loader == null)
             loader = cp.getClassLoader();
 
-        return cp.toClass(this, loader, domain);
+        return cp.toClass(this, null, loader, domain);
     }
 
     /**
@@ -1332,7 +1384,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 +1457,7 @@ public abstract class CtClass {
      * @see ClassPool#doPruning
      *
      * @see #toBytecode()
-     * @see #toClass()
+     * @see #toClass(Class)
      * @see #writeFile()
      * @see #instrument(CodeConverter)
      * @see #instrument(ExprEditor)
index 8eb067c4cb192f5b23115ec17fad41f13b77d281..37f83d686f3665cc795067408f95e668aa95ea5a 100644 (file)
 
 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;
index bc6866ceb766b880bb739526956c581dd99ef973..dea536704a8dc979239a7068c958cbea034d9d68 100644 (file)
@@ -34,9 +34,24 @@ import javassist.bytecode.ClassFile;
 public class DefineClassHelper {
 
     private static abstract class Helper {
-        abstract Class<?> defineClass(String name, byte[] b, int off, int len,
+        abstract Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
                                       ClassLoader loader, ProtectionDomain protectionDomain)
-            throws ClassFormatError;
+            throws ClassFormatError, CannotCompileException;
+    }
+
+    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 static class Java9 extends Helper {
@@ -119,7 +134,7 @@ public class DefineClassHelper {
         }
 
         @Override
-        Class<?> defineClass(String name, byte[] b, int off, int len,
+        Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
                                     ClassLoader loader, ProtectionDomain protectionDomain)
             throws ClassFormatError
         {
@@ -152,7 +167,7 @@ public class DefineClassHelper {
         }
 
         @Override
-        Class<?> defineClass(String name, byte[] b, int off, int len,
+        Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
                 ClassLoader loader, ProtectionDomain protectionDomain)
             throws ClassFormatError
         {
@@ -187,11 +202,12 @@ public class DefineClassHelper {
         }
 
         @Override
-        Class<?> defineClass(String name, byte[] b, int off, int len,
+        Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
                              ClassLoader loader, ProtectionDomain protectionDomain)
-            throws ClassFormatError
+            throws ClassFormatError, CannotCompileException
         {
-            if (stack.getCallerClass() != DefineClassHelper.class)
+            Class<?> klass = stack.getCallerClass();
+            if (klass != DefineClassHelper.class && klass != this.getClass())
                 throw new IllegalAccessError("Access denied for caller.");
             try {
                 SecurityActions.setAccessible(defineClass, true);
@@ -201,7 +217,7 @@ public class DefineClassHelper {
             } catch (Throwable e) {
                 if (e instanceof ClassFormatError) throw (ClassFormatError) e;
                 if (e instanceof RuntimeException) throw (RuntimeException) e;
-                throw new ClassFormatError(e.getMessage());
+                throw new CannotCompileException(e);
             }
             finally {
                 SecurityActions.setAccessible(defineClass, false);
@@ -212,7 +228,7 @@ public class DefineClassHelper {
     // 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 Helper privileged = ClassFile.MAJOR_VERSION > ClassFile.JAVA_10
-            ? new JavaOther()
+            ? new Java11()
             : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
                 ? new Java9()
                 : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7 ? new Java7() : new JavaOther();
@@ -220,7 +236,9 @@ public class DefineClassHelper {
     /**
      * 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
@@ -229,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.
+     * @parma 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);
@@ -251,6 +278,47 @@ 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 {
+            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}.
      *
index 1fb63b65543d668a755b09f2118c242cf2f8d8f4..38fcbf42e3305775e0ece520e141701d294064d9 100644 (file)
@@ -104,28 +104,37 @@ 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);
index d3fcddbdddc9a1473a464fdf6966ed6c8c237a58..07b0e16136b6f62ac6931e351074fbd7eea9f256 100644 (file)
@@ -213,7 +213,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;
@@ -549,7 +549,7 @@ public class ProxyFactory {
             if (writeDirectory != null)
                 FactoryHelper.writeFile(cf, writeDirectory);
 
-            thisClass = FactoryHelper.toClass(cf, cl, getDomain());
+            thisClass = FactoryHelper.toClass(cf, getClassInTheSamePackage(), cl, getDomain());
             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 +562,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 {
diff --git a/src/test/DefineClassCapability.java b/src/test/DefineClassCapability.java
new file mode 100644 (file)
index 0000000..c6dec20
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+public class DefineClassCapability {
+}
index e2f9211fb5ff9e39f96db3e68114260d096d52a0..aab0b9075b5e658150a19154c63e532491f21dd1 100644 (file)
@@ -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);
index 117560c0900da3c8f4448ac00e8875d94fa63187..0ea4571bc94121d37201efa4c51ab1c9026bd2d6 100644 (file)
@@ -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());
     }
 
index 47131a93e9771dc879f37f520e21770722b46d75..46f06b168c2ce4be58e90402794c6c8b55e1100f 100644 (file)
@@ -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
index 187abb3deb819c61fe191287e918df253d573dab..7c8c7457639b2d722019e263d78feeff46a71e24 100644 (file)
@@ -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());
     }
index ec8ff66a02673aa7d34b11c9d1ae072f7e16b3e4..c5eff4d1ba76fecac2a9f3d6c5bc7727afa4f301 100644 (file)
@@ -223,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
     }
 
@@ -451,6 +451,6 @@ public class JvstTest5 extends JvstTestRoot {
     public void testNestHostAttributeCopy() throws Exception {
         CtClass cc = sloader.get("test5.NestHost2$Foo");
         cc.getClassFile().compact();
-        cc.toClass();
+        cc.toClass(test5.DefineClassCapability.class);
     }
 }
index 44eec140171f67a55e31a6501382285ff96ff064..a76b2a309841926c4b67f454bb94a7b98b9c79d9 100644 (file)
-package javassist;\r
-import java.lang.reflect.Method;\r
-\r
-import junit.framework.TestCase;\r
-\r
-@SuppressWarnings({"rawtypes","unchecked"})\r
-public class SetterTest extends TestCase {\r
-\r
-    ClassPool pool;\r
-\r
-    public SetterTest(String name) {\r
-         super(name);\r
-    }\r
-\r
-    protected void setUp() throws Exception {\r
-        super.setUp();\r
-        pool = ClassPool.getDefault();\r
-    }\r
-\r
-    /**\r
-     * Tests a getter only on a field without a Modifier.\r
-     * \r
-     * @throws Exception\r
-     */\r
-    public void testFieldGetter() throws Exception {\r
-        CtClass clazz = pool.makeClass("HasFieldGetter");\r
-        clazz.setSuperclass(pool.get("java.lang.Object"));\r
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);\r
-        clazz.addField(field, "true");\r
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));\r
-        Class _class = clazz.toClass();\r
-\r
-        Object object = _class.getConstructor().newInstance();\r
-        check(_class, object, true);\r
-    }\r
-\r
-    /**\r
-     * Tests a getter and a setter on a field without a Modifier.\r
-     * \r
-     * @throws Exception\r
-     */\r
-    public void testFieldGetterSetter() throws Exception {\r
-        CtClass clazz = pool.makeClass("HasFieldGetterSetter");\r
-        clazz.setSuperclass(pool.get("java.lang.Object"));\r
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);\r
-        clazz.addField(field, "true");\r
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));\r
-        clazz.addMethod(CtNewMethod.setter("setBroken", field));\r
-        Class _class = clazz.toClass();\r
-\r
-        Object object = _class.getConstructor().newInstance();\r
-\r
-        set(_class, object, false);\r
-        check(_class, object, false);\r
-    }\r
-\r
-    /**\r
-     * Tests a getter only on a field with Modifier.STATIC.\r
-     * \r
-     * @throws Exception\r
-     */\r
-    public void testStaticFieldGetter() throws Exception {\r
-        CtClass clazz = pool.makeClass("HasStaticFieldGetter");\r
-        clazz.setSuperclass(pool.get("java.lang.Object"));\r
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);\r
-        field.setModifiers(Modifier.STATIC);\r
-        clazz.addField(field, "true");\r
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));\r
-        Class _class = clazz.toClass();\r
-\r
-        Object object = _class.getConstructor().newInstance();\r
-        check(_class, object, true);\r
-    }\r
-\r
-    /**\r
-     * Tests a getter and setter on a field with Modifier.STATIC.\r
-     * \r
-     * @throws Exception\r
-     */\r
-    public void testStaticFieldGetterSetter() throws Exception {\r
-        CtClass clazz = pool.makeClass("HasStaticFieldGetterSetter");\r
-        clazz.setSuperclass(pool.get("java.lang.Object"));\r
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);\r
-        field.setModifiers(Modifier.STATIC);\r
-        clazz.addField(field, "true");\r
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));\r
-        clazz.addMethod(CtNewMethod.setter("setBroken", field));\r
-        Class _class = clazz.toClass();\r
-\r
-        Object object = _class.getConstructor().newInstance();\r
-\r
-        set(_class, object, false);\r
-        check(_class, object, false);\r
-    }\r
-\r
-    private void check(Class _class, Object object, boolean shouldBe)\r
-        throws Exception\r
-    {\r
-        Method method = _class.getMethod("isBroken", new Class[] {});\r
-        Boolean result = (Boolean) method.invoke(object, new Object[] {});\r
-        assertEquals("boolean is wrong value",\r
-                     shouldBe, result.booleanValue());\r
-    }\r
-\r
-    private void set(Class _class, Object object, boolean willBe)\r
-        throws Exception\r
-    {\r
-        Method method = _class.getMethod("setBroken",\r
-                                         new Class[] {Boolean.TYPE});\r
-        method.invoke(object, new Object[] { Boolean.valueOf(willBe)});\r
-    }\r
-}\r
+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)});
+    }
+}
index 824b930541f0caf6e39b3bf9f0cd9859652ca29f..425f12d7d5e9be7f7b8da001ce9603b039bd1a5f 100644 (file)
@@ -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();
index 96632bda902398c5d024bd2d8346bd41741ba742..f5861cebb06fcdd32c20e52cc1f4f9f9368ef144 100644 (file)
@@ -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 (file)
index 0000000..e6a0fd5
--- /dev/null
@@ -0,0 +1,7 @@
+package test.javassist;
+
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+public class DefineClassCapability {
+}
index d81f220d05b6912e484df001aa58562bd08d88e9..cebd1853cd918a3018aafd181843736022130dbb 100644 (file)
@@ -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));
     }
 
index 97b7281d9f152d5f55c66017c5e3556efa336421..e47c43834318ae03ccc8eacc8e306ee838c6b978 100644 (file)
@@ -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/TestSecuredPrivileged.java b/src/test/test/javassist/proxy/TestSecuredPrivileged.java
deleted file mode 100644 (file)
index c51555f..0000000
+++ /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 (file)
index 0000000..fc3dc4e
--- /dev/null
@@ -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 (file)
index 0000000..fe386f0
--- /dev/null
@@ -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 (file)
index 0000000..303ffcc
--- /dev/null
@@ -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 (file)
index 0000000..60b9183
--- /dev/null
@@ -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 (file)
index 0000000..d0bef62
--- /dev/null
@@ -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 (file)
index 0000000..1bb573c
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * This is used as a capability for running CtClass#toClass().
+ */
+package test5;
+
+public class DefineClassCapability {
+}