]
Steve Ebersole commented on JASSIST-261:
----------------------------------------
Did you had to make code changes in Javassist to make it Java 9 compatible? And if so,
did those changes make it incompatible with Java 8?
Initially I had incorrectly run the Hibernate tests with this Javassist SNAPSHOT using JDK
8 and all the tests passed. The changes also got those tests previously failing due to
Javassist in Java 9 to pass. So it would seem to me (limited to Hibernate's usage)
that your changes leave Javassist simultaneously compatible with Java 8 and Java 9.
Therefore I'd personally not worry about Java 9 still being ea. However Java 9 is
still evolving, and as Scott pointed out, one of the current change proposals specifically
targets better operability with reflective libraries (such as Javassist) so I'd
anticipate having to at least verify this all works with later Java 9 releases.
If you want to start "Java 9 support" with a new version increment (3.20 ->
3.21) then I'd suggest a 3.21.0.CR1 for now. That gives Hibernate and others a named
Javassist release to target, but still gives you the flexibility to adjust for later
changes made in coming Java 9 updates prior to a 3.21 GA/Final
Issue with javassist on jdk 9b112
---------------------------------
Key: JASSIST-261
URL:
https://issues.jboss.org/browse/JASSIST-261
Project: Javassist
Issue Type: Bug
Affects Versions: 3.20.0-GA
Environment: Javassist with jdk 9b112
Reporter: Hoang Chuong Tran
Assignee: Shigeru Chiba
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.
{noformat}
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;
}
}
{noformat}
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
{noformat}
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(java.base@9-ea/Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(java.base@9-ea/NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-ea/DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(java.base@9-ea/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
{noformat}
I suspect that is due to the jigsaw integration into the jdk.