-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
19, 20
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
macos openjdk-19.0.1+10
A DESCRIPTION OF THE PROBLEM :
As an implementer of < https://abcl.org >, I am trying to code a pure-Java solution that will run on openjdk8, openjdk11, openjdk17, and openjdk19 that will allow the launching of virtual threads when present and enabled in the underlying JDK runtime. As such, I have to use the java.lang.reflect API to perform runtime introspection to call the virtual thread creation present as a preview in openjdk19 if it present.
Using the ABCL JSS mechanism, I can get the following pure Common Lisp solution to work, so there must be something special about the module of the runtime classloader that I don't understand. Shouldn't "--add-opens java.base/java.lang=ALL-UNNAMED" allow such access?
(let ((runnable
(java:jinterface-implementation "java.lang.Runnable" "run" (lambda ())))
(thread-factory
(java:jcall "factory"
(java:jcall "ofVirtual" (java:jnew "java.lang.Thread")))))
(java:jcall "newThread" thread-factory runnable))
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the standalone example with the following JVM options:
--enable-preview --add-opens java.base/java.lang=ALL-UNNAMED
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Process should just exit normally.
ACTUAL -
Dec 01, 2022 8:29:47 AM org.not.Reflect main
SEVERE: null
java.lang.IllegalAccessException: class org.not.Reflect cannot access a member of class java.lang.ThreadBuilders$VirtualThreadBuilder (in module java.base) with modifiers "public"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:420)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:709)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.not.Reflect.main(Reflect.java:28)
Debugging under Netbeans, the following code fails for the same
package condition: =currentClass= is =org.not.reflect=
whereas =memberClass= is
=java.lang.ThreadBuilders$VirtualThreadBuilder=.
#+begin_src java
if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
isSameClassPackage = isSameClassPackage(currentClass, memberClass);
gotIsSameClassPackage = true;
if (!isSameClassPackage) {
return false;
}
}
#+end_src
---------- BEGIN SOURCE ----------
package org.not;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Reflect {
static Object virtualThreadFactory;
static Method newThread;
public static void main(String[] args) {
try {
Class c = Class.forName("java.lang.Thread");
Method ofVirtualMethod = c.getMethod("ofVirtual");
Object threadBuilderOfVirtual = ofVirtualMethod.invoke(null);
Class factoryMethodClass = threadBuilderOfVirtual.getClass();
Method factoryMethod = factoryMethodClass.getMethod("factory");
Class virtualThreadFactoryClass = Class.forName("java.lang.ThreadBuilders$VirtualThreadFactory");
virtualThreadFactory = factoryMethod.invoke(virtualThreadFactoryClass, (Object[]) null);
newThread = virtualThreadFactory.getClass().getMethod("newThread");
} catch (ClassNotFoundException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchMethodException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None known.
FREQUENCY : always
macos openjdk-19.0.1+10
A DESCRIPTION OF THE PROBLEM :
As an implementer of < https://abcl.org >, I am trying to code a pure-Java solution that will run on openjdk8, openjdk11, openjdk17, and openjdk19 that will allow the launching of virtual threads when present and enabled in the underlying JDK runtime. As such, I have to use the java.lang.reflect API to perform runtime introspection to call the virtual thread creation present as a preview in openjdk19 if it present.
Using the ABCL JSS mechanism, I can get the following pure Common Lisp solution to work, so there must be something special about the module of the runtime classloader that I don't understand. Shouldn't "--add-opens java.base/java.lang=ALL-UNNAMED" allow such access?
(let ((runnable
(java:jinterface-implementation "java.lang.Runnable" "run" (lambda ())))
(thread-factory
(java:jcall "factory"
(java:jcall "ofVirtual" (java:jnew "java.lang.Thread")))))
(java:jcall "newThread" thread-factory runnable))
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the standalone example with the following JVM options:
--enable-preview --add-opens java.base/java.lang=ALL-UNNAMED
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Process should just exit normally.
ACTUAL -
Dec 01, 2022 8:29:47 AM org.not.Reflect main
SEVERE: null
java.lang.IllegalAccessException: class org.not.Reflect cannot access a member of class java.lang.ThreadBuilders$VirtualThreadBuilder (in module java.base) with modifiers "public"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:420)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:709)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.not.Reflect.main(Reflect.java:28)
Debugging under Netbeans, the following code fails for the same
package condition: =currentClass= is =org.not.reflect=
whereas =memberClass= is
=java.lang.ThreadBuilders$VirtualThreadBuilder=.
#+begin_src java
if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
isSameClassPackage = isSameClassPackage(currentClass, memberClass);
gotIsSameClassPackage = true;
if (!isSameClassPackage) {
return false;
}
}
#+end_src
---------- BEGIN SOURCE ----------
package org.not;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Reflect {
static Object virtualThreadFactory;
static Method newThread;
public static void main(String[] args) {
try {
Class c = Class.forName("java.lang.Thread");
Method ofVirtualMethod = c.getMethod("ofVirtual");
Object threadBuilderOfVirtual = ofVirtualMethod.invoke(null);
Class factoryMethodClass = threadBuilderOfVirtual.getClass();
Method factoryMethod = factoryMethodClass.getMethod("factory");
Class virtualThreadFactoryClass = Class.forName("java.lang.ThreadBuilders$VirtualThreadFactory");
virtualThreadFactory = factoryMethod.invoke(virtualThreadFactoryClass, (Object[]) null);
newThread = virtualThreadFactory.getClass().getMethod("newThread");
} catch (ClassNotFoundException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchMethodException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(Reflect.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None known.
FREQUENCY : always