LWJGLX/debug

Java 9 Compatibility

gudenau opened this issue · 14 comments

When attempting to use this library on Java 9 it throws an exception because it can not access "ClassLoader.defineClass".

java.lang.AssertionError: Could not find method: ClassLoader.defineClass
	at lwjglx.debug@1.0.0/org.lwjglx.debug.ClassUtils.<clinit>(ClassUtils.java:39)
	at lwjglx.debug@1.0.0/org.lwjglx.debug.InterceptClassGenerator.generate(InterceptClassGenerator.java:348)
	at lwjglx.debug@1.0.0/org.lwjglx.debug.Agent.transform_(Agent.java:182)
	at lwjglx.debug@1.0.0/org.lwjglx.debug.Agent.transform(Agent.java:70)
	at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
	at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
	at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:550)
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1086)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
	at net.gudenau.ScriptKiddie/net.gudenau.scriptkiddie.start.Start.main(Start.java:7)
java.lang.NoClassDefFoundError: Could not initialize class org.lwjglx.debug.ClassUtils
	at lwjglx.debug@1.0.0/org.lwjglx.debug.InterceptClassGenerator.generate(InterceptClassGenerator.java:348)
	at lwjglx.debug@1.0.0/org.lwjglx.debug.Agent.transform_(Agent.java:182)
	at lwjglx.debug@1.0.0/org.lwjglx.debug.Agent.transform(Agent.java:70)
	at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
	at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
	at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:550)
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1086)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
	[my stuff]

Cannot reproduce. Running Java 9.0.4 with java -javaagent:lwjglx-debug-1.0.0.jar -cp your/dependencies.jar -jar yourapp.jar works flawlessly.

Please write the exact command line you are / or your IDE is using to start the application.

Are you using a module-info.java?

I did the following:

  1. Copy the Getting Started Hello World app from lwjgl.org/guide HelloWorld.java under /src/java9test/HelloWorld.java
  2. Create a module-info.java under /src/module-info.java with the following exact contents:
module java9test {
	requires org.lwjgl;
	requires org.lwjgl.glfw;
	requires org.lwjgl.opengl;
	requires org.lwjgl.natives;
	requires org.lwjgl.glfw.natives;
	requires org.lwjgl.opengl.natives;
}
  1. Downloaded the latest lwjgl jars (include lwjglx-debug) as a zip file from lwjgl.org/customize and copied them under /deps
  2. Compiled the application using this exact command line: javac -d out -p deps\ src\java9test\HelloWorld.java src\module-info.java
  3. Ran the application using this exact command line: java -javaagent:lwjglx-debug-1.0.0.jar -p out\;deps\ -m java9test/java9test.HelloWorld

And it worked without any errors.

Again, please provide all necessary information to reproduce the error, like the ones I mentioned above.

What you probably did was to add lwjglx-debug-1.0.0.jar to the module path of your application.
At least I could get that exception stacktrace by doing that.
Adding lwjglx-debug to the module path however does not make any sense, because first, lwjglx-debug is not a library. It is an implementation of a Java Agent using the JVM's Instrumentation API. And second, it is not a runtime dependency of your application. No class in your application statically or dynamically depend on it. You also won't include lwjglx-debug into a distribution of your application via JDK's jlink utility, since it is merely used as a development-time tool.
It is a Javaagent which you attach to a JVM via the required -javaagent command line argument. This alone makes it not a module of your application in the Java 9 module sense, but instead an orthogonal "instrumentation" hooking into the JVM's classloading process.

