2016-04-11 79 views
3

我正在將項目遷移到java 9,它也使用javassist生成運行時代碼。我的一個測試在jdk 9b112上失敗,而它通過jdk 8u77。jdk上的javassist問題9b112

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) {} 
    } 

    @Test 
    public void test() throws InstantiationException, IllegalAccessException { 
     Class<? extends MyObject> clazz = compile(MyObject.class); 
     clazz.newInstance().setField(null); 
    } 

    /** 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); 
       proxyClass.addField(field); 

       // 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); 
       proxyClass.addMethod(setter); 
      } 

      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; 
    } 
} 

在JDK 8u77中,compile()函數成功的 「Hello world」 被打印到控制檯返回。 在JDK 9b112,我得到這個例外

java.lang.RuntimeException: Failure during transfer compilation for class MyTests$MyObject 
    at MyTests.compile(MyTests.java:68) 
    at MyTests.test(MyTests.java:29) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke([email protected]/Method.java:531) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:670) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 
Caused by: javassist.NotFoundException: java.lang.Object 
    at javassist.ClassPool.get(ClassPool.java:450) 
    at MyTests.compile(MyTests.java:51) 
    ... 24 more 

...我已經尋找互聯網上的這一問題,並沒有發現相關的問題,甚至不是在了Javassist的bug跟蹤系統。

+0

你可以提交一個javassist的錯誤。可能是JDK9測試版的問題。或者你可以調試自己並提供修復。 ;) – Konrad

+0

拼圖最近登陸,也許嘗試一箇舊版本 – the8472

回答

1

Javassist 3.22.0-GA似乎已經得到了這個固定的讀取在它的發行現調 -

兼容的Java 9.

可以使用使用相同的

Maven

<dependency> 
    <groupId>org.javassist</groupId> 
    <artifactId>javassist</artifactId> 
    <version>3.22.0-GA</version> 
</dependency> 

搖籃

compile 'org.javassist:javassist:3.22.0-GA' 

SBT

libraryDependencies += "org.javassist" % "javassist" % "3.22.0-GA" 

PS:我全光照g也是JDK的9.0.1版本。