88import java .io .IOException ;
99import java .lang .ref .WeakReference ;
1010import java .security .SecureClassLoader ;
11- import java .util .ArrayList ;
1211import java .util .Arrays ;
1312import java .util .Collection ;
1413import java .util .Collections ;
1817import java .util .List ;
1918import java .util .Map ;
2019import java .util .Set ;
20+ import java .util .concurrent .CopyOnWriteArrayList ;
2121import lombok .extern .slf4j .Slf4j ;
2222import net .bytebuddy .agent .builder .AgentBuilder .Transformer ;
2323import net .bytebuddy .description .type .TypeDescription ;
@@ -34,12 +34,11 @@ public class HelperInjector implements Transformer {
3434 new SecureClassLoader (null ) {};
3535
3636 private final Set <String > helperClassNames ;
37- private Map <TypeDescription , byte []> helperMap = null ;
38- private final WeakMap <ClassLoader , Boolean > injectedClassLoaders = newWeakMap ();
37+ private final Map <String , byte []> dynamicTypeMap = new LinkedHashMap <>();
3938
40- // Neither Module nor WeakReference implements equals or hashcode so using a list
41- private final List <WeakReference <Object >> helperModules = new ArrayList <>();
39+ private final WeakMap <ClassLoader , Boolean > injectedClassLoaders = newWeakMap ();
4240
41+ private final List <WeakReference <Object >> helperModules = new CopyOnWriteArrayList <>();
4342 /**
4443 * Construct HelperInjector.
4544 *
@@ -55,13 +54,7 @@ public HelperInjector(final String... helperClassNames) {
5554
5655 public HelperInjector (final Map <String , byte []> helperMap ) {
5756 helperClassNames = helperMap .keySet ();
58- this .helperMap = new LinkedHashMap <>(helperClassNames .size ());
59- for (final String helperName : helperClassNames ) {
60- final TypeDescription typeDesc =
61- new TypeDescription .Latent (
62- helperName , 0 , null , Collections .<TypeDescription .Generic >emptyList ());
63- this .helperMap .put (typeDesc , helperMap .get (helperName ));
64- }
57+ dynamicTypeMap .putAll (helperMap );
6558 }
6659
6760 public static HelperInjector forDynamicTypes (final Collection <DynamicType .Unloaded <?>> helpers ) {
@@ -72,20 +65,22 @@ public static HelperInjector forDynamicTypes(final Collection<DynamicType.Unload
7265 return new HelperInjector (bytes );
7366 }
7467
75- private synchronized Map <TypeDescription , byte []> getHelperMap () throws IOException {
76- if (helperMap == null ) {
77- helperMap = new LinkedHashMap <>(helperClassNames .size ());
78- for (final String helperName : helperClassNames ) {
79- final ClassFileLocator locator =
80- ClassFileLocator .ForClassLoader .of (Utils .getAgentClassLoader ());
81- final byte [] classBytes = locator .locate (helperName ).resolve ();
82- final TypeDescription typeDesc =
83- new TypeDescription .Latent (
84- helperName , 0 , null , Collections .<TypeDescription .Generic >emptyList ());
85- helperMap .put (typeDesc , classBytes );
68+ private Map <String , byte []> getHelperMap () throws IOException {
69+ if (dynamicTypeMap .isEmpty ()) {
70+ final Map <String , byte []> classnameToBytes = new LinkedHashMap <>();
71+
72+ final ClassFileLocator locator =
73+ ClassFileLocator .ForClassLoader .of (Utils .getAgentClassLoader ());
74+
75+ for (final String helperClassName : helperClassNames ) {
76+ final byte [] classBytes = locator .locate (helperClassName ).resolve ();
77+ classnameToBytes .put (helperClassName , classBytes );
8678 }
79+
80+ return classnameToBytes ;
81+ } else {
82+ return dynamicTypeMap ;
8783 }
88- return helperMap ;
8984 }
9085
9186 @ Override
@@ -95,55 +90,53 @@ public DynamicType.Builder<?> transform(
9590 ClassLoader classLoader ,
9691 final JavaModule module ) {
9792 if (!helperClassNames .isEmpty ()) {
98- synchronized (this ) {
99- if (classLoader == BOOTSTRAP_CLASSLOADER ) {
100- classLoader = BOOTSTRAP_CLASSLOADER_PLACEHOLDER ;
101- }
102- if (!injectedClassLoaders .containsKey (classLoader )) {
103- try {
104- final Map <TypeDescription , byte []> helperMap = getHelperMap ();
105- log .debug ("Injecting classes onto classloader {} -> {}" , classLoader , helperClassNames );
106- if (classLoader == BOOTSTRAP_CLASSLOADER_PLACEHOLDER ) {
107- final Map <TypeDescription , Class <?>> injected =
108- ClassInjector .UsingInstrumentation .of (
109- new File (System .getProperty ("java.io.tmpdir" )),
110- ClassInjector .UsingInstrumentation .Target .BOOTSTRAP ,
111- AgentInstaller .getInstrumentation ())
112- .inject (helperMap );
113- for (final TypeDescription desc : injected .keySet ()) {
114- final Class <?> injectedClass =
115- Class .forName (desc .getName (), false , Utils .getBootstrapProxy ());
116- if (JavaModule .isSupported ()) {
117- helperModules .add (new WeakReference <>(JavaModule .ofType (injectedClass ).unwrap ()));
118- }
119- }
120- } else {
121- final Map <TypeDescription , Class <?>> classMap =
122- new ClassInjector .UsingReflection (classLoader ).inject (helperMap );
123- if (JavaModule .isSupported ()) {
124- for (final Class <?> injectedClass : classMap .values ()) {
125- helperModules .add (new WeakReference <>(JavaModule .ofType (injectedClass ).unwrap ()));
126- }
127- }
128- }
129- } catch (final Exception e ) {
130- log .error (
131- "Error preparing helpers for "
132- + typeDescription
133- + ". Failed to inject helper classes into instance "
134- + classLoader
135- + " of type "
136- + (classLoader == BOOTSTRAP_CLASSLOADER_PLACEHOLDER
137- ? "<bootstrap>"
138- : classLoader .getClass ().getName ()),
139- e );
140- throw new RuntimeException (e );
93+ if (classLoader == BOOTSTRAP_CLASSLOADER ) {
94+ classLoader = BOOTSTRAP_CLASSLOADER_PLACEHOLDER ;
95+ }
96+
97+ if (!injectedClassLoaders .containsKey (classLoader )) {
98+ try {
99+ log .debug ("Injecting classes onto classloader {} -> {}" , classLoader , helperClassNames );
100+
101+ final Map <String , byte []> classnameToBytes = getHelperMap ();
102+ final Map <String , Class <?>> classes ;
103+ if (classLoader == BOOTSTRAP_CLASSLOADER_PLACEHOLDER ) {
104+ classes =
105+ ClassInjector .UsingInstrumentation .of (
106+ new File (System .getProperty ("java.io.tmpdir" )),
107+ ClassInjector .UsingInstrumentation .Target .BOOTSTRAP ,
108+ AgentInstaller .getInstrumentation ())
109+ .injectRaw (classnameToBytes );
110+ } else {
111+ classes = new ClassInjector .UsingReflection (classLoader ).injectRaw (classnameToBytes );
141112 }
142- injectedClassLoaders .put (classLoader , true );
113+
114+ // All datadog helper classes are in the unnamed module
115+ // And there's exactly one unnamed module per classloader
116+ // Use the module of the first class for convenience
117+ if (JavaModule .isSupported ()) {
118+ final JavaModule javaModule = JavaModule .ofType (classes .values ().iterator ().next ());
119+ helperModules .add (new WeakReference <>(javaModule .unwrap ()));
120+ }
121+ } catch (final Exception e ) {
122+ final String classLoaderType =
123+ classLoader == BOOTSTRAP_CLASSLOADER_PLACEHOLDER
124+ ? "<bootstrap>"
125+ : classLoader .getClass ().getName ();
126+
127+ log .error (
128+ "Error preparing helpers for {}. Failed to inject helper classes into instance {} of type {}" ,
129+ typeDescription ,
130+ classLoader ,
131+ classLoaderType ,
132+ e );
133+ throw new RuntimeException (e );
143134 }
144135
145- ensureModuleCanReadHelperModules ( module );
136+ injectedClassLoaders . put ( classLoader , true );
146137 }
138+
139+ ensureModuleCanReadHelperModules (module );
147140 }
148141 return builder ;
149142 }
0 commit comments