1 package org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.stream.Collectors;
29 import java.util.stream.Stream;
30
31 import org.apache.maven.plugins.annotations.Parameter;
32 import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotatedClass;
33 import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner;
34 import org.codehaus.plexus.util.StringUtils;
35 import org.objectweb.asm.AnnotationVisitor;
36 import org.objectweb.asm.ClassVisitor;
37 import org.objectweb.asm.FieldVisitor;
38 import org.objectweb.asm.MethodVisitor;
39 import org.objectweb.asm.Opcodes;
40 import org.objectweb.asm.Type;
41 import org.objectweb.asm.signature.SignatureReader;
42 import org.objectweb.asm.util.TraceSignatureVisitor;
43
44
45
46
47
48
49
50 public class MojoClassVisitor
51 extends ClassVisitor
52 {
53 private MojoAnnotatedClass mojoAnnotatedClass;
54
55 private Map<String, MojoAnnotationVisitor> annotationVisitorMap = new HashMap<>();
56
57 private List<MojoFieldVisitor> fieldVisitors = new ArrayList<>();
58
59 private List<MojoMethodVisitor> methodVisitors = new ArrayList<>();
60
61 public MojoClassVisitor()
62 {
63 super( Opcodes.ASM9 );
64 }
65
66 public MojoAnnotatedClass getMojoAnnotatedClass()
67 {
68 return mojoAnnotatedClass;
69 }
70
71 public MojoAnnotationVisitor getAnnotationVisitor( Class<?> annotation )
72 {
73 return annotationVisitorMap.get( annotation.getName() );
74 }
75
76 public List<MojoFieldVisitor> findFieldWithAnnotation( Class<?> annotation )
77 {
78 String annotationClassName = annotation.getName();
79
80 return fieldVisitors.stream()
81 .filter( field -> field.getAnnotationVisitorMap().containsKey( annotationClassName ) )
82 .collect( Collectors.toList() );
83 }
84
85 public List<MojoParameterVisitor> findParameterVisitors()
86 {
87 String annotationClassName = Parameter.class.getName();
88
89 return Stream
90 .concat(
91 findFieldWithAnnotation( Parameter.class ).stream(),
92 methodVisitors.stream()
93 .filter( method -> method.getAnnotationVisitorMap().containsKey( annotationClassName ) ) )
94 .collect( Collectors.toList() );
95 }
96
97 @Override
98 public void visit( int version, int access, String name, String signature, String superName, String[] interfaces )
99 {
100 mojoAnnotatedClass = new MojoAnnotatedClass();
101 mojoAnnotatedClass.setClassName( Type.getObjectType( name ).getClassName() );
102 if ( superName != null )
103 {
104 mojoAnnotatedClass.setParentClassName( Type.getObjectType( superName ).getClassName() );
105 }
106 }
107
108 @Override
109 public AnnotationVisitor visitAnnotation( String desc, boolean visible )
110 {
111 String annotationClassName = Type.getType( desc ).getClassName();
112 if ( !MojoAnnotationsScanner.CLASS_LEVEL_ANNOTATIONS.contains( annotationClassName ) )
113 {
114 return null;
115 }
116 MojoAnnotationVisitor mojoAnnotationVisitor = new MojoAnnotationVisitor( annotationClassName );
117 annotationVisitorMap.put( annotationClassName, mojoAnnotationVisitor );
118 return mojoAnnotationVisitor;
119 }
120
121 @Override
122 public FieldVisitor visitField( int access, String name, String desc, String signature, Object value )
123 {
124 List<String> typeParameters = extractTypeParameters( access, signature, true );
125 MojoFieldVisitor mojoFieldVisitor = new MojoFieldVisitor( name, Type.getType( desc ).getClassName(),
126 typeParameters );
127 fieldVisitors.add( mojoFieldVisitor );
128 return mojoFieldVisitor;
129 }
130
131
132
133
134
135
136
137
138
139
140 private List<String> extractTypeParameters( int access, String signature, boolean isField )
141 {
142 if ( StringUtils.isEmpty( signature ) )
143 {
144 return Collections.emptyList();
145 }
146 TraceSignatureVisitor traceSignatureVisitor = new TraceSignatureVisitor( access );
147 SignatureReader signatureReader = new SignatureReader( signature );
148 if ( isField )
149 {
150 signatureReader.acceptType( traceSignatureVisitor );
151 }
152 else
153 {
154 signatureReader.accept( traceSignatureVisitor );
155 }
156 String declaration = traceSignatureVisitor.getDeclaration();
157 int startTypeParameters = declaration.indexOf( '<' );
158 if ( startTypeParameters == -1 )
159 {
160 return Collections.emptyList();
161 }
162 String typeParameters = declaration.substring( startTypeParameters + 1,
163 declaration.lastIndexOf( '>' ) );
164 return Arrays.asList( typeParameters.split( ", " ) );
165 }
166
167 @Override
168 public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions )
169 {
170 if ( ( access & Opcodes.ACC_PUBLIC ) != Opcodes.ACC_PUBLIC
171 || ( access & Opcodes.ACC_STATIC ) == Opcodes.ACC_STATIC )
172 {
173 return null;
174 }
175
176 if ( name.length() < 4 || !( name.startsWith( "add" ) || name.startsWith( "set" ) ) )
177 {
178 return null;
179 }
180
181 Type type = Type.getType( desc );
182
183 if ( "void".equals( type.getReturnType().getClassName() ) && type.getArgumentTypes().length == 1 )
184 {
185 String fieldName = StringUtils.lowercaseFirstLetter( name.substring( 3 ) );
186 String className = type.getArgumentTypes()[0].getClassName();
187 List<String> typeParameters = extractTypeParameters( access, signature, false );
188
189 MojoMethodVisitor mojoMethodVisitor = new MojoMethodVisitor( fieldName, className, typeParameters );
190 methodVisitors.add( mojoMethodVisitor );
191 return mojoMethodVisitor;
192 }
193
194 return null;
195 }
196 }