• Type: Bug
    • Status: Resolved (View Workflow)
    • Priority: Major
    • Resolution: Done
    • Affects Version/s: 3.20.0-GA
    • Fix Version/s: 3.22.0-CR1
    • Labels:


      I am migrating a project to java 9, which also uses javassist to generate runtime code.
      One test of mine fails on jdk 9b112 while it passes on jdk 8u77.

      import static javassist.CtClass.voidType;
      import java.lang.reflect.Method;
      import java.lang.reflect.Modifier;
      import java.util.HashMap;
      import java.util.Map;
      import org.junit.Test;
      import javassist.ClassClassPath;
      import javassist.ClassPool;
      import javassist.CtClass;
      import javassist.CtField;
      import javassist.CtMethod;
      import javassist.CtNewMethod;
      public class MyTests {
          public static class MyObject {
              protected Object field;
              Object getField() {return field;}
              public void setField(Object field) {}
          public void test() throws InstantiationException, IllegalAccessException {
              Class<? extends MyObject> clazz = compile(MyObject.class);
          /** Compile a transfer class */
          public static synchronized Class<? extends MyObject> compile(Class<?> targetClass) {
              // Determine class setters
              Map<String, Method> setters = extractSetters(targetClass);
              ClassPool classPool = ClassPool.getDefault();
              classPool.insertClassPath(new ClassClassPath(targetClass));
              try {
                  // Compile a new transfer class on the fly
                  CtClass baseClass = classPool.get(MyObject.class.getName());
                  CtClass proxyClass = classPool.makeClass(targetClass.getName() + "_Modified", baseClass);
                  for(Method originalSetter : setters.values()) {
                      // Create a field to hold the attribute
                      Class<?> fieldClass = originalSetter.getParameterTypes()[0];
                      CtClass fieldType = classPool.get(fieldClass.getName());
                      String fieldName = originalSetter.getName().substring(3);
                      CtField field = new CtField(fieldType, fieldName, proxyClass);
                      // Create a setter method to set that field
                      CtClass[] parameters = new CtClass[] { fieldType };
                      String setterBody = "{ System.out.println(\"Hello World\"); }";
                      CtMethod setter = CtNewMethod.make(voidType, originalSetter.getName(), parameters, new CtClass[0], setterBody, proxyClass);
                  Class<? extends MyObject> javaClass = proxyClass.toClass(targetClass.getClassLoader(), targetClass.getProtectionDomain());
                  return javaClass;
              } catch(Exception e) {
                  throw new RuntimeException("Failure during transfer compilation for " + targetClass, e);
          /** Extract setter methods from a class */
          public static Map<String, Method> extractSetters(Class<?> cls) {
              Map<String, Method> setters = new HashMap<String, Method>();
              for(Method method : cls.getMethods()) {
                  // Lookup setter methods
                  if(method.getName().startsWith("set")) {
                      // Only public setters
                      int modifiers = method.getModifiers();
                      if(Modifier.isPublic(modifiers)) {
                          Class<?>[] exceptions = method.getExceptionTypes();
                          Class<?>[] parameters = method.getParameterTypes();
                          Class<?> returnType = method.getReturnType();
                          if(exceptions.length <= 0 && parameters.length == 1 && "void".equals(returnType.getName())) {
                              setters.put(method.getName(), method);
              return setters;

      On jdk 8u77, the compile() function returns with success and "Hello world" is printed to the console.
      On jdk 9b112, I got the following exception

      java.lang.RuntimeException: Failure during transfer compilation for class MyTests$MyObject
          at MyTests.compile(
          at MyTests.test(
          at sun.reflect.NativeMethodAccessorImpl.invoke0(java.base@9-ea/Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(java.base@9-ea/
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-ea/
          at java.lang.reflect.Method.invoke(java.base@9-ea/
          at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(
          at org.junit.runners.model.FrameworkMethod.invokeExplosively(
          at org.junit.internal.runners.statements.InvokeMethod.evaluate(
          at org.junit.runners.ParentRunner.runLeaf(
          at org.junit.runners.BlockJUnit4ClassRunner.runChild(
          at org.junit.runners.BlockJUnit4ClassRunner.runChild(
          at org.junit.runners.ParentRunner$
          at org.junit.runners.ParentRunner$1.schedule(
          at org.junit.runners.ParentRunner.runChildren(
          at org.junit.runners.ParentRunner.access$000(
          at org.junit.runners.ParentRunner$2.evaluate(
          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(
          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(
          at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(
      Caused by: javassist.NotFoundException: java.lang.Object
          at javassist.ClassPool.get(
          at MyTests.compile(
          ... 24 more

      I suspect that is due to the jigsaw integration into the jdk.

        Gliffy Diagrams




              • Assignee:
                chiba Shigeru Chiba
                thchuong Hoang Chuong Tran
              • Votes:
                0 Vote for this issue
                10 Start watching this issue


                • Created: