3
3
import java .io .IOException ;
4
4
import java .util .Arrays ;
5
5
import java .util .Collections ;
6
- import java .util .HashMap ;
7
6
import java .util .HashSet ;
7
+ import java .util .LinkedHashMap ;
8
+ import java .util .LinkedHashSet ;
8
9
import java .util .Map ;
9
10
import java .util .Set ;
10
11
import lombok .extern .slf4j .Slf4j ;
@@ -26,15 +27,17 @@ public class HelperInjector implements Transformer {
26
27
* Construct HelperInjector.
27
28
*
28
29
* @param helperClassNames binary names of the helper classes to inject. These class names must be
29
- * resolvable by the classloader returned by DDAdvice#getAgentClassLoader()
30
+ * resolvable by the classloader returned by DDAdvice#getAgentClassLoader(). Classes are
31
+ * injected in the order provided. This is important if there is interdependency between
32
+ * helper classes that requires them to be injected in a specific order.
30
33
*/
31
34
public HelperInjector (final String ... helperClassNames ) {
32
- this .helperClassNames = new HashSet <>(Arrays .asList (helperClassNames ));
35
+ this .helperClassNames = new LinkedHashSet <>(Arrays .asList (helperClassNames ));
33
36
}
34
37
35
38
private synchronized Map <TypeDescription , byte []> getHelperMap () throws IOException {
36
39
if (helperMap == null ) {
37
- helperMap = new HashMap <>(helperClassNames .size ());
40
+ helperMap = new LinkedHashMap <>(helperClassNames .size ());
38
41
for (final String helperName : helperClassNames ) {
39
42
final ClassFileLocator locator =
40
43
ClassFileLocator .ForClassLoader .of (Utils .getAgentClassLoader ());
@@ -58,7 +61,29 @@ public DynamicType.Builder<?> transform(
58
61
synchronized (this ) {
59
62
if (!injectedClassLoaders .contains (classLoader )) {
60
63
try {
61
- new ClassInjector .UsingReflection (classLoader ).inject (getHelperMap ());
64
+ final Map <TypeDescription , byte []> helperMap = getHelperMap ();
65
+ final Set <String > existingClasses = new HashSet <>();
66
+ final ClassLoader systemCL = ClassLoader .getSystemClassLoader ();
67
+ if (!classLoader .equals (systemCL )) {
68
+ // Build a list of existing helper classes.
69
+ for (final TypeDescription def : helperMap .keySet ()) {
70
+ final String name = def .getName ();
71
+ if (Utils .isClassLoaded (name , systemCL )) {
72
+ existingClasses .add (name );
73
+ }
74
+ }
75
+ }
76
+ new ClassInjector .UsingReflection (classLoader ).inject (helperMap );
77
+ if (!classLoader .equals (systemCL )) {
78
+ for (final TypeDescription def : helperMap .keySet ()) {
79
+ // Ensure we didn't add any helper classes to the system CL.
80
+ final String name = def .getName ();
81
+ if (!existingClasses .contains (name ) && Utils .isClassLoaded (name , systemCL )) {
82
+ throw new IllegalStateException (
83
+ "Class was erroneously loaded on the System classloader: " + name );
84
+ }
85
+ }
86
+ }
62
87
} catch (final Exception e ) {
63
88
log .error ("Failed to inject helper classes into " + classLoader , e );
64
89
throw new RuntimeException (e );
0 commit comments