32
32
import java .io .IOException ;
33
33
import java .io .PrintWriter ;
34
34
import java .util .*;
35
+ import java .util .concurrent .ConcurrentHashMap ;
36
+ import java .util .concurrent .ConcurrentMap ;
35
37
36
38
import static net .openhft .compiler .CompilerUtils .*;
37
39
@@ -48,8 +50,7 @@ public class CachedCompiler implements Closeable {
48
50
@ Nullable
49
51
private final File classDir ;
50
52
51
- private final Map <String , JavaFileObject > javaFileObjects =
52
- new HashMap <String , JavaFileObject >();
53
+ private final ConcurrentMap <String , JavaFileObject > javaFileObjects = new ConcurrentHashMap <>();
53
54
54
55
public CachedCompiler (@ Nullable File sourceDir , @ Nullable File classDir ) {
55
56
this .sourceDir = sourceDir ;
@@ -97,7 +98,7 @@ Map<String, byte[]> compileFromJava(@NotNull String className,
97
98
98
99
} else {
99
100
javaFileObjects .put (className , new JavaSourceFromString (className , javaCode ));
100
- compilationUnits = javaFileObjects .values ();
101
+ compilationUnits = new ArrayList <>( javaFileObjects .values ()); // To prevent CME from compiler code
101
102
}
102
103
// reuse the same file manager to allow caching of jar files
103
104
List <String > options = Arrays .asList ("-g" , "-nowarn" );
@@ -109,7 +110,7 @@ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
109
110
}
110
111
}
111
112
}, options , null , compilationUnits ).call ();
112
- Map < String , byte []> result = fileManager . getAllBuffers ();
113
+
113
114
if (!ok ) {
114
115
// compilation error, so we want to exclude this file from future compilation passes
115
116
if (sourceDir == null )
@@ -118,7 +119,11 @@ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
118
119
// nothing to return due to compiler error
119
120
return Collections .emptyMap ();
120
121
}
121
- return result ;
122
+ else {
123
+ Map <String , byte []> result = fileManager .getAllBuffers ();
124
+
125
+ return result ;
126
+ }
122
127
}
123
128
124
129
public Class loadFromJava (@ NotNull ClassLoader classLoader ,
@@ -143,7 +148,8 @@ public Class loadFromJava(@NotNull ClassLoader classLoader,
143
148
StandardJavaFileManager standardJavaFileManager = s_compiler .getStandardFileManager (null , null , null );
144
149
fileManagerMap .put (classLoader , fileManager = new MyJavaFileManager (standardJavaFileManager ));
145
150
}
146
- for (Map .Entry <String , byte []> entry : compileFromJava (className , javaCode , printWriter , fileManager ).entrySet ()) {
151
+ final Map <String , byte []> compiled = compileFromJava (className , javaCode , printWriter , fileManager );
152
+ for (Map .Entry <String , byte []> entry : compiled .entrySet ()) {
147
153
String className2 = entry .getKey ();
148
154
synchronized (loadedClassesMap ) {
149
155
if (loadedClasses .containsKey (className2 ))
@@ -157,9 +163,17 @@ public Class loadFromJava(@NotNull ClassLoader classLoader,
157
163
LOG .info ("Updated {} in {}" , className2 , classDir );
158
164
}
159
165
}
160
- Class clazz2 = CompilerUtils .defineClass (classLoader , className2 , bytes );
161
- synchronized (loadedClassesMap ) {
162
- loadedClasses .put (className2 , clazz2 );
166
+
167
+ synchronized (className2 .intern ()) { // To prevent duplicate class definition error
168
+ synchronized (loadedClassesMap ) {
169
+ if (loadedClasses .containsKey (className2 ))
170
+ continue ;
171
+ }
172
+
173
+ Class <?> clazz2 = CompilerUtils .defineClass (classLoader , className2 , bytes );
174
+ synchronized (loadedClassesMap ) {
175
+ loadedClasses .put (className2 , clazz2 );
176
+ }
163
177
}
164
178
}
165
179
synchronized (loadedClassesMap ) {
0 commit comments