19
19
package org .apache .maven .plugin .plugin ;
20
20
21
21
import java .io .File ;
22
+ import java .io .IOException ;
23
+ import java .io .InputStream ;
24
+ import java .io .OutputStream ;
22
25
import java .net .URI ;
23
- import java .util .Arrays ;
24
- import java .util .Collections ;
25
- import java .util .LinkedHashSet ;
26
- import java .util .List ;
27
- import java .util .Set ;
26
+ import java .nio .charset .StandardCharsets ;
27
+ import java .nio .file .Files ;
28
+ import java .nio .file .Path ;
29
+ import java .util .*;
30
+ import java .util .stream .Collectors ;
31
+ import java .util .stream .Stream ;
28
32
29
33
import org .apache .maven .artifact .Artifact ;
30
34
import org .apache .maven .artifact .resolver .filter .ArtifactFilter ;
31
35
import org .apache .maven .artifact .resolver .filter .IncludesArtifactFilter ;
32
36
import org .apache .maven .execution .MavenSession ;
33
37
import org .apache .maven .plugin .MojoExecutionException ;
34
38
import org .apache .maven .plugin .descriptor .InvalidPluginDescriptorException ;
39
+ import org .apache .maven .plugin .descriptor .MojoDescriptor ;
35
40
import org .apache .maven .plugin .descriptor .PluginDescriptor ;
36
41
import org .apache .maven .plugins .annotations .Component ;
37
42
import org .apache .maven .plugins .annotations .LifecyclePhase ;
38
43
import org .apache .maven .plugins .annotations .Mojo ;
39
44
import org .apache .maven .plugins .annotations .Parameter ;
40
45
import org .apache .maven .plugins .annotations .ResolutionScope ;
41
46
import org .apache .maven .tools .plugin .DefaultPluginToolsRequest ;
47
+ import org .apache .maven .tools .plugin .ExtendedMojoDescriptor ;
42
48
import org .apache .maven .tools .plugin .ExtendedPluginDescriptor ;
43
49
import org .apache .maven .tools .plugin .PluginToolsRequest ;
44
50
import org .apache .maven .tools .plugin .extractor .ExtractionException ;
48
54
import org .apache .maven .tools .plugin .scanner .MojoScanner ;
49
55
import org .codehaus .plexus .component .repository .ComponentDependency ;
50
56
import org .codehaus .plexus .util .ReaderFactory ;
57
+ import org .codehaus .plexus .util .io .CachingOutputStream ;
58
+ import org .codehaus .plexus .util .io .CachingWriter ;
59
+ import org .objectweb .asm .*;
51
60
import org .sonatype .plexus .build .incremental .BuildContext ;
52
61
62
+ import static org .objectweb .asm .Opcodes .*;
63
+ import static org .objectweb .asm .Opcodes .ACC_PUBLIC ;
64
+
53
65
/**
54
66
* <p>
55
67
* Generate a plugin descriptor.
@@ -78,6 +90,12 @@ public class DescriptorGeneratorMojo extends AbstractGeneratorMojo {
78
90
@ Parameter (defaultValue = "${project.build.outputDirectory}/META-INF/maven" , readonly = true )
79
91
private File outputDirectory ;
80
92
93
+ /**
94
+ * The directory where the generated class files will be put.
95
+ */
96
+ @ Parameter (defaultValue = "${project.build.outputDirectory}" , readonly = true )
97
+ private File classesOutputDirectory ;
98
+
81
99
/**
82
100
* The file encoding of the source files.
83
101
*
@@ -269,7 +287,6 @@ public class DescriptorGeneratorMojo extends AbstractGeneratorMojo {
269
287
protected BuildContext buildContext ;
270
288
271
289
public void generate () throws MojoExecutionException {
272
-
273
290
if (!"maven-plugin" .equalsIgnoreCase (project .getArtifactId ())
274
291
&& project .getArtifactId ().toLowerCase ().startsWith ("maven-" )
275
292
&& project .getArtifactId ().toLowerCase ().endsWith ("-plugin" )
@@ -352,6 +369,12 @@ public void generate() throws MojoExecutionException {
352
369
PluginDescriptorFilesGenerator pluginDescriptorGenerator = new PluginDescriptorFilesGenerator ();
353
370
pluginDescriptorGenerator .execute (outputDirectory , request );
354
371
372
+ // Generate the additional factories for v4 mojos
373
+ generateFactories (request .getPluginDescriptor ());
374
+
375
+ // Generate index for v4 beans
376
+ generateIndex ();
377
+
355
378
buildContext .refresh (outputDirectory );
356
379
} catch (GeneratorException e ) {
357
380
throw new MojoExecutionException ("Error writing plugin descriptor" , e );
@@ -367,6 +390,128 @@ public void generate() throws MojoExecutionException {
367
390
}
368
391
}
369
392
393
+ private void generateIndex () throws GeneratorException {
394
+ try {
395
+ Set <String > diBeans = new TreeSet <>();
396
+ try (Stream <Path > paths = Files .walk (classesOutputDirectory .toPath ())) {
397
+ List <Path > classes = paths .filter (
398
+ p -> p .getFileName ().toString ().endsWith (".class" ))
399
+ .collect (Collectors .toList ());
400
+ for (Path classFile : classes ) {
401
+ String fileString = classFile .toString ();
402
+ String className = fileString
403
+ .substring (0 , fileString .length () - ".class" .length ())
404
+ .replace ('/' , '.' );
405
+ try (InputStream is = Files .newInputStream (classFile )) {
406
+ ClassReader rdr = new ClassReader (is );
407
+ rdr .accept (
408
+ new ClassVisitor (Opcodes .ASM9 ) {
409
+ String className ;
410
+
411
+ @ Override
412
+ public void visit (
413
+ int version ,
414
+ int access ,
415
+ String name ,
416
+ String signature ,
417
+ String superName ,
418
+ String [] interfaces ) {
419
+ super .visit (version , access , name , signature , superName , interfaces );
420
+ className = name ;
421
+ }
422
+
423
+ @ Override
424
+ public AnnotationVisitor visitAnnotation (String descriptor , boolean visible ) {
425
+ if ("Lorg/apache/maven/api/di/Named;" .equals (descriptor )) {
426
+ diBeans .add (className .replace ('/' , '.' ));
427
+ }
428
+ return null ;
429
+ }
430
+ },
431
+ ClassReader .SKIP_FRAMES | ClassReader .SKIP_CODE | ClassReader .SKIP_DEBUG );
432
+ }
433
+
434
+ // Class<?> clazz = project.getClassRealm().loadClass(className);
435
+ // boolean hasQualifier = Stream.of(clazz.getAnnotations())
436
+ // .flatMap(ann -> Stream.of(ann.getClass().getAnnotations()))
437
+ // .anyMatch(ann -> "org.apache.maven.api.di.Qualifier"
438
+ // .equals(ann.annotationType().getName()));
439
+ // if (hasQualifier) {
440
+ // diBeans.add(className);
441
+ // }
442
+ }
443
+ }
444
+ Path path = outputDirectory .toPath ().resolve ("org.apache.maven.api.di.Inject" );
445
+ if (diBeans .isEmpty ()) {
446
+ Files .deleteIfExists (path );
447
+ } else {
448
+ String nl = System .lineSeparator ();
449
+ try (CachingWriter w = new CachingWriter (path , StandardCharsets .UTF_8 )) {
450
+ String content = diBeans .stream ().collect (Collectors .joining (nl , "" , nl ));
451
+ w .write (content );
452
+ }
453
+ }
454
+ } catch (Exception e ) {
455
+ throw new GeneratorException ("Unable to generate index for v4 beans" , e );
456
+ }
457
+ }
458
+
459
+ private void generateFactories (PluginDescriptor pd ) throws GeneratorException {
460
+ try {
461
+ for (MojoDescriptor md : pd .getMojos ()) {
462
+ if (md instanceof ExtendedMojoDescriptor && ((ExtendedMojoDescriptor ) md ).isV4Api ()) {
463
+ generateFactory (md );
464
+ }
465
+ }
466
+ } catch (IOException e ) {
467
+ throw new GeneratorException ("Unable to generate factories for v4 mojos" , e );
468
+ }
469
+ }
470
+
471
+ private void generateFactory (MojoDescriptor md ) throws IOException {
472
+ String mojoClassName = md .getImplementation ();
473
+ String packageName = mojoClassName .substring (0 , mojoClassName .lastIndexOf ('.' ));
474
+ String generatorClassName = mojoClassName .substring (mojoClassName .lastIndexOf ('.' ) + 1 ) + "Factory" ;
475
+ String mojoName = md .getId ();
476
+
477
+ getLog ().debug ("Generating v4 factory for " + mojoClassName );
478
+
479
+ byte [] bin = computeGeneratorClassBytes (packageName , generatorClassName , mojoName , mojoClassName );
480
+
481
+ try (OutputStream os = new CachingOutputStream (classesOutputDirectory
482
+ .toPath ()
483
+ .resolve (packageName .replace ('.' , '/' ) + "/" + generatorClassName + ".class" ))) {
484
+ os .write (bin );
485
+ }
486
+ }
487
+
488
+ static byte [] computeGeneratorClassBytes (
489
+ String packageName , String generatorClassName , String mojoName , String mojoClassName ) {
490
+ String mojo = mojoClassName .replace ('.' , '/' );
491
+ ClassWriter cw = new ClassWriter (ClassWriter .COMPUTE_FRAMES | ClassWriter .COMPUTE_MAXS );
492
+ cw .visitSource (generatorClassName + ".java" , null );
493
+ AnnotationVisitor av = cw .visitAnnotation ("Lorg/apache/maven/api/di/Named;" , true );
494
+ av .visit ("value" , mojoName );
495
+ av .visitEnd ();
496
+ cw .visitAnnotation ("Lorg/apache/maven/api/annotations/Generated;" , true ).visitEnd ();
497
+ cw .visit (
498
+ V1_8 ,
499
+ ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC ,
500
+ packageName .replace ("." , "/" ) + "/" + generatorClassName ,
501
+ null ,
502
+ mojo ,
503
+ null );
504
+ MethodVisitor mv = cw .visitMethod (ACC_PUBLIC + ACC_SYNTHETIC , "<init>" , "()V" , null , null );
505
+ mv .visitCode ();
506
+ mv .visitVarInsn (Opcodes .ALOAD , 0 );
507
+ mv .visitMethodInsn (Opcodes .INVOKESPECIAL , mojo , "<init>" , "()V" , false );
508
+ mv .visitInsn (Opcodes .RETURN );
509
+ mv .visitMaxs (-1 , -1 );
510
+ mv .visitEnd ();
511
+ cw .visitEnd ();
512
+ return cw .toByteArray ();
513
+ }
514
+
370
515
private PluginDescriptor extendPluginDescriptor (PluginToolsRequest request ) {
371
516
ExtendedPluginDescriptor extendedPluginDescriptor = new ExtendedPluginDescriptor (request .getPluginDescriptor ());
372
517
extendedPluginDescriptor .setRequiredJavaVersion (getRequiredJavaVersion (request ));
0 commit comments