We have a javaagent written in Java 8 that instruments application code using javassist. There is one simple ClassFileTransformer that instruments java.lang.Error class constructor to record an instantiated error. I am retransforming Error class because it is loaded much before my agent is loaded. The instrumetation code used links java.lang.Error class to classes in agent jar. As java.lang.Error is loaded by bootstrap class loader and that Error is linked to classes in agent jar, I am using -Xbootclasspath/a option to load agent classes as well using bootstrap class loader. This is working fine in Java 8.
Now to Java 9+: Now I am trying to run the same Java 8 agent in Java 9 JVM and running into modularity issues. I am still using -Xbootclasspath/a option because I still have to load the agent classes using bootstrap class loader. As with Java 9 modularity, my agent classes are loaded into unnamed module of bootstrap class loader. Though java.lang.Error class is also loaded by bootstrap class loader but it is part of java.base named module in Java 9 and I am running into below error because unnamed module is not accessible to named java.base module.
Java command line options used are -Xbootclasspath/a:"path-to-agent.jar" and -javaagent:path-to-agent.jar
javassist.CannotCompileException: [source error] no such class: com.sg.agent.ErrorRecorder
at javassist.CtBehavior.insertAfter(CtBehavior.java:877)
at javassist.CtBehavior.insertAfter(CtBehavior.java:792)
at com.sg.agent.ErrorClassTransformer.transform(ErrorClassTransformer.java:60)
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.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:157)
at com.sg.agent.SGAgent.retransformError(SGAgent.java:362)
at com.sg.agent.SGAgent.premain(SGAgent.java:346)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:500)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:512)
Caused by: compile error: no such class: com.sg.agent.ErrorRecorder
at javassist.compiler.MemberResolver.searchImports(MemberResolver.java:470)
at javassist.compiler.MemberResolver.lookupClass(MemberResolver.java:414)
at javassist.compiler.MemberResolver.lookupClassByJvmName(MemberResolver.java:321)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:683)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:157)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:46)
at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:242)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:330)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
at javassist.compiler.Javac.compileStmnt(Javac.java:567)
at javassist.CtBehavior.insertAfterAdvice(CtBehavior.java:892)
at javassist.CtBehavior.insertAfter(CtBehavior.java:851)
... 15 more
So after some googling I found there are java command line options to overcome these issues. Accordingly, now I am using these below command line options
1) -Xbootclasspath/a:"path-to-agent.jar"
2) -javaagent:path-to-agent.jar
3) --module-path path-to-agent-jar-folder
4) --add-modules sg.agent
5) --add-modules java.base
6) --add-reads java.base=sg.agent
and agent jar file has below contents in it's manifest file.
Manifest-Version: 1.0
Premain-Class: com.sg.agent.SGAgent
Can-Retransform-Classes: true
Created-By: Srinivas
Automatic-Module-Name: sg.agent
Add-Exports: module/package
Add-Opens: module/package
Boot-Class-Path: C:/Test/SGAgent.jar
and now JVM is throwing below error. From the below stacktrace it can be seen that JVM has read sg.agent as a named module but still complaining no such class: com.sg.agent.ErrorRecorder though --add-reads option gives java.base access to sg.agent. And additionally, my jetty server is not starting now.
javassist.CannotCompileException: [source error] no such class: com.sg.agent.ErrorRecorder
at sg.agent/javassist.CtBehavior.insertAfter(CtBehavior.java:877)
at sg.agent/javassist.CtBehavior.insertAfter(CtBehavior.java:792)
at sg.agent/com.sg.agent.ErrorClassTransformer.transform(ErrorClassTransformer.java:60)
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.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:157)
at sg.agent/com.sg.agent.SGAgent.retransformError(SGAgent.java:362)
at sg.agent/com.sg.agent.SGAgent.premain(SGAgent.java:346)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:500)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:512)
Caused by: compile error: no such class: com.sg.agent.ErrorRecorder
at sg.agent/javassist.compiler.MemberResolver.searchImports(MemberResolver.java:470)
at sg.agent/javassist.compiler.MemberResolver.lookupClass(MemberResolver.java:414)
at sg.agent/javassist.compiler.MemberResolver.lookupClassByJvmName(MemberResolver.java:321)
at sg.agent/javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:683)
at sg.agent/javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:157)
at sg.agent/javassist.compiler.ast.CallExpr.accept(CallExpr.java:46)
at sg.agent/javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:242)
at sg.agent/javassist.compiler.CodeGen.atStmnt(CodeGen.java:330)
at sg.agent/javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
at sg.agent/javassist.compiler.Javac.compileStmnt(Javac.java:567)
at sg.agent/javassist.CtBehavior.insertAfterAdvice(CtBehavior.java:892)
at sg.agent/javassist.CtBehavior.insertAfter(CtBehavior.java:851)
... 15 more
Error: LinkageError occurred while loading main class org.eclipse.jetty.start.Main
java.lang.LinkageError: loader (instance of jdk/internal/loader/ClassLoaders$AppClassLoader): attempted duplicate class definition for name: "org/eclipse/jetty/start/Main"