Java call:
"C:\Program Files\Java\jdk-9.0.4\bin\java" -javaagent:../../3rdparty/lwjgl3/3.1.5/lwjglx-debug-1.0.0.jar -javaagent:D:\JetBrains\apps\IDEA-U\ch-0\173.4548.28\lib\idea_rt.jar=54890:D:\JetBrains\apps\IDEA-U\ch-0\173.4548.28\bin -Dfile.encoding=UTF-8 -p Z:\java\game[redacted]\target\classes;Z:\java\3rdparty\lwjgl3\3.1.5\lwjglx-debug-1.0.0.jar;Z:\java\library\Annotations\target\classes;Z:\java\library\Cleanup\target\classes;Z:\java\library\EventHandler\target\classes;Z:\java\3rdparty\gson\master-8445689\gson\target\classes;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl\3.1.5\lwjgl-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-assimp\3.1.5\lwjgl-assimp-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-glfw\3.1.5\lwjgl-glfw-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-jemalloc\3.1.5\lwjgl-jemalloc-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-lz4\3.1.5\lwjgl-lz4-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-openal\3.1.5\lwjgl-openal-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-opencl\3.1.5\lwjgl-opencl-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-opengl\3.1.5\lwjgl-opengl-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-rpmalloc\3.1.5\lwjgl-rpmalloc-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-sse\3.1.5\lwjgl-sse-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-stb\3.1.5\lwjgl-stb-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-xxhash\3.1.5\lwjgl-xxhash-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-zstd\3.1.5\lwjgl-zstd-3.1.5.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl\3.1.5\lwjgl-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-assimp\3.1.5\lwjgl-assimp-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-glfw\3.1.5\lwjgl-glfw-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-jemalloc\3.1.5\lwjgl-jemalloc-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-lz4\3.1.5\lwjgl-lz4-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-openal\3.1.5\lwjgl-openal-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-opengl\3.1.5\lwjgl-opengl-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-rpmalloc\3.1.5\lwjgl-rpmalloc-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-sse\3.1.5\lwjgl-sse-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-stb\3.1.5\lwjgl-stb-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-xxhash\3.1.5\lwjgl-xxhash-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\lwjgl\lwjgl-zstd\3.1.5\lwjgl-zstd-3.1.5-natives-windows.jar;C:\Users\gudenau.m2\repository\org\joml\joml\1.9.8\joml-1.9.8.jar -m net.gudenau.[redacted]/net.gudenau.[redacted].start.Start

module-info.java

module net.gudenau.[redacted]{
    requires com.google.gson;
    
    requires org.lwjgl.glfw;
    requires org.lwjgl.openal;
    requires org.lwjgl.opengl;
    
    requires lwjglx.debug;
    
    requires net.gudenau.lib.Annotations;
    requires net.gudenau.lib.Cleanup;
    requires net.gudenau.lib.EventHandler;
    
    requires java.desktop;
    
    exports net.gudenau.[redacted].start;
}

Yes, as I expected. Following my explanations #17 (comment) above, your task is now to remove requires lwjglx.debug; from the module-info.java file and also from IntelliJ IDEA's module path (which it forwards to javac and java as -p). Then it will work.
Additionally, JOML is a Java 9 module, so add the missing requires org.joml; to the module-info.java file.

If I remove the requires it makes it so that my program can not set the main GLFW thread, which causes an exception to be thrown any time my GLFW thread does anything.

Please show the exception stacktrace. It is highly likely that this exception means that lwjglx-debug is actually working fine and hints you to errors in your code!

java.lang.RuntimeException: Failed to execute event
	at net.gudenau.lib.EventHandler/net.gudenau.lib.eventhandler.EventHandler.handler(EventHandler.java:57)
	at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.IllegalStateException: Method glfwInit was called in thread [Thread[GLFW Event Thread,5,main]] which is not the main thread.
	at net.gudenau.[redacted]/net.gudenau.[redacted].glfw.GLFW.lambda$init$0(GLFW.java:34)
	at net.gudenau.lib.EventHandler/net.gudenau.lib.eventhandler.EventHandler$EventWrapper.execute(EventHandler.java:116)
	at net.gudenau.lib.EventHandler/net.gudenau.lib.eventhandler.EventHandler.handler(EventHandler.java:52)
	... 1 more

To solve this I have RT.mainThread = eventHandler.getThread(); in my GLFW init method to set the mainThread to be the correct one.

Please read the exception message!

Caused by: java.lang.IllegalStateException: Method glfwInit was called in thread [Thread[GLFW Event Thread,5,main]] which is not the main thread.

Which in my case the main GLFW thread is the thread that it is getting called in, I have it setup so that all the GLFW calls happen in a dedicated thread. According to the GLFW docs that I found, the main thread is whatever you call glfwInit in .

According to the GLFW docs that I found, the main thread is whatever you call glfwInit in.

Where did you read that?? The "main" thread is the main thread of the process. In the case of Java, it is the thread that calls your public static void main(String[] args) method...

Also, please read this: http://www.glfw.org/docs/latest/group__init.html#ga317aac130a235ab08c6db0834907d85e
under "Thread safety": "This function must only be called from the main thread."

How much sense would it make to say that the "main" thread is the thread that calls glfwInit() when the documentation of that very same glfwInit() mentions, that this function may only be called from the main thread??

Strange, I can not seem to find that again.

Guess I have some modifications to do.