5555public final class JctCompilationFactoryImpl implements JctCompilationFactory {
5656
5757 private static final Logger LOGGER = LoggerFactory .getLogger (JctCompilationFactoryImpl .class );
58- private static final String THE_ROOT_PACKAGE = "" ;
58+ private static final String ROOT_PACKAGE = "" ;
5959
6060 private final JctCompiler compiler ;
6161
6262 public JctCompilationFactoryImpl (JctCompiler compiler ) {
63- this .compiler = compiler ;
63+ this .compiler = requireNonNull ( compiler ) ;
6464 }
6565
6666 @ Override
@@ -71,6 +71,7 @@ public JctCompilation createCompilation(
7171 @ Nullable Collection <String > classNames
7272 ) {
7373 try {
74+ final var startPreparation = System .nanoTime ();
7475 var compilationUnits = findFilteredCompilationUnits (fileManager , classNames );
7576
7677 if (compilationUnits .isEmpty ()) {
@@ -81,16 +82,18 @@ public JctCompilation createCompilation(
8182 var writer = TeeWriter .wrapOutputStream (System .out , compiler .getLogCharset ());
8283
8384 var diagnosticListener = new TracingDiagnosticListener <>(
84- compiler .getDiagnosticLoggingMode () != LoggingMode .DISABLED ,
85- compiler .getDiagnosticLoggingMode () == LoggingMode .STACKTRACES
85+ /* enabled */ compiler .getDiagnosticLoggingMode () != LoggingMode .DISABLED ,
86+ /* stackTraces */ compiler .getDiagnosticLoggingMode () == LoggingMode .STACKTRACES
8687 );
8788
89+ // We work out the classes to annotation process rather than relying on the
90+ // compiler to do this, as we retain more control by doing so.
8891 var task = jsr199Compiler .getTask (
8992 writer ,
9093 fileManager ,
9194 diagnosticListener ,
9295 flags ,
93- null ,
96+ /* classes */ null ,
9497 compilationUnits
9598 );
9699
@@ -101,20 +104,23 @@ public JctCompilation createCompilation(
101104
102105 task .setLocale (compiler .getLocale ());
103106
107+ var preparationExecutionTimeMs = timeDeltaMs (startPreparation );
108+
104109 LOGGER
105110 .atInfo ()
106- .setMessage ("Starting compilation with {} (found {} compilation units)" )
111+ .setMessage ("Starting compilation with {} (found {} compilation units in approx {}ms )" )
107112 .addArgument (compiler ::getName )
108113 .addArgument (compilationUnits ::size )
114+ .addArgument (preparationExecutionTimeMs )
109115 .log ();
110116
111- var start = System .nanoTime ();
117+ var startCompilation = System .nanoTime ();
112118 var success = requireNonNull (
113119 task .call (),
114120 () -> "Compiler " + compiler .getName ()
115121 + " task .call() method returned null unexpectedly!"
116122 );
117- var delta = ( System . nanoTime () - start ) / 1_000_000L ;
123+ var compilationExecutionTimeMs = timeDeltaMs ( startCompilation ) ;
118124
119125 // Ensure we commit the writer contents to the wrapped output stream in full.
120126 writer .flush ();
@@ -124,8 +130,11 @@ public JctCompilation createCompilation(
124130 .setMessage ("Compilation with {} {} after approximately {}ms (roughly {} classes/sec)" )
125131 .addArgument (compiler ::getName )
126132 .addArgument (() -> success ? "completed successfully" : "failed" )
127- .addArgument (delta )
128- .addArgument (() -> String .format ("%.2f" , 1000.0 * compilationUnits .size () / delta ))
133+ .addArgument (compilationExecutionTimeMs )
134+ .addArgument (() -> String .format (
135+ "%.2f" ,
136+ (1000.0 * compilationUnits .size ()) / compilationExecutionTimeMs
137+ ))
129138 .log ();
130139
131140 return JctCompilationImpl
@@ -177,8 +186,9 @@ private Collection<JavaFileObject> findFilteredCompilationUnits(
177186 private Collection <JavaFileObject > findCompilationUnits (
178187 JctFileManager fileManager
179188 ) throws IOException {
180- var locations = IterableUtils
181- .flatten (fileManager .listLocationsForModules (StandardLocation .MODULE_SOURCE_PATH ));
189+ // If we use modules, we may have more than one module location to search for.
190+ var deepLocations = fileManager .listLocationsForModules (StandardLocation .MODULE_SOURCE_PATH );
191+ var locations = IterableUtils .flatten (deepLocations );
182192
183193 if (locations .isEmpty ()) {
184194 LOGGER .info (
@@ -192,30 +202,24 @@ private Collection<JavaFileObject> findCompilationUnits(
192202 }
193203
194204 // Use a linked hash set to retain order for consistency.
195- var objects = new LinkedHashSet <JavaFileObject >();
205+ var fileObjects = new LinkedHashSet <JavaFileObject >();
206+ var kinds = Set .of (Kind .SOURCE );
196207
197208 for (var location : locations ) {
198- objects .addAll (fileManager .list (location , THE_ROOT_PACKAGE , Set .of (Kind .SOURCE ), true ));
209+ var nextFileObjects = fileManager .list (location , ROOT_PACKAGE , kinds , true );
210+ fileObjects .addAll (nextFileObjects );
199211 }
200212
201- return objects ;
213+ return fileObjects ;
202214 }
203215
204216 private Collection <JavaFileObject > filterCompilationUnitsByBinaryNames (
205217 Collection <JavaFileObject > compilationUnits ,
206218 Collection <String > classNames
207219 ) {
208- // We need to access the binary name of each file object. This forces us
209- // to cast to PathFileObject in an unsafe way as the standard JavaFileObject
210- // interface does not expose this information consistently.
211- // All JCT implementations should be using PathFileObject types internally
212- // anyway, so this should be fine as a hack for now. In the future I may decide
213- // to add an additional set of methods to PathFileObject to expose searching
214- // for PathFileObjects directly to prevent the cast back to JavaFileObject that
215- // makes us need this hsck.
216220 var binaryNamesToCompilationUnits = compilationUnits
217221 .stream ()
218- .map (PathFileObject . class :: cast )
222+ .map (this :: forceUpcastJavaFileObject )
219223 .filter (fo -> classNames .contains (fo .getBinaryName ()))
220224 .collect (Collectors .toMap (PathFileObject ::getBinaryName , JavaFileObject .class ::cast ));
221225
@@ -228,11 +232,30 @@ private Collection<JavaFileObject> filterCompilationUnitsByBinaryNames(
228232 }
229233
230234 LOGGER .atDebug ()
231- .setMessage ("Filtered {} candidate compilation units down to {} final compilation units " )
235+ .setMessage ("Filtered {} candidate compilation units down to {} via class whitelist {} " )
232236 .addArgument (compilationUnits ::size )
233237 .addArgument (binaryNamesToCompilationUnits ::size )
238+ .addArgument (classNames )
234239 .log ();
235240
236241 return binaryNamesToCompilationUnits .values ();
237242 }
243+
244+ // We need to access the binary name of each file object. This forces us
245+ // to cast to PathFileObject in an unsafe way as the standard JavaFileObject
246+ // interface does not expose this information consistently.
247+ // All JCT implementations should be using PathFileObject types internally
248+ // anyway, so this should be fine as a hack for now. In the future I may decide
249+ // to add an additional set of methods to PathFileObject to expose searching
250+ // for PathFileObjects directly to prevent the cast back to JavaFileObject that
251+ // makes us need this hack.
252+ private PathFileObject forceUpcastJavaFileObject (JavaFileObject jfo ) {
253+ assert jfo instanceof PathFileObject
254+ : "Unexpected state: JavaFileObject " + jfo + " was not a PathFileObject!" ;
255+ return (PathFileObject ) jfo ;
256+ }
257+
258+ private static long timeDeltaMs (long startNanos ) {
259+ return (System .nanoTime () - startNanos ) / 1_000_000 ;
260+ }
238261}
0 commit comments