title: Modularity issues with javaagent in Java 9
body: <p>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.</p>
  <p>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.</p>
  <p>Java command line options used are -Xbootclasspath/a:&quot;path-to-agent.jar&quot; and -javaagent:path-to-agent.jar</p>
  <pre><code>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
  </code></pre>
  <p>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</p>
  <pre><code>1) -Xbootclasspath/a:&quot;path-to-agent.jar&quot;
  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
  </code></pre>
  <p>and agent jar file has below contents in it's manifest file.</p>
  <pre><code>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
  </code></pre>
  <p>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.</p>
  <pre><code>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: &quot;org/eclipse/jetty/start/Main&quot;
  </code></pre>