30
30
import org .codehaus .plexus .compiler .CompilerMessage ;
31
31
import org .codehaus .plexus .compiler .CompilerOutputStyle ;
32
32
import org .codehaus .plexus .compiler .CompilerResult ;
33
+ import org .codehaus .plexus .util .DirectoryScanner ;
33
34
import org .codehaus .plexus .util .StringUtils ;
34
35
import org .eclipse .jdt .core .compiler .CompilationProgress ;
35
36
import org .eclipse .jdt .core .compiler .batch .BatchCompiler ;
36
37
37
38
import java .io .File ;
38
- import java .io .IOException ;
39
39
import java .io .PrintWriter ;
40
40
import java .io .StringWriter ;
41
+ import java .nio .charset .Charset ;
41
42
import java .util .ArrayList ;
42
- import java .util .Collections ;
43
+ import java .util .Iterator ;
43
44
import java .util .List ;
45
+ import java .util .Locale ;
44
46
import java .util .Map ;
45
47
import java .util .Map .Entry ;
48
+ import java .util .ServiceLoader ;
46
49
import java .util .Set ;
47
50
51
+ import javax .tools .Diagnostic ;
52
+ import javax .tools .DiagnosticListener ;
53
+ import javax .tools .JavaCompiler ;
54
+ import javax .tools .JavaFileObject ;
55
+ import javax .tools .StandardJavaFileManager ;
56
+
48
57
/**
49
58
* @plexus.component role="org.codehaus.plexus.compiler.Compiler" role-hint="eclipse"
50
59
*/
@@ -61,6 +70,7 @@ public EclipseJavaCompiler()
61
70
// ----------------------------------------------------------------------
62
71
boolean errorsAsWarnings = false ;
63
72
73
+ @ Override
64
74
public CompilerResult performCompile (CompilerConfiguration config )
65
75
throws CompilerException
66
76
{
@@ -240,97 +250,166 @@ else if(extras.containsKey("-errorsAsWarnings"))
240
250
args .add ("-classpath" );
241
251
args .add (getPathString (classpathEntries ));
242
252
243
- // Compile! Send all errors to xml temp file.
244
- File errorF = null ;
245
- try
253
+ // Collect sources
254
+ List < String > allSources = new ArrayList <>() ;
255
+ for ( String source : config . getSourceLocations ())
246
256
{
247
- errorF = File .createTempFile ("ecjerr-" , ".xml" );
248
-
249
- args .add ("-log" );
250
- args .add (errorF .toString ());
251
-
252
- // Add all sources.
253
- int argCount = args .size ();
254
- for (String source : config .getSourceLocations ())
257
+ File srcFile = new File (source );
258
+ if (srcFile .exists ())
255
259
{
256
- File srcFile = new File (source );
257
- if (srcFile .exists ())
258
- {
259
- Set <String > ss = getSourceFilesForSourceRoot (config , source );
260
- args .addAll (ss );
261
- }
260
+ Set <String > ss = getSourceFilesForSourceRoot (config , source );
261
+ allSources .addAll (ss );
262
262
}
263
- args . addAll ( extraSourceDirs );
264
- if ( args . size () == argCount )
265
- {
266
- //-- Nothing to do -> bail out
267
- return new CompilerResult ( true , Collections . EMPTY_LIST );
263
+ }
264
+ for ( String extraSrcDir : extraSourceDirs ) {
265
+ File extraDir = new File ( extraSrcDir );
266
+ if ( extraDir . isDirectory ()) {
267
+ addExtraSources ( extraDir , allSources );
268
268
}
269
+ }
270
+ List <CompilerMessage > messageList = new ArrayList <>();
271
+ if (allSources .isEmpty ()) {
272
+ // -- Nothing to do -> bail out
273
+ return new CompilerResult (true , messageList );
274
+ }
269
275
270
- getLogger (). debug ( "ecj command line: " + args );
271
-
276
+ // Compile
277
+ try {
272
278
StringWriter sw = new StringWriter ();
273
279
PrintWriter devNull = new PrintWriter (sw );
274
-
275
- //BatchCompiler.compile(args.toArray(new String[args.size()]), new PrintWriter(System.err), new PrintWriter(System.out), new CompilationProgress() {
276
- boolean success = BatchCompiler .compile (args .toArray (new String [args .size ()]), devNull , devNull , new CompilationProgress () {
277
- @ Override
278
- public void begin (int i )
279
- {
280
+ JavaCompiler compiler = getEcj ();
281
+ boolean success = false ;
282
+ if (compiler != null ) {
283
+ getLogger ().debug ("Using JSR-199 EclipseCompiler" );
284
+ // ECJ JSR-199 compiles against the latest Java version it supports if no source
285
+ // version is given explicitly. BatchCompiler uses 1.3 as default. So check
286
+ // whether a source version is specified, and if not supply 1.3 explicitly.
287
+ String srcVersion = null ;
288
+ Iterator <String > allArgs = args .iterator ();
289
+ while (allArgs .hasNext ()) {
290
+ String option = allArgs .next ();
291
+ if ("-source" .equals (option ) && allArgs .hasNext ()) {
292
+ srcVersion = allArgs .next ();
293
+ break ;
294
+ }
280
295
}
281
-
282
- @ Override
283
- public void done ()
284
- {
296
+ if ( srcVersion == null ) {
297
+ getLogger (). debug ( "ecj: no source level specified, defaulting to Java 1.3" );
298
+ args . add ( "-source" );
299
+ args . add ( "1.3" );
285
300
}
301
+ final Locale defaultLocale = Locale .getDefault ();
302
+ final List <CompilerMessage > messages = messageList ;
303
+ DiagnosticListener <? super JavaFileObject > messageCollector = new DiagnosticListener <JavaFileObject >() {
304
+
305
+ @ Override
306
+ public void report (Diagnostic <? extends JavaFileObject > diagnostic ) {
307
+ // Convert to Plexus' CompilerMessage and append to messageList
308
+ String fileName = "Unknown source" ;
309
+ try {
310
+ JavaFileObject file = diagnostic .getSource ();
311
+ if (file != null ) {
312
+ fileName = file .getName ();
313
+ }
314
+ } catch (NullPointerException e ) {
315
+ // ECJ bug: diagnostic.getSource() may throw an NPE if there is no source
316
+ }
317
+ long startColumn = diagnostic .getColumnNumber ();
318
+ // endColumn may be wrong if the endPosition is not on the same line.
319
+ long endColumn = startColumn + (diagnostic .getEndPosition () - diagnostic .getStartPosition ());
320
+ CompilerMessage message = new CompilerMessage (fileName ,
321
+ convert (diagnostic .getKind ()), (int ) diagnostic .getLineNumber (), (int ) startColumn ,
322
+ (int ) diagnostic .getLineNumber (), (int ) endColumn ,
323
+ diagnostic .getMessage (defaultLocale ));
324
+ messages .add (message );
325
+ }
326
+ };
327
+ StandardJavaFileManager manager = compiler .getStandardFileManager (messageCollector , defaultLocale ,
328
+ Charset .defaultCharset ());
286
329
287
- @ Override
288
- public boolean isCanceled ()
289
- {
290
- return false ;
291
- }
330
+ getLogger ().debug ("ecj command line: " + args );
331
+ getLogger ().debug ("ecj input source files: " + allSources );
292
332
293
- @ Override
294
- public void setTaskName (String s )
295
- {
333
+ Iterable <? extends JavaFileObject > units = manager .getJavaFileObjectsFromStrings (allSources );
334
+ try {
335
+ success = Boolean .TRUE
336
+ .equals (compiler .getTask (devNull , manager , messageCollector , args , null , units ).call ());
337
+ } catch (RuntimeException e ) {
338
+ throw new EcjFailureException (e .getLocalizedMessage ());
296
339
}
297
-
298
- @ Override
299
- public void worked (int i , int i1 )
300
- {
340
+ getLogger ().debug (sw .toString ());
341
+ } else {
342
+ // Use the BatchCompiler and send all errors to xml temp file.
343
+ File errorF = null ;
344
+ try {
345
+ errorF = File .createTempFile ("ecjerr-" , ".xml" );
346
+ getLogger ().debug ("Using legacy BatchCompiler; error file " + errorF );
347
+
348
+ args .add ("-log" );
349
+ args .add (errorF .toString ());
350
+ args .addAll (allSources );
351
+
352
+ getLogger ().debug ("ecj command line: " + args );
353
+
354
+ success = BatchCompiler .compile (args .toArray (new String [args .size ()]), devNull , devNull ,
355
+ new CompilationProgress () {
356
+ @ Override
357
+ public void begin (int i ) {
358
+ }
359
+
360
+ @ Override
361
+ public void done () {
362
+ }
363
+
364
+ @ Override
365
+ public boolean isCanceled () {
366
+ return false ;
367
+ }
368
+
369
+ @ Override
370
+ public void setTaskName (String s ) {
371
+ }
372
+
373
+ @ Override
374
+ public void worked (int i , int i1 ) {
375
+ }
376
+ });
377
+ getLogger ().debug (sw .toString ());
378
+
379
+ if (errorF .length () < 80 ) {
380
+ throw new EcjFailureException (sw .toString ());
381
+ }
382
+ messageList = new EcjResponseParser ().parse (errorF , errorsAsWarnings );
383
+ } finally {
384
+ if (null != errorF ) {
385
+ try {
386
+ errorF .delete ();
387
+ } catch (Exception x ) {
388
+ }
389
+ }
301
390
}
302
- });
303
- getLogger ().debug (sw .toString ());
304
-
305
- List <CompilerMessage > messageList ;
306
- boolean hasError = false ;
307
- if (errorF .length () < 80 )
308
- {
309
- throw new EcjFailureException (sw .toString ());
310
391
}
311
- messageList = new EcjResponseParser ().parse (errorF , errorsAsWarnings );
312
-
313
- for (CompilerMessage compilerMessage : messageList )
314
- {
315
- if (compilerMessage .isError ())
316
- {
392
+ boolean hasError = false ;
393
+ for (CompilerMessage compilerMessage : messageList ) {
394
+ if (compilerMessage .isError ()) {
317
395
hasError = true ;
318
396
break ;
319
397
}
320
398
}
321
- if (!hasError && !success && !errorsAsWarnings )
322
- {
323
- CompilerMessage .Kind kind = errorsAsWarnings ? CompilerMessage .Kind .WARNING : CompilerMessage .Kind .ERROR ;
324
-
325
- //-- Compiler reported failure but we do not seem to have one -> probable exception
326
- CompilerMessage cm = new CompilerMessage ("[ecj] The compiler reported an error but has not written it to its logging" , kind );
399
+ if (!hasError && !success && !errorsAsWarnings ) {
400
+ CompilerMessage .Kind kind = errorsAsWarnings ? CompilerMessage .Kind .WARNING
401
+ : CompilerMessage .Kind .ERROR ;
402
+
403
+ // -- Compiler reported failure but we do not seem to have one -> probable
404
+ // exception
405
+ CompilerMessage cm = new CompilerMessage (
406
+ "[ecj] The compiler reported an error but has not written it to its logging" , kind );
327
407
messageList .add (cm );
328
408
hasError = true ;
329
409
330
- //-- Try to find the actual message by reporting the last 5 lines as a message
410
+ // -- Try to find the actual message by reporting the last 5 lines as a message
331
411
String stdout = getLastLines (sw .toString (), 5 );
332
- if (stdout .length () > 0 )
333
- {
412
+ if (stdout .length () > 0 ) {
334
413
cm = new CompilerMessage ("[ecj] The following line(s) might indicate the issue:\n " + stdout , kind );
335
414
messageList .add (cm );
336
415
}
@@ -339,14 +418,58 @@ public void worked(int i, int i1)
339
418
} catch (EcjFailureException x ) {
340
419
throw x ;
341
420
} catch (Exception x ) {
342
- throw new RuntimeException (x ); // sigh
343
- } finally {
344
- if (null != errorF ) {
345
- try {
346
- errorF .delete ();
347
- } catch (Exception x ) {}
421
+ throw new RuntimeException (x ); // sigh
422
+ }
423
+ }
424
+
425
+ private JavaCompiler getEcj () {
426
+ ServiceLoader <JavaCompiler > javaCompilerLoader = ServiceLoader .load (JavaCompiler .class ,
427
+ BatchCompiler .class .getClassLoader ());
428
+ Class <?> c = null ;
429
+ try {
430
+ c = Class .forName ("org.eclipse.jdt.internal.compiler.tool.EclipseCompiler" , false ,
431
+ BatchCompiler .class .getClassLoader ());
432
+ } catch (ClassNotFoundException e ) {
433
+ // Ignore
434
+ }
435
+ if (c != null ) {
436
+ for (JavaCompiler javaCompiler : javaCompilerLoader ) {
437
+ if (c .isInstance (javaCompiler )) {
438
+ return javaCompiler ;
439
+ }
348
440
}
349
441
}
442
+ getLogger ().debug ("Cannot find org.eclipse.jdt.internal.compiler.tool.EclipseCompiler" );
443
+ return null ;
444
+ }
445
+
446
+ private void addExtraSources (File dir , List <String > allSources ) {
447
+ DirectoryScanner scanner = new DirectoryScanner ();
448
+ scanner .setBasedir (dir .getAbsolutePath ());
449
+ scanner .setIncludes (new String [] { "**/*.java" });
450
+ scanner .scan ();
451
+ for (String file : scanner .getIncludedFiles ()) {
452
+ allSources .add (new File (dir , file ).getAbsolutePath ());
453
+ }
454
+ }
455
+
456
+ private CompilerMessage .Kind convert (Diagnostic .Kind kind ) {
457
+ if (kind == null ) {
458
+ return CompilerMessage .Kind .OTHER ;
459
+ }
460
+ switch (kind ) {
461
+ case ERROR :
462
+ return errorsAsWarnings ? CompilerMessage .Kind .WARNING : CompilerMessage .Kind .ERROR ;
463
+ case WARNING :
464
+ return CompilerMessage .Kind .WARNING ;
465
+ case MANDATORY_WARNING :
466
+ return CompilerMessage .Kind .MANDATORY_WARNING ;
467
+ case NOTE :
468
+ return CompilerMessage .Kind .NOTE ;
469
+ case OTHER :
470
+ default :
471
+ return CompilerMessage .Kind .OTHER ;
472
+ }
350
473
}
351
474
352
475
private String getLastLines (String text , int lines )
@@ -396,6 +519,7 @@ private boolean isPreJava16(CompilerConfiguration config) {
396
519
|| s .startsWith ( "1.1" ) || s .startsWith ( "1.0" );
397
520
}
398
521
522
+ @ Override
399
523
public String [] createCommandLine ( CompilerConfiguration config )
400
524
throws CompilerException
401
525
{
0 commit comments