ClassLoadingUtil { public static <T> Class<T> toClass(CtClass ctClass) throws CannotCompileException { return toClass(ctClass, ClassLoadingUtil.class.getClassLoader(), null); } private  ClassLoadingUtil(); static Class<T> toClass(CtClass ctClass); static Class<T> toClass(CtClass ctClass, ClassLoader loader, ProtectionDomain domain);  }
@Test public void basicSubclassWorks() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException { CtClass superClass = pool.get(TestClassAlpha.class.getName()); CtClass subClass = pool.makeClass(makeNewName()); subClass.setSuperclass(superClass); CtMethod toStringMethod = superClass.getDeclaredMethod("toString"); CtMethod override = CtNewMethod.copy(toStringMethod, "toString", subClass, null); override.setBody("return ($r) super.toString().concat(\"Beta!\");"); subClass.addMethod(override); Class<TestClassAlpha> betaClass = ClassLoadingUtil.toClass(subClass); TestClassAlpha beta = betaClass.newInstance(); assertEquals("AlphaBeta!", beta.toString()); }
@Test public void utilityAppearsThreadSafe() throws Exception { int threads = 10; int iterations = 500; ExecutorService exec = Executors.newFixedThreadPool(threads); final Method defineClass1 = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); final Method defineClass2 = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class); final CountDownLatch start = new CountDownLatch(1); final CountDownLatch done = new CountDownLatch(threads * iterations); final List<Class<?>> newClasses = Collections.synchronizedList(new ArrayList<Class<?>>(threads)); for (int i = 0; i < threads * iterations; i++) { exec.submit(new Runnable() { public void run() { try { String newName = makeNewName(); CtClass newClass = pool.makeClass(newName); start.await(); assertFalse(defineClass1.isAccessible()); assertFalse(defineClass2.isAccessible()); Class<Object> theNewClass = ClassLoadingUtil.toClass(newClass); assertFalse(defineClass1.isAccessible()); assertFalse(defineClass2.isAccessible()); newClasses.add(theNewClass); } catch (Exception e) { } finally { done.countDown(); } } }); } start.countDown(); done.await(); assertEquals("Bug in test", 0, exec.shutdownNow().size()); assertEquals(threads * iterations, newClasses.size()); assertFalse(defineClass1.isAccessible()); assertFalse(defineClass2.isAccessible()); }
@Test public void enhanceGamma() throws Exception { CtClass gamma = pool.get(TestClassGamma.class.getName()); CtClass dirtyInterface = pool.get(Persistent.class.getName()); CtClass enhanced = pool.makeClass(makeNewName()); enhanced.setSuperclass(gamma); enhanced.addInterface(dirtyInterface); CtMethod isDirtyMethod = CtNewMethod.make("public boolean isDirty() { return getFoo() != null || getBars() != null; }", enhanced); enhanced.addMethod(isDirtyMethod); Class<TestClassGamma> cls = ClassLoadingUtil.toClass(enhanced); TestClassGamma instance = cls.newInstance(); assertNotNull(instance); assertNull(instance.getBars()); assertNull(instance.getFoo()); assertDirty(instance, false); instance.setFoo(toString()); instance.setBars(Collections.singletonList("bar")); assertDirty(instance, true); assertEquals(toString(), instance.getFoo()); assertEquals(Collections.singletonList("bar"), instance.getBars()); instance.setFoo(null); instance.setBars(null); assertNull(instance.getBars()); assertNull(instance.getFoo()); assertDirty(instance, false); }