3232import java .io .IOException ;
3333import java .io .PrintWriter ;
3434import java .util .*;
35+ import java .util .concurrent .ConcurrentHashMap ;
36+ import java .util .concurrent .ConcurrentMap ;
3537
3638import static net .openhft .compiler .CompilerUtils .*;
3739
@@ -48,8 +50,7 @@ public class CachedCompiler implements Closeable {
4850 @ Nullable
4951 private final File classDir ;
5052
51- private final Map <String , JavaFileObject > javaFileObjects =
52- new HashMap <String , JavaFileObject >();
53+ private final ConcurrentMap <String , JavaFileObject > javaFileObjects = new ConcurrentHashMap <>();
5354
5455 public CachedCompiler (@ Nullable File sourceDir , @ Nullable File classDir ) {
5556 this .sourceDir = sourceDir ;
@@ -97,7 +98,7 @@ Map<String, byte[]> compileFromJava(@NotNull String className,
9798
9899 } else {
99100 javaFileObjects .put (className , new JavaSourceFromString (className , javaCode ));
100- compilationUnits = javaFileObjects .values ();
101+ compilationUnits = new ArrayList <>( javaFileObjects .values ()); // To prevent CME from compiler code
101102 }
102103 // reuse the same file manager to allow caching of jar files
103104 List <String > options = Arrays .asList ("-g" , "-nowarn" );
@@ -109,7 +110,7 @@ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
109110 }
110111 }
111112 }, options , null , compilationUnits ).call ();
112- Map < String , byte []> result = fileManager . getAllBuffers ();
113+
113114 if (!ok ) {
114115 // compilation error, so we want to exclude this file from future compilation passes
115116 if (sourceDir == null )
@@ -118,7 +119,11 @@ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
118119 // nothing to return due to compiler error
119120 return Collections .emptyMap ();
120121 }
121- return result ;
122+ else {
123+ Map <String , byte []> result = fileManager .getAllBuffers ();
124+
125+ return result ;
126+ }
122127 }
123128
124129 public Class loadFromJava (@ NotNull ClassLoader classLoader ,
@@ -143,7 +148,8 @@ public Class loadFromJava(@NotNull ClassLoader classLoader,
143148 StandardJavaFileManager standardJavaFileManager = s_compiler .getStandardFileManager (null , null , null );
144149 fileManagerMap .put (classLoader , fileManager = new MyJavaFileManager (standardJavaFileManager ));
145150 }
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 ()) {
147153 String className2 = entry .getKey ();
148154 synchronized (loadedClassesMap ) {
149155 if (loadedClasses .containsKey (className2 ))
@@ -157,9 +163,17 @@ public Class loadFromJava(@NotNull ClassLoader classLoader,
157163 LOG .info ("Updated {} in {}" , className2 , classDir );
158164 }
159165 }
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+ }
163177 }
164178 }
165179 synchronized (loadedClassesMap ) {
0 commit comments