5
5
package org .hibernate .bytecode .enhance .internal .bytebuddy ;
6
6
7
7
import java .io .IOException ;
8
+ import java .util .HashMap ;
8
9
import java .util .Objects ;
9
- import java .util .concurrent .ConcurrentHashMap ;
10
10
11
11
import net .bytebuddy .dynamic .ClassFileLocator ;
12
12
13
13
/**
14
14
* Allows wrapping another ClassFileLocator to add the ability to define
15
15
* resolution overrides for specific resources.
16
+ * This is useful when enhancing entities and we need to process an
17
+ * input byte array representing the bytecode of the entity, and some
18
+ * external party is providing the byte array explicitly, avoiding for
19
+ * us having to load it from the classloader.
20
+ * We'll still need to load several other symbols from a parent @{@link ClassFileLocator}
21
+ * (typically based on the classloader), but need to return the provided
22
+ * byte array for some selected resources.
23
+ * Any override is scoped to the current thread; this is to avoid
24
+ * interference among threads in systems which perform parallel
25
+ * class enhancement, for example containers requiring "on the fly"
26
+ * transformation of classes as they are being loaded will often
27
+ * perform such operations concurrently.
16
28
*/
17
- public final class OverridingClassFileLocator implements ClassFileLocator {
29
+ final class OverridingClassFileLocator implements ClassFileLocator {
18
30
19
- private final ConcurrentHashMap < String , Resolution > registeredResolutions = new ConcurrentHashMap <>();
31
+ private final ThreadLocal < HashMap < String , Resolution >> registeredResolutions = ThreadLocal . withInitial ( () -> new HashMap <>() );
20
32
private final ClassFileLocator parent ;
21
33
22
- public OverridingClassFileLocator (final ClassFileLocator parent ) {
34
+ /**
35
+ * @param parent the @{@link ClassFileLocator} which will be used to load any resource which wasn't explicitly registered as an override.
36
+ */
37
+ OverridingClassFileLocator (final ClassFileLocator parent ) {
23
38
this .parent = Objects .requireNonNull ( parent );
24
39
}
25
40
26
41
@ Override
27
42
public Resolution locate (final String name ) throws IOException {
28
- final Resolution resolution = registeredResolutions .get ( name );
43
+ final Resolution resolution = getLocalMap () .get ( name );
29
44
if ( resolution != null ) {
30
45
return resolution ;
31
46
}
@@ -34,17 +49,32 @@ public Resolution locate(final String name) throws IOException {
34
49
}
35
50
}
36
51
52
+ private HashMap <String , Resolution > getLocalMap () {
53
+ return registeredResolutions .get ();
54
+ }
55
+
37
56
@ Override
38
- public void close () throws IOException {
39
- //Nothing to do: we're not responsible for parent
57
+ public void close () {
58
+ registeredResolutions . remove ();
40
59
}
41
60
61
+ /**
62
+ * Registers an explicit resolution override
63
+ *
64
+ * @param className
65
+ * @param explicit
66
+ */
42
67
void put (String className , Resolution .Explicit explicit ) {
43
- registeredResolutions .put ( className , explicit );
68
+ getLocalMap () .put ( className , explicit );
44
69
}
45
70
71
+ /**
72
+ * Removes an explicit resolution override
73
+ *
74
+ * @param className
75
+ */
46
76
void remove (String className ) {
47
- registeredResolutions .remove ( className );
77
+ getLocalMap () .remove ( className );
48
78
}
49
79
50
80
}
0 commit comments