1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.devtools.jpa.eclipselink.conv.parser.helper;
17
18 import japa.parser.ast.CompilationUnit;
19 import japa.parser.ast.ImportDeclaration;
20 import japa.parser.ast.Node;
21 import japa.parser.ast.body.BodyDeclaration;
22 import japa.parser.ast.body.ClassOrInterfaceDeclaration;
23 import japa.parser.ast.body.FieldDeclaration;
24 import japa.parser.ast.body.TypeDeclaration;
25 import japa.parser.ast.body.VariableDeclarator;
26 import japa.parser.ast.expr.AnnotationExpr;
27 import org.apache.commons.lang.ClassUtils;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.List;
34
35
36
37
38
39 public class AnnotationHelper extends VoidVisitorHelperBase<String> {
40
41 private static final Log LOG = LogFactory.getLog(AnnotationHelper.class);
42
43 private final Collection<AnnotationResolver> resolvers;
44 private final boolean removeExisting;
45
46 public AnnotationHelper(Collection<AnnotationResolver> resolvers, boolean removeExisting) {
47 this.resolvers = resolvers;
48 this.removeExisting = removeExisting;
49 }
50
51 @Override
52 public void visitPre(final ClassOrInterfaceDeclaration n, final String mappedClass) {
53 addAnnotation(n, mappedClass, Level.CLASS);
54 }
55
56 @Override
57 public void visitPre(final FieldDeclaration n, final String mappedClass) {
58 addAnnotation(n, mappedClass, Level.FIELD);
59 }
60
61
62 private CompilationUnit getCompilationUnit(Node n) {
63 Node unit = n;
64 while (!(unit instanceof CompilationUnit) && unit != null) {
65 unit = unit.getParentNode();
66 }
67 return (CompilationUnit) unit;
68 }
69
70 private void addAnnotation(final BodyDeclaration n, final String mappedClass, Level level) {
71 for (AnnotationResolver resolver : resolvers) {
72 if (resolver.getLevel() == level) {
73 LOG.debug("Evaluating resolver " + ClassUtils.getShortClassName(resolver.getClass()) + " for " + getTypeOrFieldNameForMsg(n) + ".");
74
75 final String fullyQualifiedName = resolver.getFullyQualifiedName();
76
77
78 final CompilationUnit unit = getCompilationUnit(n);
79 final List<ImportDeclaration> imports = unit.getImports() != null ? unit.getImports() : new ArrayList<ImportDeclaration>();
80 final boolean foundAnnImport = imported(imports, fullyQualifiedName);
81
82
83 final AnnotationExpr existingAnnotation = findAnnotation(n, fullyQualifiedName, foundAnnImport);
84
85
86
87
88 if (removeExisting && existingAnnotation != null) {
89 LOG.info("removing existing " + existingAnnotation + " from " + getTypeOrFieldNameForMsg(n) + ".");
90 final List<AnnotationExpr> annotations = n.getAnnotations() != null ? n.getAnnotations() : new ArrayList<AnnotationExpr>();
91 annotations.remove(existingAnnotation);
92 n.setAnnotations(annotations);
93 }
94
95
96
97 if (existingAnnotation == null || (existingAnnotation != null && removeExisting)) {
98 NodeData nodes = resolver.resolve(n, mappedClass);
99 if (nodes != null && nodes.annotation != null) {
100 LOG.info("adding " + nodes.annotation + " to " + getTypeOrFieldNameForMsg(n) + ".");
101 final List<AnnotationExpr> annotations = n.getAnnotations() != null ? n.getAnnotations() : new ArrayList<AnnotationExpr>();
102 annotations.add(nodes.annotation);
103 n.setAnnotations(annotations);
104
105
106 if (!foundAnnImport) {
107 LOG.info("adding import " + fullyQualifiedName + " to " + getTypeNameForMsg(n) + ".");
108 imports.add(nodes.annotationImport);
109 }
110
111
112 if (nodes.additionalImports != null) {
113 for (ImportDeclaration aImport : nodes.additionalImports) {
114 if (aImport.isStatic() || aImport.isAsterisk()) {
115 throw new IllegalStateException("The additional imports should not be static or star imports");
116 }
117 final boolean imported = imported(imports, aImport.getName().toString());
118 if (!imported) {
119 LOG.info("adding import " + aImport.getName().toString() + " to " + getTypeNameForMsg(n) + ".");
120 imports.add(aImport);
121 }
122 }
123 }
124
125 unit.setImports(imports);
126
127 if (nodes.nestedDeclaration != null) {
128 final TypeDeclaration parent = unit.getTypes().get(0);
129
130 final List<BodyDeclaration> members = parent.getMembers() != null ? parent.getMembers() : new ArrayList<BodyDeclaration>();
131 final TypeDeclaration existingNestedDeclaration = findTypeDeclaration(members, nodes.nestedDeclaration.getName());
132
133
134 if (removeExisting) {
135 if (existingNestedDeclaration != null) {
136 LOG.info("removing existing nested declaration " + existingNestedDeclaration.getName() + " from " + getTypeOrFieldNameForMsg(n) + ".");
137 members.remove(existingNestedDeclaration);
138 }
139 }
140
141
142 if (existingNestedDeclaration == null || (existingNestedDeclaration != null && removeExisting)) {
143 nodes.nestedDeclaration.setParentNode(parent);
144 LOG.info("adding nested declaration " + nodes.nestedDeclaration.getName() + " to " + getTypeOrFieldNameForMsg(n) + ".");
145 members.add(nodes.nestedDeclaration);
146 }
147 parent.setMembers(members);
148 }
149 }
150 }
151 }
152 }
153 }
154
155 private AnnotationExpr findAnnotation(final BodyDeclaration n, String fullyQualifiedName, boolean foundAnnImport) {
156 final String simpleName = ClassUtils.getShortClassName(fullyQualifiedName);
157 final List<AnnotationExpr> annotations = n.getAnnotations() != null ? n.getAnnotations() : new ArrayList<AnnotationExpr>();
158
159 for (AnnotationExpr ae : annotations) {
160 final String name = ae.getName().toString();
161 if ((simpleName.equals(name) && foundAnnImport)) {
162 LOG.info("found " + ae + " on " + getTypeOrFieldNameForMsg(n) + ".");
163 return ae;
164 }
165
166 if (fullyQualifiedName.equals(name)) {
167 LOG.info("found " + ae + " on " + getTypeOrFieldNameForMsg(n) + ".");
168 return ae;
169 }
170 }
171 return null;
172 }
173
174 private TypeDeclaration findTypeDeclaration(List<BodyDeclaration> members, String name) {
175 if (members != null) {
176 for (BodyDeclaration bd : members) {
177 if (bd instanceof TypeDeclaration) {
178 if (((TypeDeclaration) bd).getName().equals(name)) {
179 return (TypeDeclaration) bd;
180 }
181 }
182 }
183 }
184 return null;
185 }
186
187 private boolean imported(List<ImportDeclaration> imports, String fullyQualifiedName) {
188 final String packageName = ClassUtils.getPackageName(fullyQualifiedName);
189
190 for (final ImportDeclaration i : imports) {
191 if (!i.isStatic()) {
192 final String importName = i.getName().toString();
193 if (i.isAsterisk()) {
194 if (packageName.equals(importName)) {
195 if ( LOG.isDebugEnabled() ) {
196 LOG.debug("found import " + packageName + ".* on " + getTypeNameForMsg(i) + ".");
197 }
198 return true;
199 }
200 } else {
201 if (fullyQualifiedName.equals(importName)) {
202 if ( LOG.isDebugEnabled() ) {
203 LOG.debug("found import " + fullyQualifiedName + " on " + getTypeNameForMsg(i) + ".");
204 }
205 return true;
206 }
207 }
208 }
209 }
210 return false;
211 }
212
213 private String getTypeOrFieldNameForMsg(final BodyDeclaration n) {
214 if (n instanceof TypeDeclaration) {
215 return ((TypeDeclaration) n).getName();
216 } else if (n instanceof FieldDeclaration) {
217 final FieldDeclaration fd = (FieldDeclaration) n;
218
219 final CompilationUnit unit = getCompilationUnit(n);
220 final TypeDeclaration parent = unit.getTypes().get(0);
221 Collection<String> variableNames = new ArrayList<String>();
222 if (fd.getVariables() != null) {
223 for (VariableDeclarator vd : fd.getVariables()) {
224 variableNames.add(vd.getId().getName());
225 }
226 }
227 return variableNames.size() == 1 ?
228 parent.getName() + "." + variableNames.iterator().next() :
229 parent.getName() + "." + variableNames.toString();
230
231 }
232 return null;
233 }
234
235 private String getTypeNameForMsg(final Node n) {
236 final CompilationUnit unit = getCompilationUnit(n);
237 final TypeDeclaration parent = unit.getTypes().get(0);
238 return parent.getName();
239 }
240 }