[jboss-jira] [JBoss JIRA] (JASSIST-261) Issue with javassist on jdk 9b112

Scott Marlow (JIRA) issues at jboss.org
Thu Sep 22 09:55:01 EDT 2016


    [ https://issues.jboss.org/browse/JASSIST-261?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13297235#comment-13297235 ] 

Scott Marlow commented on JASSIST-261:
--------------------------------------

[~sebersole] I think yes, part of the text from the linked [http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2016-June/000307.html] proposal is quoted here, which I think is showing that the application developer changes their Hibernate applications to privately export these classes to Hibernate:
{quote}
Proposal
--------

Extend the language of module declarations so that a package can be
declared to be exported at run time but not at compile time.  This is,
roughly, the dual of the `requires static` construct proposed for
#CompileTimeDependences, hence we propose to introduce a new modifier,
`dynamic`, for use on the `exports` directive.  It has the following
meanings:

  - At compile time, `exports dynamic P` does not cause the package `P`
    to be exported, though it does require `P` to be a package defined
    in the module.

  - In phases after compile time, `exports dynamic P` behaves in exactly
    the same way as `exports P`.  It therefore takes part fully in
    resolution and configuration, and is subject to the same consistency
    constraints as normally-exported packages (e.g., no split packages).

Thus a module declaration of the form

    module com.foo.app {
        requires hibernate.core;
        requires hibernate.entitymanager;
        exports dynamic com.foo.app.model;
    }

makes the types in the `com.foo.app.model` package accessible at run time
but not at compile time.  In combination with the earlier change to
enable #ReflectionWithoutReadability [2] this means that frameworks that
today use core reflection to manipulate user classes at run time are more
likely to work out-of-the-box, without change, as automatic modules.  If
the `com.foo.app.model` package in this example includes entity classes
to be managed by Hibernate then the framework will be able to access them
without further ado, but under normal circumstances an attempt to compile
code that refers directly to those classes will fail.

The `dynamic` modifier can be applied to both unqualified and qualified
`exports` directives, though the caveats on using qualified exports [3]
still apply.
{quote}

[https://java.net/projects/javaee-spec/lists/jsr366-experts/archive/2016-09/message/2] is where I saw the (above mentioned) list of issues being discussed.  


> 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 at 9-ea/Native Method)
>     at sun.reflect.NativeMethodAccessorImpl.invoke(java.base at 9-ea/NativeMethodAccessorImpl.java:62)
>     at sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base at 9-ea/DelegatingMethodAccessorImpl.java:43)
>     at java.lang.reflect.Method.invoke(java.base at 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.



--
This message was sent by Atlassian JIRA
(v6.4.11#64026)


More information about the jboss-jira mailing list