Browse Source

changes CtClass#toClass() and ClassPool#toClass() etc. to support Java 11,

in other words, java.lang.invoke.MethodHandles.Lookup.
tags/rel_3_24_0_rc
chibash 10 months ago
parent
commit
6320bc4e14

+ 1
- 1
.gitignore View File

@@ -12,4 +12,4 @@ tmp/
12 12
 .project
13 13
 .settings
14 14
 TestLog.xml
15
-
15
+*~

+ 1
- 0
Readme.html View File

@@ -283,6 +283,7 @@ see javassist.Dump.
283 283
 
284 284
 <p>-version 3.24
285 285
 <ul>
286
+	<li>Java 11 supports.</li>
286 287
     <li>JIRA JASSIST-267.</li>
287 288
     <li>Github PR #218.</li>
288 289
 </ul>

+ 123
- 11
src/main/javassist/ClassPool.java View File

@@ -1023,16 +1023,23 @@ public class ClassPool {
1023 1023
      * the <code>getClassLoader()</code> method.
1024 1024
      * If the program is running on some application
1025 1025
      * server, the context class loader might be inappropriate to load the
1026
-     * class.
1026
+     * class.</p>
1027 1027
      *
1028 1028
      * <p>This method is provided for convenience.  If you need more
1029 1029
      * complex functionality, you should write your own class loader.
1030 1030
      *
1031
-     * <p><b>Warining:</b> A Class object returned by this method may not
1031
+     * <p><b>Warining:</b>
1032
+     * This method should not be used in Java 11 or later.
1033
+     * Use {@link #toClass(CtClass,Class)}.
1034
+     * </p>
1035
+     *
1036
+     * <p><b>Warining:</b>
1037
+     * A Class object returned by this method may not
1032 1038
      * work with a security manager or a signed jar file because a
1033
-     * protection domain is not specified.
1039
+     * protection domain is not specified.</p>
1034 1040
      *
1035
-     * @see #toClass(CtClass, java.lang.ClassLoader, ProtectionDomain)
1041
+     * @see #toCalss(CtClass,Class)
1042
+     * @see #toClass(CtClass,Class,java.lang.ClassLoader,ProtectionDomain)
1036 1043
      * @see #getClassLoader()
1037 1044
      */
1038 1045
     public Class toClass(CtClass clazz) throws CannotCompileException {
@@ -1066,21 +1073,21 @@ public class ClassPool {
1066 1073
     /**
1067 1074
      * Converts the class to a <code>java.lang.Class</code> object.
1068 1075
      * Do not override this method any more at a subclass because
1069
-     * <code>toClass(CtClass)</code> never calls this method.
1076
+     * {@link #toClass(CtClass)} will never calls this method.
1070 1077
      *
1071 1078
      * <p><b>Warining:</b> A Class object returned by this method may not
1072 1079
      * work with a security manager or a signed jar file because a
1073 1080
      * protection domain is not specified.
1074 1081
      *
1075
-     * @deprecated      Replaced by {@link #toClass(CtClass,ClassLoader,ProtectionDomain)}.
1082
+     * @deprecated      Replaced by {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}.
1076 1083
      * A subclass of <code>ClassPool</code> that has been
1077 1084
      * overriding this method should be modified.  It should override
1078
-     * {@link #toClass(CtClass,ClassLoader,ProtectionDomain)}.
1085
+     * {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}.
1079 1086
      */
1080 1087
     public Class toClass(CtClass ct, ClassLoader loader)
1081 1088
         throws CannotCompileException
1082 1089
     {
1083
-        return toClass(ct, loader, null);
1090
+        return toClass(ct, null, loader, null);
1084 1091
     }
1085 1092
 
1086 1093
     /**
@@ -1092,7 +1099,7 @@ public class ClassPool {
1092 1099
      * loaded by the given class loader to construct a
1093 1100
      * <code>java.lang.Class</code> object.  Since a private method
1094 1101
      * on the class loader is invoked through the reflection API,
1095
-     * the caller must have permissions to do that.
1102
+     * the caller must have permissions to do that.</p>
1096 1103
      *
1097 1104
      * <p>An easy way to obtain <code>ProtectionDomain</code> object is
1098 1105
      * to call <code>getProtectionDomain()</code>
@@ -1100,8 +1107,9 @@ public class ClassPool {
1100 1107
      * class belongs to.
1101 1108
      *
1102 1109
      * <p>This method is provided for convenience.  If you need more
1103
-     * complex functionality, you should write your own class loader.
1110
+     * complex functionality, you should write your own class loader.</p>
1104 1111
      *
1112
+     * @param ct            the class converted into {@code java.lang.Class}.
1105 1113
      * @param loader        the class loader used to load this class.
1106 1114
      *                      For example, the loader returned by
1107 1115
      *                      <code>getClassLoader()</code> can be used
@@ -1112,13 +1120,117 @@ public class ClassPool {
1112 1120
      *
1113 1121
      * @see #getClassLoader()
1114 1122
      * @since 3.3
1123
+     * @deprecated      Replaced by {@link #toClass(CtClass,Class,ClassLoader,ProtectionDomain)}.
1115 1124
      */
1116 1125
     public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain)
1117 1126
         throws CannotCompileException
1118 1127
     {
1128
+        return toClass(ct, null, loader, domain);
1129
+    }
1130
+
1131
+    /**
1132
+     * Converts the class to a <code>java.lang.Class</code> object.
1133
+     * Once this method is called, further modifications are not allowed
1134
+     * any more.
1135
+     *
1136
+     * <p>This method is available in Java 9 or later.
1137
+     * It loads the class
1138
+     * by using {@code java.lang.invoke.MethodHandles} with {@code neighbor}.
1139
+     * </p>
1140
+     *
1141
+     * @param ct            the class converted into {@code java.lang.Class}.
1142
+     * @param neighbor      a class belonging to the same package that
1143
+     *                      the converted class belongs to.
1144
+     * @since 3.24
1145
+     */
1146
+    public Class<?> toClass(CtClass ct, Class<?> neighbor)
1147
+        throws CannotCompileException
1148
+    {
1149
+        try {
1150
+            return javassist.util.proxy.DefineClassHelper.toClass(neighbor,
1151
+                                                            ct.toBytecode());
1152
+        }
1153
+        catch (IOException e) {
1154
+            throw new CannotCompileException(e);
1155
+        }
1156
+    }
1157
+
1158
+    /**
1159
+     * Converts the class to a <code>java.lang.Class</code> object.
1160
+     * Once this method is called, further modifications are not allowed
1161
+     * any more.
1162
+     *
1163
+     * <p>This method is available in Java 9 or later.
1164
+     * It loads the class
1165
+     * by using the given {@code java.lang.invoke.MethodHandles.Lookup}.
1166
+     * </p>
1167
+     *
1168
+     * @param ct            the class converted into {@code java.lang.Class}.
1169
+     * @since 3.24
1170
+     */
1171
+    public Class<?> toClass(CtClass ct,
1172
+                            java.lang.invoke.MethodHandles.Lookup lookup)
1173
+        throws CannotCompileException
1174
+    {
1175
+        try {
1176
+            return javassist.util.proxy.DefineClassHelper.toClass(lookup,
1177
+                                                            ct.toBytecode());
1178
+        }
1179
+        catch (IOException e) {
1180
+            throw new CannotCompileException(e);
1181
+        }
1182
+    }
1183
+
1184
+    /**
1185
+     * Converts the class to a <code>java.lang.Class</code> object.
1186
+     * Once this method is called, further modifications are not allowed
1187
+     * any more.
1188
+     *
1189
+     * <p>When the JVM is Java 11 or later, this method loads the class
1190
+     * by using {@code java.lang.invoke.MethodHandles} with {@code neighbor}.
1191
+     * The other arguments {@code loader} and {@code domain} are not used;
1192
+     * so they can be null.
1193
+     * </p>
1194
+     *
1195
+     * <p>Otherwise, or when {@code neighbor} is null,
1196
+     * the class file represented by the given <code>CtClass</code> is
1197
+     * loaded by the given class loader to construct a
1198
+     * <code>java.lang.Class</code> object.  Since a private method
1199
+     * on the class loader is invoked through the reflection API,
1200
+     * the caller must have permissions to do that.
1201
+     *
1202
+     * <p>An easy way to obtain <code>ProtectionDomain</code> object is
1203
+     * to call <code>getProtectionDomain()</code>
1204
+     * in <code>java.lang.Class</code>.  It returns the domain that the
1205
+     * class belongs to.
1206
+     *
1207
+     * <p>If your program is for only Java 9 or later, don't use this method.
1208
+     * Use {@link #toClass(CtClass,Class)} or
1209
+     * {@link #toClass(CtClass)CtClass,java.lang.invoke.MethodHandles.Lookup)}.
1210
+     * </p>
1211
+     *
1212
+     * @param ct            the class converted into {@code java.lang.Class}.
1213
+     * @param neighbor      a class belonging to the same package that
1214
+     *                      the converted class belongs to.
1215
+     *                      It can be null.
1216
+     * @param loader        the class loader used to load this class.
1217
+     *                      For example, the loader returned by
1218
+     *                      <code>getClassLoader()</code> can be used
1219
+     *                      for this parameter.
1220
+     * @param domain        the protection domain for the class.
1221
+     *                      If it is null, the default domain created
1222
+     *                      by <code>java.lang.ClassLoader</code> is used.
1223
+     *
1224
+     * @see #getClassLoader()
1225
+     * @since 3.24
1226
+     */
1227
+    public Class toClass(CtClass ct, Class<?> neighbor, ClassLoader loader,
1228
+                         ProtectionDomain domain)
1229
+            throws CannotCompileException
1230
+    {
1119 1231
         try {
1120 1232
             return javassist.util.proxy.DefineClassHelper.toClass(ct.getName(),
1121
-                    loader, domain, ct.toBytecode());
1233
+                    neighbor, loader, domain, ct.toBytecode());
1122 1234
         }
1123 1235
         catch (IOException e) {
1124 1236
             throw new CannotCompileException(e);

+ 56
- 4
src/main/javassist/CtClass.java View File

@@ -1271,7 +1271,8 @@ public abstract class CtClass {
1271 1271
      * work with a security manager or a signed jar file because a
1272 1272
      * protection domain is not specified.
1273 1273
      *
1274
-     * @see #toClass(java.lang.ClassLoader,ProtectionDomain)
1274
+     * @see #toClass(java.lang.invoke.MethodHandles.Lookup)
1275
+     * @see #toClass(Class)
1275 1276
      * @see ClassPool#toClass(CtClass)
1276 1277
      */
1277 1278
     public Class<?> toClass() throws CannotCompileException {
@@ -1280,6 +1281,57 @@ public abstract class CtClass {
1280 1281
 
1281 1282
     /**
1282 1283
      * Converts this class to a <code>java.lang.Class</code> object.
1284
+     * Once this method is called, further modifications are not
1285
+     * allowed any more.
1286
+     *
1287
+     * <p>This method is provided for convenience.  If you need more
1288
+     * complex functionality, you should write your own class loader.
1289
+     *
1290
+     * <p>Note: this method calls <code>toClass()</code>
1291
+     * in <code>ClassPool</code>.
1292
+     *
1293
+     * <p><b>Warining:</b> A Class object returned by this method may not
1294
+     * work with a security manager or a signed jar file because a
1295
+     * protection domain is not specified.
1296
+     *
1297
+     * @param neighbor    A class belonging to the same package that this
1298
+     *                    class belongs to.  It is used to load the class.
1299
+     * @see ClassPool#toClass(CtClass,Class)
1300
+     * @since 3.24
1301
+     */
1302
+    public Class<?> toClass(Class<?> neighbor) throws CannotCompileException
1303
+    {
1304
+        return getClassPool().toClass(this, neighbor);
1305
+    }
1306
+
1307
+    /**
1308
+     * Converts this class to a <code>java.lang.Class</code> object.
1309
+     * Once this method is called, further modifications are not
1310
+     * allowed any more.
1311
+     *
1312
+     * <p>This method is provided for convenience.  If you need more
1313
+     * complex functionality, you should write your own class loader.
1314
+     *
1315
+     * <p>Note: this method calls <code>toClass()</code>
1316
+     * in <code>ClassPool</code>.
1317
+     *
1318
+     * <p><b>Warining:</b> A Class object returned by this method may not
1319
+     * work with a security manager or a signed jar file because a
1320
+     * protection domain is not specified.
1321
+     *
1322
+     * @param lookup    used when loading the class.  It has to have
1323
+     *                  an access right to define a new class.
1324
+     * @see ClassPool#toClass(CtClass,java.lang.invoke.MethodHandles.Lookup)
1325
+     * @since 3.24
1326
+     */
1327
+    public Class<?> toClass(java.lang.invoke.MethodHandles.Lookup lookup)
1328
+        throws CannotCompileException
1329
+    {
1330
+        return getClassPool().toClass(this, lookup);
1331
+    }
1332
+
1333
+    /**
1334
+     * Converts this class to a <code>java.lang.Class</code> object.
1283 1335
      * Once this method is called, further modifications are not allowed
1284 1336
      * any more.
1285 1337
      *
@@ -1316,7 +1368,7 @@ public abstract class CtClass {
1316 1368
         if (loader == null)
1317 1369
             loader = cp.getClassLoader();
1318 1370
 
1319
-        return cp.toClass(this, loader, domain);
1371
+        return cp.toClass(this, null, loader, domain);
1320 1372
     }
1321 1373
 
1322 1374
     /**
@@ -1332,7 +1384,7 @@ public abstract class CtClass {
1332 1384
     public final Class<?> toClass(ClassLoader loader)
1333 1385
         throws CannotCompileException
1334 1386
     {
1335
-        return getClassPool().toClass(this, loader);
1387
+        return getClassPool().toClass(this, null, loader, null);
1336 1388
     }
1337 1389
 
1338 1390
     /**
@@ -1405,7 +1457,7 @@ public abstract class CtClass {
1405 1457
      * @see ClassPool#doPruning
1406 1458
      *
1407 1459
      * @see #toBytecode()
1408
-     * @see #toClass()
1460
+     * @see #toClass(Class)
1409 1461
      * @see #writeFile()
1410 1462
      * @see #instrument(CodeConverter)
1411 1463
      * @see #instrument(ExprEditor)

+ 45
- 3
src/main/javassist/Loader.java View File

@@ -16,11 +16,12 @@
16 16
 
17 17
 package javassist;
18 18
 
19
+import java.io.IOException;
19 20
 import java.io.InputStream;
20 21
 import java.lang.reflect.InvocationTargetException;
21 22
 import java.security.ProtectionDomain;
22 23
 import java.util.Arrays;
23
-import java.util.Hashtable;
24
+import java.util.HashMap;
24 25
 import java.util.Vector;
25 26
 
26 27
 import javassist.bytecode.ClassFile;
@@ -138,7 +139,48 @@ import javassist.bytecode.ClassFile;
138 139
  * @see javassist.Translator
139 140
  */
140 141
 public class Loader extends ClassLoader {
141
-    private Hashtable<String,ClassLoader> notDefinedHere; // must be atomic.
142
+
143
+    /**
144
+     * A simpler class loader.
145
+     * This is a class loader that exposes the protected {@code defineClass()} method
146
+     * declared in {@code java.lang.ClassLoader}.  It provides a method similar to
147
+     * {@code CtClass#toClass()}.
148
+     *
149
+     * <p>When loading a class, this class loader delegates the work to the
150
+     * parent class loader unless the loaded classes are explicitly given
151
+     * by {@link #invokeDefineClass(CtClass)}.
152
+     * Note that a class {@code Foo} loaded by this class loader is
153
+     * different from the class with the same name {@code Foo} but loaded by
154
+     * another class loader.  This is Java's naming rule.
155
+     * </p>
156
+     *
157
+     * @since 3.24
158
+     */
159
+    public static class Simple extends ClassLoader {
160
+        /**
161
+         * Constructs a class loader.
162
+         */
163
+        public Simple() {}
164
+
165
+        /**
166
+         * Constructs a class loader.
167
+         * @param parent    the parent class loader.
168
+         */
169
+        public Simple(ClassLoader parent) {
170
+            super(parent);
171
+        }
172
+
173
+        /**
174
+         * Invokes the protected {@code defineClass()} in {@code ClassLoader}.
175
+         * It converts the given {@link CtClass} object into a {@code java.lang.Class} object.
176
+         */
177
+        public Class<?> invokeDefineClass(CtClass cc) throws IOException, CannotCompileException {
178
+            byte[] code = cc.toBytecode();
179
+            return defineClass(cc.getName(), code, 0, code.length);
180
+        }
181
+    }
182
+
183
+    private HashMap<String,ClassLoader> notDefinedHere; // must be atomic.
142 184
     private Vector<String> notDefinedPackages; // must be atomic.
143 185
     private ClassPool source;
144 186
     private Translator translator;
@@ -186,7 +228,7 @@ public class Loader extends ClassLoader {
186 228
     }
187 229
 
188 230
     private void init(ClassPool cp) {
189
-        notDefinedHere = new Hashtable<String,ClassLoader>();
231
+        notDefinedHere = new HashMap<String,ClassLoader>();
190 232
         notDefinedPackages = new Vector<String>();
191 233
         source = cp;
192 234
         translator = null;

+ 80
- 12
src/main/javassist/util/proxy/DefineClassHelper.java View File

@@ -34,9 +34,24 @@ import javassist.bytecode.ClassFile;
34 34
 public class DefineClassHelper {
35 35
 
36 36
     private static abstract class Helper {
37
-        abstract Class<?> defineClass(String name, byte[] b, int off, int len,
37
+        abstract Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
38 38
                                       ClassLoader loader, ProtectionDomain protectionDomain)
39
-            throws ClassFormatError;
39
+            throws ClassFormatError, CannotCompileException;
40
+    }
41
+
42
+    private static class Java11 extends JavaOther {
43
+        Class<?> defineClass(String name, byte[] bcode, int off, int len, Class<?> neighbor,
44
+                             ClassLoader loader, ProtectionDomain protectionDomain)
45
+            throws ClassFormatError, CannotCompileException
46
+        {
47
+            if (neighbor != null)
48
+                return toClass(neighbor, bcode);
49
+            else {
50
+                // Lookup#defineClass() is not available.  So fallback to invoking defineClass on
51
+                // ClassLoader, which causes a warning message.
52
+                return super.defineClass(name, bcode, off, len, neighbor, loader, protectionDomain);
53
+            }
54
+        }
40 55
     }
41 56
 
42 57
     private static class Java9 extends Helper {
@@ -119,7 +134,7 @@ public class DefineClassHelper {
119 134
         }
120 135
 
121 136
         @Override
122
-        Class<?> defineClass(String name, byte[] b, int off, int len,
137
+        Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
123 138
                                     ClassLoader loader, ProtectionDomain protectionDomain)
124 139
             throws ClassFormatError
125 140
         {
@@ -152,7 +167,7 @@ public class DefineClassHelper {
152 167
         }
153 168
 
154 169
         @Override
155
-        Class<?> defineClass(String name, byte[] b, int off, int len,
170
+        Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
156 171
                 ClassLoader loader, ProtectionDomain protectionDomain)
157 172
             throws ClassFormatError
158 173
         {
@@ -187,11 +202,12 @@ public class DefineClassHelper {
187 202
         }
188 203
 
189 204
         @Override
190
-        Class<?> defineClass(String name, byte[] b, int off, int len,
205
+        Class<?> defineClass(String name, byte[] b, int off, int len, Class<?> neighbor,
191 206
                              ClassLoader loader, ProtectionDomain protectionDomain)
192
-            throws ClassFormatError
207
+            throws ClassFormatError, CannotCompileException
193 208
         {
194
-            if (stack.getCallerClass() != DefineClassHelper.class)
209
+            Class<?> klass = stack.getCallerClass();
210
+            if (klass != DefineClassHelper.class && klass != this.getClass())
195 211
                 throw new IllegalAccessError("Access denied for caller.");
196 212
             try {
197 213
                 SecurityActions.setAccessible(defineClass, true);
@@ -201,7 +217,7 @@ public class DefineClassHelper {
201 217
             } catch (Throwable e) {
202 218
                 if (e instanceof ClassFormatError) throw (ClassFormatError) e;
203 219
                 if (e instanceof RuntimeException) throw (RuntimeException) e;
204
-                throw new ClassFormatError(e.getMessage());
220
+                throw new CannotCompileException(e);
205 221
             }
206 222
             finally {
207 223
                 SecurityActions.setAccessible(defineClass, false);
@@ -212,7 +228,7 @@ public class DefineClassHelper {
212 228
     // Java 11+ removed sun.misc.Unsafe.defineClass, so we fallback to invoking defineClass on
213 229
     // ClassLoader until we have an implementation that uses MethodHandles.Lookup.defineClass
214 230
     private static final Helper privileged = ClassFile.MAJOR_VERSION > ClassFile.JAVA_10
215
-            ? new JavaOther()
231
+            ? new Java11()
216 232
             : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
217 233
                 ? new Java9()
218 234
                 : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7 ? new Java7() : new JavaOther();
@@ -220,7 +236,9 @@ public class DefineClassHelper {
220 236
     /**
221 237
      * Loads a class file by a given class loader.
222 238
      *
223
-     * <p>This first tries to use {@code sun.misc.Unsafe} to load a class.
239
+     * <p>This first tries to use {@code java.lang.invoke.MethodHandle} to load a class.
240
+     * Otherwise, or if {@code neighbor} is null,
241
+     * this tries to use {@code sun.misc.Unsafe} to load a class.
224 242
      * Then it tries to use a {@code protected} method in {@code java.lang.ClassLoader}
225 243
      * via {@code PrivilegedAction}.  Since the latter approach is not available
226 244
      * any longer by default in Java 9 or later, the JVM argument
@@ -229,19 +247,28 @@ public class DefineClassHelper {
229 247
      * should be used instead.
230 248
      * </p>
231 249
      *
250
+     * @param className     the name of the loaded class.
251
+     * @param neighbor      the class contained in the same package as the loaded class.
252
+     * @param loader        the class loader.  It can be null if {@code neighbor} is not null
253
+     *                      and the JVM is Java 11 or later.
232 254
      * @param domain        if it is null, a default domain is used.
255
+     * @parma bcode         the bytecode for the loaded class.
233 256
      * @since 3.22
234 257
      */
235
-    public static Class<?> toClass(String className, ClassLoader loader,
258
+    public static Class<?> toClass(String className, Class<?> neighbor, ClassLoader loader,
236 259
                                    ProtectionDomain domain, byte[] bcode)
237 260
         throws CannotCompileException
238 261
     {
239 262
         try {
240
-            return privileged.defineClass(className, bcode, 0, bcode.length, loader, domain);
263
+            return privileged.defineClass(className, bcode, 0, bcode.length,
264
+                                          neighbor, loader, domain);
241 265
         }
242 266
         catch (RuntimeException e) {
243 267
             throw e;
244 268
         }
269
+        catch (CannotCompileException e) {
270
+            throw e;
271
+        }
245 272
         catch (ClassFormatError e) {
246 273
             Throwable t = e.getCause();
247 274
             throw new CannotCompileException(t == null ? e : t);
@@ -251,6 +278,47 @@ public class DefineClassHelper {
251 278
         }
252 279
     }
253 280
 
281
+
282
+    /**
283
+     * Loads a class file by {@code java.lang.invoke.MethodHandles.Lookup}.
284
+     * It is obtained by using {@code neighbor}.
285
+     *
286
+     * @param neighbor  a class belonging to the same package that the loaded
287
+     *                  class belogns to.
288
+     * @param bcode     the bytecode.
289
+     * @since 3.24
290
+     */
291
+    public static Class<?> toClass(Class<?> neighbor, byte[] bcode)
292
+        throws CannotCompileException
293
+    {
294
+        try {
295
+            Lookup lookup = MethodHandles.lookup();
296
+            Lookup prvlookup = MethodHandles.privateLookupIn(neighbor, lookup);
297
+            return prvlookup.defineClass(bcode);
298
+        } catch (IllegalAccessException | IllegalArgumentException e) {
299
+            throw new CannotCompileException(e.getMessage() + ": " + neighbor.getName()
300
+                                             + " has no permission to define the class");
301
+        }
302
+    }
303
+
304
+    /**
305
+     * Loads a class file by {@code java.lang.invoke.MethodHandles.Lookup}.
306
+     * It can be obtained by {@code MethodHandles.lookup()} called from
307
+     * somewhere in the package that the loaded class belongs to.
308
+     *
309
+     * @param bcode     the bytecode.
310
+     * @since 3.24
311
+     */
312
+    public static Class<?> toClass(Lookup lookup, byte[] bcode)
313
+        throws CannotCompileException
314
+    {
315
+        try {
316
+            return lookup.defineClass(bcode);
317
+        } catch (IllegalAccessException | IllegalArgumentException e) {
318
+            throw new CannotCompileException(e.getMessage());
319
+        }
320
+    }
321
+
254 322
     /**
255 323
      * Loads a class file by {@code java.lang.invoke.MethodHandles.Lookup}.
256 324
      *

+ 13
- 4
src/main/javassist/util/proxy/FactoryHelper.java View File

@@ -104,28 +104,37 @@ public class FactoryHelper {
104 104
      * This method uses a default protection domain for the class
105 105
      * but it may not work with a security manager or a signed jar file.
106 106
      *
107
-     * @see #toClass(ClassFile,ClassLoader,ProtectionDomain)
107
+     * @see #toClass(ClassFile,Class,ClassLoader,ProtectionDomain)
108
+     * @deprecated
108 109
      */
109 110
     public static Class<?> toClass(ClassFile cf, ClassLoader loader)
110 111
         throws CannotCompileException
111 112
     {
112
-        return toClass(cf, loader, null);
113
+        return toClass(cf, null, loader, null);
113 114
     }
114 115
 
115 116
     /**
116 117
      * Loads a class file by a given class loader.
117 118
      *
119
+     * @param neighbor      a class belonging to the same package that
120
+     *                      the loaded class belongs to.
121
+     *                      It can be null.
122
+     * @param loader        The class loader.  It can be null if {@code neighbor}
123
+     *                      is not null.
118 124
      * @param domain        if it is null, a default domain is used.
119 125
      * @since 3.3
120 126
      */
121
-    public static Class<?> toClass(ClassFile cf, ClassLoader loader, ProtectionDomain domain)
127
+    public static Class<?> toClass(ClassFile cf, Class<?> neighbor,
128
+                                   ClassLoader loader, ProtectionDomain domain)
122 129
         throws CannotCompileException
123 130
     {
124 131
         try {
125 132
             byte[] b = toBytecode(cf);
126 133
             if (ProxyFactory.onlyPublicMethods)
127 134
                 return DefineClassHelper.toPublicClass(cf.getName(), b);
128
-            return DefineClassHelper.toClass(cf.getName(), loader, domain, b);
135
+            else
136
+                return DefineClassHelper.toClass(cf.getName(), neighbor,
137
+                                                 loader, domain, b);
129 138
         }
130 139
         catch (IOException e) {
131 140
             throw new CannotCompileException(e);

+ 16
- 2
src/main/javassist/util/proxy/ProxyFactory.java View File

@@ -213,7 +213,7 @@ public class ProxyFactory {
213 213
      *
214 214
      * <p>The default value is {@code false}.</p>
215 215
      *
216
-     * @see DefineClassHelper#toClass(String, ClassLoader, ProtectionDomain, byte[])
216
+     * @see DefineClassHelper#toClass(String, Class<?>, ClassLoader, ProtectionDomain, byte[])
217 217
      * @since 3.22
218 218
      */
219 219
     public static boolean onlyPublicMethods = false;
@@ -549,7 +549,7 @@ public class ProxyFactory {
549 549
             if (writeDirectory != null)
550 550
                 FactoryHelper.writeFile(cf, writeDirectory);
551 551
 
552
-            thisClass = FactoryHelper.toClass(cf, cl, getDomain());
552
+            thisClass = FactoryHelper.toClass(cf, getClassInTheSamePackage(), cl, getDomain());
553 553
             setField(FILTER_SIGNATURE_FIELD, signature);
554 554
             // legacy behaviour : we only set the default interceptor static field if we are not using the cache
555 555
             if (!factoryUseCache) {
@@ -562,6 +562,20 @@ public class ProxyFactory {
562 562
 
563 563
     }
564 564
 
565
+    /**
566
+     * Obtains a class belonging to the same package that the created
567
+     * proxy class belongs to.  It is used to obtain an appropriate
568
+     * {@code java.lang.invoke.MethodHandles.Lookup}.
569
+     */
570
+    private Class<?> getClassInTheSamePackage() {
571
+        if (superClass != null && superClass != OBJECT_TYPE)
572
+            return superClass;
573
+        else if (interfaces != null && interfaces.length > 0)
574
+            return interfaces[0];
575
+        else
576
+            return this.getClass();     // maybe wrong?
577
+    }
578
+
565 579
     private void setField(String fieldName, Object value) {
566 580
         if (thisClass != null && value != null)
567 581
             try {

+ 5
- 0
src/test/DefineClassCapability.java View File

@@ -0,0 +1,5 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+public class DefineClassCapability {
5
+}

+ 5
- 2
src/test/javassist/JvstTest.java View File

@@ -1,6 +1,8 @@
1 1
 package javassist;
2 2
 
3 3
 import junit.framework.*;
4
+import test1.DefineClassCapability;
5
+
4 6
 import java.io.File;
5 7
 import java.io.FileInputStream;
6 8
 import java.io.InputStream;
@@ -743,8 +745,8 @@ public class JvstTest extends JvstTestRoot {
743 745
 
744 746
         ctInterface.stopPruning(true);
745 747
         ctInterface.writeFile();
746
-        ctInterface.toClass();
747
-        targetCtClass.toClass();
748
+        ctInterface.toClass(DefineClassCapability.class);
749
+        targetCtClass.toClass(DefineClassCapability.class);
748 750
     }
749 751
 
750 752
     public void testDispatch() throws Exception {
@@ -1161,6 +1163,7 @@ public class JvstTest extends JvstTestRoot {
1161 1163
         suite.addTestSuite(javassist.SetterTest.class);
1162 1164
         suite.addTestSuite(javassist.bytecode.InsertGap0.class);
1163 1165
         suite.addTestSuite(javassist.tools.reflect.LoaderTest.class);
1166
+        suite.addTestSuite(javassist.tools.CallbackTest.class);
1164 1167
         suite.addTestSuite(testproxy.ProxyTester.class);
1165 1168
         suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class); // remove?
1166 1169
         suite.addTestSuite(javassist.proxyfactory.ProxyFactoryTest.class);

+ 2
- 1
src/test/javassist/JvstTest2.java View File

@@ -9,6 +9,7 @@ import org.junit.runners.MethodSorters;
9 9
 import java.lang.reflect.Method;
10 10
 
11 11
 import javassist.expr.*;
12
+import test2.DefineClassCapability;
12 13
 
13 14
 @SuppressWarnings({"rawtypes","unused"})
14 15
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -709,7 +710,7 @@ public class JvstTest2 extends JvstTestRoot {
709 710
     public void testToClass() throws Exception {
710 711
         ClassPool cp = ClassPool.getDefault();
711 712
         CtClass cc = cp.makeClass("test2.ToClassTest");
712
-        Class c = cc.toClass();
713
+        Class c = cc.toClass(DefineClassCapability.class);
713 714
 	assertEquals(getClass().getClassLoader(), c.getClassLoader());
714 715
     }
715 716
 

+ 4
- 4
src/test/javassist/JvstTest3.java View File

@@ -340,7 +340,7 @@ public class JvstTest3 extends JvstTestRoot {
340 340
         System.out.println("Num Annotation : " +ans.length);
341 341
 
342 342
         // c.debugWriteFile();
343
-        Class newclass = c.toClass();
343
+        Class newclass = c.toClass(DefineClassCapability.class);
344 344
         java.lang.annotation.Annotation[] anns = newclass.getAnnotations();
345 345
         System.out.println("Num NewClass Annotation : " +anns.length);
346 346
         assertEquals(ans.length, anns.length);
@@ -737,7 +737,7 @@ public class JvstTest3 extends JvstTestRoot {
737 737
         CtMethod m2 = cc2.getDeclaredMethod("getX");
738 738
         copyAnnotations(m1, m2);
739 739
         cc2.getClassFile();
740
-        Class clazz = cc2.toClass();
740
+        Class clazz = cc2.toClass(DefineClassCapability.class);
741 741
         java.lang.reflect.Method m = clazz.getDeclaredMethod("getX", new Class[0]);
742 742
         assertEquals(1, m.getAnnotations().length);
743 743
         test3.VisibleAnno a = m.getAnnotation(test3.VisibleAnno.class);
@@ -790,7 +790,7 @@ public class JvstTest3 extends JvstTestRoot {
790 790
         cc.addField(fobj, CtField.Initializer.constant("bar"));
791 791
 
792 792
         cc.writeFile();
793
-        Class clazz = cc.toClass();
793
+        Class clazz = cc.toClass(DefineClassCapability.class);
794 794
         assertEquals(2L, clazz.getField("j").getLong(null));
795 795
         assertEquals(3, clazz.getField("i").getInt(null));
796 796
         assertEquals(4, clazz.getField("s").getShort(null));
@@ -1108,7 +1108,7 @@ public class JvstTest3 extends JvstTestRoot {
1108 1108
         sb.append("}"); 
1109 1109
         ctc.addMethod(CtNewMethod.make(sb.toString(), ctc));
1110 1110
         ctc.debugWriteFile();
1111
-        ctc.toClass().getConstructor().newInstance();
1111
+        ctc.toClass(DefineClassCapability.class).getConstructor().newInstance();
1112 1112
     }
1113 1113
 
1114 1114
     // JIRA-83

+ 2
- 1
src/test/javassist/JvstTest4.java View File

@@ -1054,7 +1054,7 @@ public class JvstTest4 extends JvstTestRoot {
1054 1054
         addDeadCode(newClass, "public boolean evaluate7(){ return !true; }");
1055 1055
 
1056 1056
         newClass.debugWriteFile();
1057
-        Class<?> cClass = newClass.toClass();
1057
+        Class<?> cClass = newClass.toClass(test4.DefineClassCapability.class);
1058 1058
         Object o = cClass.getConstructor().newInstance();
1059 1059
         java.lang.reflect.Method m = cClass.getMethod("evaluate");
1060 1060
         m.invoke(o);
@@ -1112,6 +1112,7 @@ public class JvstTest4 extends JvstTestRoot {
1112 1112
         attr.setAnnotation(a);
1113 1113
         m.getMethodInfo().addAttribute(attr);
1114 1114
         cc.writeFile();
1115
+        anno.toClass(test4.DefineClassCapability.class);
1115 1116
         Class<?> rc = ((java.lang.annotation.Annotation)m.getAnnotations()[0]).annotationType();
1116 1117
         assertEquals(anno.getName(), rc.getName());
1117 1118
     }

+ 2
- 2
src/test/javassist/JvstTest5.java View File

@@ -223,7 +223,7 @@ public class JvstTest5 extends JvstTestRoot {
223 223
                 "}");
224 224
         System.out.println(src);
225 225
         badClass.addMethod(CtMethod.make(src, badClass));
226
-        Class clazzz = badClass.toClass();
226
+        Class clazzz = badClass.toClass(Class.forName("DefineClassCapability"));
227 227
         Object obj = clazzz.getConstructor().newInstance(); // <-- falls here
228 228
     }
229 229
 
@@ -451,6 +451,6 @@ public class JvstTest5 extends JvstTestRoot {
451 451
     public void testNestHostAttributeCopy() throws Exception {
452 452
         CtClass cc = sloader.get("test5.NestHost2$Foo");
453 453
         cc.getClassFile().compact();
454
-        cc.toClass();
454
+        cc.toClass(test5.DefineClassCapability.class);
455 455
     }
456 456
 }

+ 114
- 112
src/test/javassist/SetterTest.java View File

@@ -1,112 +1,114 @@
1
-package javassist;
2
-import java.lang.reflect.Method;
3
-
4
-import junit.framework.TestCase;
5
-
6
-@SuppressWarnings({"rawtypes","unchecked"})
7
-public class SetterTest extends TestCase {
8
-
9
-    ClassPool pool;
10
-
11
-    public SetterTest(String name) {
12
-         super(name);
13
-    }
14
-
15
-    protected void setUp() throws Exception {
16
-        super.setUp();
17
-        pool = ClassPool.getDefault();
18
-    }
19
-
20
-    /**
21
-     * Tests a getter only on a field without a Modifier.
22
-     * 
23
-     * @throws Exception
24
-     */
25
-    public void testFieldGetter() throws Exception {
26
-        CtClass clazz = pool.makeClass("HasFieldGetter");
27
-        clazz.setSuperclass(pool.get("java.lang.Object"));
28
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
29
-        clazz.addField(field, "true");
30
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));
31
-        Class _class = clazz.toClass();
32
-
33
-        Object object = _class.getConstructor().newInstance();
34
-        check(_class, object, true);
35
-    }
36
-
37
-    /**
38
-     * Tests a getter and a setter on a field without a Modifier.
39
-     * 
40
-     * @throws Exception
41
-     */
42
-    public void testFieldGetterSetter() throws Exception {
43
-        CtClass clazz = pool.makeClass("HasFieldGetterSetter");
44
-        clazz.setSuperclass(pool.get("java.lang.Object"));
45
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
46
-        clazz.addField(field, "true");
47
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));
48
-        clazz.addMethod(CtNewMethod.setter("setBroken", field));
49
-        Class _class = clazz.toClass();
50
-
51
-        Object object = _class.getConstructor().newInstance();
52
-
53
-        set(_class, object, false);
54
-        check(_class, object, false);
55
-    }
56
-
57
-    /**
58
-     * Tests a getter only on a field with Modifier.STATIC.
59
-     * 
60
-     * @throws Exception
61
-     */
62
-    public void testStaticFieldGetter() throws Exception {
63
-        CtClass clazz = pool.makeClass("HasStaticFieldGetter");
64
-        clazz.setSuperclass(pool.get("java.lang.Object"));
65
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
66
-        field.setModifiers(Modifier.STATIC);
67
-        clazz.addField(field, "true");
68
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));
69
-        Class _class = clazz.toClass();
70
-
71
-        Object object = _class.getConstructor().newInstance();
72
-        check(_class, object, true);
73
-    }
74
-
75
-    /**
76
-     * Tests a getter and setter on a field with Modifier.STATIC.
77
-     * 
78
-     * @throws Exception
79
-     */
80
-    public void testStaticFieldGetterSetter() throws Exception {
81
-        CtClass clazz = pool.makeClass("HasStaticFieldGetterSetter");
82
-        clazz.setSuperclass(pool.get("java.lang.Object"));
83
-        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
84
-        field.setModifiers(Modifier.STATIC);
85
-        clazz.addField(field, "true");
86
-        clazz.addMethod(CtNewMethod.getter("isBroken", field));
87
-        clazz.addMethod(CtNewMethod.setter("setBroken", field));
88
-        Class _class = clazz.toClass();
89
-
90
-        Object object = _class.getConstructor().newInstance();
91
-
92
-        set(_class, object, false);
93
-        check(_class, object, false);
94
-    }
95
-
96
-    private void check(Class _class, Object object, boolean shouldBe)
97
-        throws Exception
98
-    {
99
-        Method method = _class.getMethod("isBroken", new Class[] {});
100
-        Boolean result = (Boolean) method.invoke(object, new Object[] {});
101
-        assertEquals("boolean is wrong value",
102
-                     shouldBe, result.booleanValue());
103
-    }
104
-
105
-    private void set(Class _class, Object object, boolean willBe)
106
-        throws Exception
107
-    {
108
-        Method method = _class.getMethod("setBroken",
109
-                                         new Class[] {Boolean.TYPE});
110
-        method.invoke(object, new Object[] { Boolean.valueOf(willBe)});
111
-    }
112
-}
1
+package javassist;
2
+import java.lang.reflect.Method;
3
+
4
+import junit.framework.TestCase;
5
+
6
+@SuppressWarnings({"rawtypes","unchecked"})
7
+public class SetterTest extends TestCase {
8
+
9
+    ClassPool pool;
10
+    Class<?> capability;
11
+
12
+    public SetterTest(String name) {
13
+         super(name);
14
+    }
15
+
16
+    protected void setUp() throws Exception {
17
+        super.setUp();
18
+        pool = ClassPool.getDefault();
19
+        capability = Class.forName("DefineClassCapability");
20
+    }
21
+
22
+    /**
23
+     * Tests a getter only on a field without a Modifier.
24
+     * 
25
+     * @throws Exception
26
+     */
27
+    public void testFieldGetter() throws Exception {
28
+        CtClass clazz = pool.makeClass("HasFieldGetter");
29
+        clazz.setSuperclass(pool.get("java.lang.Object"));
30
+        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
31
+        clazz.addField(field, "true");
32
+        clazz.addMethod(CtNewMethod.getter("isBroken", field));
33
+        Class _class = clazz.toClass(capability);
34
+
35
+        Object object = _class.getConstructor().newInstance();
36
+        check(_class, object, true);
37
+    }
38
+
39
+    /**
40
+     * Tests a getter and a setter on a field without a Modifier.
41
+     * 
42
+     * @throws Exception
43
+     */
44
+    public void testFieldGetterSetter() throws Exception {
45
+        CtClass clazz = pool.makeClass("HasFieldGetterSetter");
46
+        clazz.setSuperclass(pool.get("java.lang.Object"));
47
+        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
48
+        clazz.addField(field, "true");
49
+        clazz.addMethod(CtNewMethod.getter("isBroken", field));
50
+        clazz.addMethod(CtNewMethod.setter("setBroken", field));
51
+        Class _class = clazz.toClass(capability);
52
+
53
+        Object object = _class.getConstructor().newInstance();
54
+
55
+        set(_class, object, false);
56
+        check(_class, object, false);
57
+    }
58
+
59
+    /**
60
+     * Tests a getter only on a field with Modifier.STATIC.
61
+     * 
62
+     * @throws Exception
63
+     */
64
+    public void testStaticFieldGetter() throws Exception {
65
+        CtClass clazz = pool.makeClass("HasStaticFieldGetter");
66
+        clazz.setSuperclass(pool.get("java.lang.Object"));
67
+        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
68
+        field.setModifiers(Modifier.STATIC);
69
+        clazz.addField(field, "true");
70
+        clazz.addMethod(CtNewMethod.getter("isBroken", field));
71
+        Class _class = clazz.toClass(capability);
72
+
73
+        Object object = _class.getConstructor().newInstance();
74
+        check(_class, object, true);
75
+    }
76
+
77
+    /**
78
+     * Tests a getter and setter on a field with Modifier.STATIC.
79
+     * 
80
+     * @throws Exception
81
+     */
82
+    public void testStaticFieldGetterSetter() throws Exception {
83
+        CtClass clazz = pool.makeClass("HasStaticFieldGetterSetter");
84
+        clazz.setSuperclass(pool.get("java.lang.Object"));
85
+        CtField field = new CtField(CtClass.booleanType, "broken", clazz);
86
+        field.setModifiers(Modifier.STATIC);
87
+        clazz.addField(field, "true");
88
+        clazz.addMethod(CtNewMethod.getter("isBroken", field));
89
+        clazz.addMethod(CtNewMethod.setter("setBroken", field));
90
+        Class _class = clazz.toClass(capability);
91
+
92
+        Object object = _class.getConstructor().newInstance();
93
+
94
+        set(_class, object, false);
95
+        check(_class, object, false);
96
+    }
97
+
98
+    private void check(Class _class, Object object, boolean shouldBe)
99
+        throws Exception
100
+    {
101
+        Method method = _class.getMethod("isBroken", new Class[] {});
102
+        Boolean result = (Boolean) method.invoke(object, new Object[] {});
103
+        assertEquals("boolean is wrong value",
104
+                     shouldBe, result.booleanValue());
105
+    }
106
+
107
+    private void set(Class _class, Object object, boolean willBe)
108
+        throws Exception
109
+    {
110
+        Method method = _class.getMethod("setBroken",
111
+                                         new Class[] {Boolean.TYPE});
112
+        method.invoke(object, new Object[] { Boolean.valueOf(willBe)});
113
+    }
114
+}

+ 2
- 2
src/test/javassist/bytecode/InsertGap0.java View File

@@ -175,7 +175,7 @@ public final class InsertGap0 extends JvstTestRoot {
175 175
         cc.addField(new CtField(CtClass.intType, "i", cc), "++counter");
176 176
         boolean p = cc.stopPruning(true);
177 177
         cc.writeFile();
178
-        Class c = cc.toClass();
178
+        Class c = cc.toClass(ClassFile.class);
179 179
         cc.stopPruning(p);
180 180
 
181 181
         Object obj = c.getConstructor().newInstance();
@@ -194,7 +194,7 @@ public final class InsertGap0 extends JvstTestRoot {
194 194
         cc.addField(new CtField(CtClass.intType, "i", cc), "++counter");
195 195
         boolean p = cc.stopPruning(true);
196 196
         cc.writeFile();
197
-        Class c = cc.toClass();
197
+        Class c = cc.toClass(ClassFile.class);
198 198
         cc.stopPruning(p);
199 199
 
200 200
         Object obj = c.getConstructor().newInstance();

+ 2
- 1
src/test/javassist/tools/CallbackTest.java View File

@@ -3,6 +3,7 @@ package javassist.tools;
3 3
 import javassist.*;
4 4
 import junit.framework.TestCase;
5 5
 import test.javassist.tools.DummyClass;
6
+import test.javassist.tools.DefineClassCapability;
6 7
 
7 8
 import static javassist.tools.Callback.*;
8 9
 
@@ -34,7 +35,7 @@ public class CallbackTest extends TestCase {
34 35
         });
35 36
 
36 37
         // Change class and invoke method;
37
-        classToChange.toClass();
38
+        classToChange.toClass(DefineClassCapability.class);
38 39
         new DummyClass().dummyMethod();
39 40
     }
40 41
 }

+ 7
- 0
src/test/test/javassist/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+package test.javassist;
2
+
3
+/*
4
+ * This is used as a capability for running CtClass#toClass().
5
+ */
6
+public class DefineClassCapability {
7
+}

+ 7
- 5
src/test/test/javassist/convert/ArrayAccessReplaceTest.java View File

@@ -1,7 +1,5 @@
1 1
 package test.javassist.convert;
2 2
 
3
-import java.net.URL;
4
-import java.net.URLClassLoader;
5 3
 import java.util.HashMap;
6 4
 import java.util.Map;
7 5
 
@@ -11,7 +9,7 @@ import javassist.CtClass;
11 9
 import junit.framework.TestCase;
12 10
 
13 11
 public class ArrayAccessReplaceTest extends TestCase {
14
-    private static SimpleInterface simple;
12
+    private static SimpleInterface simple = null;
15 13
 
16 14
     public void setUp() throws Exception {
17 15
         ClassPool pool = new ClassPool(true);
@@ -21,7 +19,9 @@ public class ArrayAccessReplaceTest extends TestCase {
21 19
         converter.replaceArrayAccess(echoClass, new CodeConverter.DefaultArrayAccessReplacementMethodNames());
22 20
         simpleClass.instrument(converter);
23 21
         //simpleClass.writeFile("/tmp");
24
-        simple = (SimpleInterface) simpleClass.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).getConstructor().newInstance();
22
+
23
+        simple = (SimpleInterface)new javassist.Loader.Simple().invokeDefineClass(simpleClass)
24
+                                                               .getConstructor().newInstance();
25 25
     }
26 26
 
27 27
     public void testComplex() throws Exception {
@@ -31,7 +31,9 @@ public class ArrayAccessReplaceTest extends TestCase {
31 31
         CodeConverter converter = new CodeConverter();
32 32
         converter.replaceArrayAccess(clazz, new CodeConverter.DefaultArrayAccessReplacementMethodNames());
33 33
         clazz.instrument(converter);
34
-        ComplexInterface instance = (ComplexInterface) clazz.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).getConstructor().newInstance();
34
+        ComplexInterface instance
35
+            = (ComplexInterface)new javassist.Loader.Simple().invokeDefineClass(clazz)
36
+                                                             .getConstructor().newInstance();
35 37
         assertEquals(Integer.valueOf(5), instance.complexRead(4));
36 38
     }
37 39
 

+ 3
- 3
src/test/test/javassist/proxy/ProxyCacheGCTest.java View File

@@ -90,9 +90,9 @@ public class ProxyCacheGCTest extends TestCase
90 90
             // now create a proxyfactory and use it to create a proxy
91 91
 
92 92
             ProxyFactory factory = new ProxyFactory();
93
-            Class javaTargetClass = classPool.toClass(ctTargetClass);
94
-            Class javaHandlerClass = classPool.toClass(ctHandlerClass);
95
-            Class javaFilterClass = classPool.toClass(ctFilterClass);
93
+            Class javaTargetClass = classPool.toClass(ctTargetClass, test.javassist.DefineClassCapability.class);
94
+            Class javaHandlerClass = classPool.toClass(ctHandlerClass, test.javassist.DefineClassCapability.class);
95
+            Class javaFilterClass = classPool.toClass(ctFilterClass, test.javassist.DefineClassCapability.class);
96 96
 
97 97
             MethodHandler handler= (MethodHandler)javaHandlerClass.getConstructor().newInstance();
98 98
             MethodFilter filter = (MethodFilter)javaFilterClass.getConstructor().newInstance();

+ 0
- 281
src/test/test/javassist/proxy/TestSecuredPrivileged.java View File

@@ -1,281 +0,0 @@
1
-package test.javassist.proxy;
2
-import static org.hamcrest.Matchers.arrayWithSize;
3
-import static org.hamcrest.Matchers.both;
4
-import static org.hamcrest.Matchers.endsWith;
5
-import static org.hamcrest.Matchers.equalTo;
6
-import static org.hamcrest.Matchers.instanceOf;
7
-import static org.hamcrest.Matchers.not;
8
-import static org.hamcrest.Matchers.notNullValue;
9
-import static org.hamcrest.Matchers.startsWith;
10
-import static org.hamcrest.Matchers.stringContainsInOrder;
11
-import static org.junit.Assert.assertThat;
12
-import static org.junit.Assert.assertTrue;
13
-
14
-import java.lang.reflect.Constructor;
15
-import java.lang.reflect.Field;
16
-import java.lang.reflect.InvocationTargetException;
17
-import java.lang.reflect.Method;
18
-import java.lang.reflect.Modifier;
19
-import java.security.ProtectionDomain;
20
-import java.util.Arrays;
21
-
22
-import org.junit.Rule;
23
-import org.junit.Test;
24
-import org.junit.rules.ExpectedException;
25
-
26
-import javassist.ClassPool;
27
-import javassist.CtClass;
28
-import javassist.util.proxy.DefineClassHelper;
29
-
30
-public class TestSecuredPrivileged {
31
-
32
-    public TestSecuredPrivileged() {
33
-    }
34
-
35
-    @Rule
36
-    public ExpectedException thrown = ExpectedException.none();
37
-    /**
38
-     * Test proves that you cannot even access members with
39
-     * private static and final modifiers. */
40
-    @Test
41
-    public void testDefinedHelperPrivilegedFieldVisibility() {
42
-        try {
43
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
44
-            assertTrue(Modifier.isStatic(privi.getModifiers()));
45
-            thrown.expectCause(instanceOf(IllegalAccessException.class));
46
-            thrown.expectMessage(both(stringContainsInOrder(Arrays.asList("cannot access a member")))
47
-                    .and(stringContainsInOrder(Arrays.asList("with modifiers \"private static final".split("", 1)))));
48
-    
49
-            privi.get(null);
50
-        } catch(Throwable  t) {
51
-            throw new RuntimeException(t);
52
-        }
53
-    }
54
-    /**
55
-     * Test proves that the default enum constant is a class and specifically
56
-     * auto selected for Java 9. */
57
-    @Test
58
-    public void testDefinedHelperPrivilegedField() {
59
-        try {
60
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
61
-            assertTrue(Modifier.isStatic(privi.getModifiers()));
62
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
63
-            con.setAccessible(true);
64
-            DefineClassHelper inst = con.newInstance();
65
-            assertThat(inst, instanceOf(DefineClassHelper.class));
66
-            privi.setAccessible(true);
67
-            Object p = privi.get(inst);
68
-            assertThat(""+p, equalTo("JAVA_9"));
69
-            assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$1"));
70
-        } catch(Throwable  t) {
71
-            throw new RuntimeException(t);
72
-        }
73
-    }
74
-    /**
75
-     * Test proves that caller class security is enforced and works
76
-     * as expected. */
77
-    @Test
78
-    public void testDefinedHelperPrivilegedFieldMethodAccessDenied() {
79
-        try {
80
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
81
-            con.setAccessible(true);
82
-            DefineClassHelper inst = con.newInstance();
83
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
84
-            privi.setAccessible(true);
85
-            Object priviInst = privi.get(inst);
86
-            Method defineClass = priviInst.getClass().getDeclaredMethod(
87
-                    "defineClass", new Class[] {
88
-                        String.class, byte[].class, int.class, int.class, 
89
-                        ClassLoader.class, ProtectionDomain.class
90
-                    });
91
-        
92
-            assertThat(defineClass, notNullValue());
93
-            defineClass.setAccessible(true);
94
-            assertThat(defineClass.getName(), equalTo("defineClass"));
95
-            assertTrue(defineClass.canAccess(priviInst));
96
-            ClassPool cp = ClassPool.getDefault();
97
-            CtClass c = cp.makeClass("a.b.C");
98
-            byte[] bc = c.toBytecode();
99
-
100
-            thrown.expectCause(instanceOf(IllegalAccessError.class));
101
-            thrown.expectMessage(equalTo("java.lang.IllegalAccessError: Access denied for caller."));
102
-
103
-            @SuppressWarnings("unused")
104
-            Object res = defineClass.invoke(priviInst, new Object[] {
105
-                c.getName(), bc, 0, bc.length, new ClassLoader() {},
106
-                ClassLoader.class.getProtectionDomain()
107
-            });
108
-        } catch(InvocationTargetException  t) { 
109
-            throw new RuntimeException(t.getTargetException());
110
-        } catch(Throwable  t) { throw new RuntimeException(t); }
111
-    }
112
-    /**
113
-     * Test proves that we do have 3 enum constants in the private static 
114
-     * inner class. */
115
-    @Test
116
-    public void testDefinedHelperEnumClass() {
117
-        try {
118
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
119
-            con.setAccessible(true);
120
-            assertThat(DefineClassHelper.class.getDeclaredClasses(), arrayWithSize(1));
121
-            Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
122
-            assertTrue(secPriv.isEnum());
123
-            assertThat(secPriv.getEnumConstants(), arrayWithSize(3));
124
-            assertThat(""+secPriv.getEnumConstants()[0], equalTo("JAVA_9"));
125
-            assertThat(""+secPriv.getEnumConstants()[1], equalTo("JAVA_7"));
126
-            assertThat(""+secPriv.getEnumConstants()[2], equalTo("JAVA_OTHER"));
127
-
128
-        } catch (Throwable t) {t.printStackTrace();}
129
-
130
-    }
131
-    /**
132
-     * Test proves that you cannot modify private static final reference even 
133
-     * with setAccessible(true). */
134
-    @Test
135
-    public void testDefinedHelperCannotSetPrivileged() {
136
-        try {
137
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
138
-            con.setAccessible(true);
139
-            DefineClassHelper inst = con.newInstance();
140
-            Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
141
-            Object J7 = secPriv.getEnumConstants()[1];
142
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
143
-            privi.setAccessible(true);
144
-            thrown.expectCause(instanceOf(IllegalAccessException.class));
145
-            thrown.expectMessage(startsWith("java.lang.IllegalAccessException: Can not set static final"));
146
-            privi.set(inst, J7);
147
-
148
-        } catch (Throwable t) {throw new RuntimeException(t);}
149
-
150
-    }
151
-    /**
152
-     * Test proves that you can achieve the impossible and modify private
153
-     * static final class reference without an instance. Now we can Mock
154
-     * test JDK 6 to 8 functionality  */
155
-    @Test
156
-    public void testDefinedHelperSetPrivilegedToJava7() {
157
-        try {
158
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
159
-            con.setAccessible(true);
160
-            DefineClassHelper inst = con.newInstance();
161
-            Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
162
-            Object J9 = secPriv.getEnumConstants()[0];
163
-            Object J7 = secPriv.getEnumConstants()[1];
164
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
165
-            privi.setAccessible(true);
166
-            Object privInst = privi.get(inst);
167
-            Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
168
-            unsf.setAccessible(true);
169
-            Object refu = unsf.get(privInst);
170
-            Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
171
-            tuf.setAccessible(true);
172
-            Object tu = tuf.get(refu);
173
-            Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
174
-            tu_call.setAccessible(true);
175
-            long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset",  new Object[] {privi}}); 
176
-            tu_call.invoke(tu, new Object[] {"putObjectVolatile",  new Object[] {DefineClassHelper.class, offset, J7}});
177
-
178
-            Object p = privi.get(inst);
179
-            assertThat(""+p, equalTo("JAVA_7"));
180
-            assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$2"));
181
-
182
-            tu_call.invoke(tu, new Object[] {"putObjectVolatile",  new Object[] {DefineClassHelper.class, offset, J9}});
183
-
184
-        } catch (Throwable t) {t.printStackTrace();}
185
-
186
-    }
187
-    /**
188
-     * Test proves that Java 7+ MethodHandle defineClass (or DefineClassHelper.toClass)
189
-     * works as expected. */
190
-    @Test
191
-    public void testDefinedHelperJava7ToClass() {
192
-        try {
193
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
194
-            con.setAccessible(true);
195
-            DefineClassHelper inst = con.newInstance();
196
-            Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
197
-            Object J9 = secPriv.getEnumConstants()[0];
198
-            Object J7 = secPriv.getEnumConstants()[1];
199
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
200
-            privi.setAccessible(true);
201
-            Object privInst = privi.get(inst);
202
-            Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
203
-            unsf.setAccessible(true);
204
-            Object refu = unsf.get(privInst);
205
-            Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
206
-            tuf.setAccessible(true);
207
-            Object tu = tuf.get(refu);
208
-            Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
209
-            tu_call.setAccessible(true);
210
-            long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset",  new Object[] {privi}}); 
211
-            tu_call.invoke(tu, new Object[] {"putObjectVolatile",  new Object[] {DefineClassHelper.class, offset, J7}});
212
-
213
-            ClassPool cp = ClassPool.getDefault();
214
-            CtClass c = cp.makeClass("a.b.J7");
215
-            byte[] bc = c.toBytecode();
216
-            Class<?> bcCls = DefineClassHelper.toClass("a.b.J7", new ClassLoader() {}, null, bc);
217
-            assertThat(bcCls.getName(), equalTo("a.b.J7"));
218
-            assertThat(bcCls.getDeclaredConstructor().newInstance(),
219
-                    not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
220
-
221
-            tu_call.invoke(tu, new Object[] {"putObjectVolatile",  new Object[] {DefineClassHelper.class, offset, J9}});
222
-            
223
-        } catch (Throwable t) {t.printStackTrace();}
224
-
225
-    }
226
-    /**
227
-     * Test proves that Java 6 reflection method defineClass (or DefineClassHelper.toClass)
228
-     * works as expected. */
229
-    @Test
230
-    public void testDefinedHelperJavaOtherToClass() {
231
-        try {
232
-            Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
233
-            con.setAccessible(true);
234
-            DefineClassHelper inst = con.newInstance();
235
-            Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
236
-            Object J9 = secPriv.getEnumConstants()[0];
237
-            Object JO = secPriv.getEnumConstants()[2];
238
-            Field privi = DefineClassHelper.class.getDeclaredField("privileged");
239
-            privi.setAccessible(true);
240
-            Object privInst = privi.get(inst);
241
-            Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
242
-            unsf.setAccessible(true);
243
-            Object refu = unsf.get(privInst);
244
-            Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
245
-            tuf.setAccessible(true);
246
-            Object tu = tuf.get(refu);
247
-            Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
248
-            tu_call.setAccessible(true);
249
-            long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset",  new Object[] {privi}}); 
250
-            tu_call.invoke(tu, new Object[] {"putObjectVolatile",  new Object[] {DefineClassHelper.class, offset, JO}});
251
-
252
-            ClassPool cp = ClassPool.getDefault();
253
-            CtClass c = cp.makeClass("a.b.JO");
254
-            byte[] bc = c.toBytecode();
255
-            Class<?> bcCls = DefineClassHelper.toClass("a.b.JO", new ClassLoader() {}, null, bc);
256
-            assertThat(bcCls.getName(), equalTo("a.b.JO"));
257
-            assertThat(bcCls.getDeclaredConstructor().newInstance(),
258
-                    not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
259
-
260
-            tu_call.invoke(tu, new Object[] {"putObjectVolatile",  new Object[] {DefineClassHelper.class, offset, J9}});
261
-            
262
-        } catch (Throwable t) {t.printStackTrace();}
263
-
264
-    }
265
-    /**
266
-     * Test proves that default Java 9 defineClass (or DefineClassHelper.toClass)
267
-     * works as expected. */
268
-    @Test
269
-    public void testDefinedHelperDefaultToClass() {
270
-        try {
271
-            ClassPool cp = ClassPool.getDefault();
272
-            CtClass c = cp.makeClass("a.b.D");
273
-            byte[] bc = c.toBytecode();
274
-            Class<?> bcCls = DefineClassHelper.toClass("a.b.D", new ClassLoader() {}, null, bc);
275
-            assertThat(bcCls.getName(), equalTo("a.b.D"));
276
-            assertThat(bcCls.getDeclaredConstructor().newInstance(),
277
-                    not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
278
-        } catch (Throwable t) {t.printStackTrace();}
279
-
280
-    }
281
-}

+ 7
- 0
src/test/test/javassist/tools/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+package test.javassist.tools;
5
+
6
+public class DefineClassCapability {
7
+}

+ 7
- 0
src/test/test1/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+package test1;
5
+
6
+public class DefineClassCapability {
7
+}

+ 7
- 0
src/test/test2/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+package test2;
5
+
6
+public class DefineClassCapability {
7
+}

+ 7
- 0
src/test/test3/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+package test3;
5
+
6
+public class DefineClassCapability {
7
+}

+ 7
- 0
src/test/test4/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+package test4;
5
+
6
+public class DefineClassCapability {
7
+}

+ 7
- 0
src/test/test5/DefineClassCapability.java View File

@@ -0,0 +1,7 @@
1
+/*
2
+ * This is used as a capability for running CtClass#toClass().
3
+ */
4
+package test5;
5
+
6
+public class DefineClassCapability {
7
+}

Loading…
Cancel
Save