1 package org.springframework.roo.classpath.javaparser.details;
2
3 import japa.parser.ASTHelper;
4 import japa.parser.JavaParser;
5 import japa.parser.ParseException;
6 import japa.parser.ast.CompilationUnit;
7 import japa.parser.ast.body.BodyDeclaration;
8 import japa.parser.ast.body.FieldDeclaration;
9 import japa.parser.ast.body.TypeDeclaration;
10 import japa.parser.ast.body.VariableDeclarator;
11 import japa.parser.ast.expr.AnnotationExpr;
12 import japa.parser.ast.expr.Expression;
13 import japa.parser.ast.expr.NameExpr;
14 import japa.parser.ast.type.ClassOrInterfaceType;
15 import japa.parser.ast.type.Type;
16
17 import java.io.ByteArrayInputStream;
18 import java.lang.reflect.Modifier;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Set;
23
24 import org.springframework.roo.classpath.details.FieldMetadata;
25 import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
26 import org.springframework.roo.classpath.javaparser.CompilationUnitServices;
27 import org.springframework.roo.classpath.javaparser.JavaParserUtils;
28 import org.springframework.roo.model.JavaSymbolName;
29 import org.springframework.roo.model.JavaType;
30 import org.springframework.roo.support.style.ToStringCreator;
31 import org.springframework.roo.support.util.Assert;
32
33
34
35
36
37
38
39
40 public class JavaParserFieldMetadata implements FieldMetadata {
41 private JavaType fieldType;
42 private String fieldInitializer;
43 private JavaSymbolName fieldName;
44 private List<AnnotationMetadata> annotations = new ArrayList<AnnotationMetadata>();
45 private String declaredByMetadataId;
46 private int modifier;
47
48 public JavaParserFieldMetadata(String declaredByMetadataId, FieldDeclaration fieldDeclaration, VariableDeclarator var, CompilationUnitServices compilationUnitServices, Set<JavaSymbolName> typeParameters) {
49 Assert.notNull(declaredByMetadataId, "Declared by metadata ID required");
50 Assert.notNull(fieldDeclaration, "Field declaration is mandatory");
51 Assert.notNull(var, "Variable declarator required");
52 Assert.isTrue(fieldDeclaration.getVariables().contains(var), "Cannot request a variable not already in the field declaration");
53 Assert.notNull(compilationUnitServices, "Compilation unit services are required");
54
55
56 this.modifier = JavaParserUtils.getJdkModifier(fieldDeclaration.getModifiers());
57
58 this.declaredByMetadataId = declaredByMetadataId;
59
60 Type type = fieldDeclaration.getType();
61 this.fieldType = JavaParserUtils.getJavaType(compilationUnitServices, type, typeParameters);
62
63
64 if (var.getId().getArrayCount() > 0) {
65 this.fieldType = new JavaType(fieldType.getFullyQualifiedTypeName(), var.getId().getArrayCount() + fieldType.getArray(), fieldType.getDataType(), fieldType.getArgName(), fieldType.getParameters());
66 }
67
68 this.fieldName = new JavaSymbolName(var.getId().getName());
69
70
71 Expression e = var.getInit();
72 if (e != null) {
73 this.fieldInitializer = e.toString();
74 }
75
76 List<AnnotationExpr> annotations = fieldDeclaration.getAnnotations();
77 if (annotations != null) {
78 for (AnnotationExpr annotation : annotations) {
79 this.annotations.add(new JavaParserAnnotationMetadata(annotation, compilationUnitServices));
80 }
81 }
82 }
83
84 public int getModifier() {
85 return modifier;
86 }
87
88 public String getDeclaredByMetadataId() {
89 return declaredByMetadataId;
90 }
91
92 public List<AnnotationMetadata> getAnnotations() {
93 return Collections.unmodifiableList(annotations);
94 }
95
96 public JavaSymbolName getFieldName() {
97 return fieldName;
98 }
99
100 public JavaType getFieldType() {
101 return fieldType;
102 }
103
104 public static void addField(CompilationUnitServices compilationUnitServices, List<BodyDeclaration> members, FieldMetadata field, boolean permitFlush) {
105 Assert.notNull(compilationUnitServices, "Compilation unit services required");
106 Assert.notNull(members, "Members required");
107 Assert.notNull(field, "Field required");
108
109
110 NameExpr importedType = JavaParserUtils.importTypeIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), field.getFieldType());
111 ClassOrInterfaceType fieldType = JavaParserUtils.getClassOrInterfaceType(importedType);
112
113 FieldDeclaration newField = ASTHelper.createFieldDeclaration(JavaParserUtils.getJavaParserModifier(field.getModifier()), fieldType, field.getFieldName().getSymbolName());
114
115
116 if (field.getFieldType().getParameters().size() > 0) {
117 List<Type> fieldTypeArgs = new ArrayList<Type>();
118 fieldType.setTypeArgs(fieldTypeArgs);
119 for (JavaType parameter : field.getFieldType().getParameters()) {
120
121
122 fieldTypeArgs.add(JavaParserUtils.importParametersForType(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), parameter));
123 }
124 }
125
126 List<VariableDeclarator> vars = newField.getVariables();
127 Assert.notEmpty(vars, "Expected ASTHelper to have provided a single VariableDeclarator");
128 Assert.isTrue(vars.size() == 1, "Expected ASTHelper to have provided a single VariableDeclarator");
129 VariableDeclarator vd = vars.iterator().next();
130
131 if (field.getFieldInitializer() != null && field.getFieldInitializer().length() > 0) {
132
133
134
135 StringBuilder sb = new StringBuilder();
136 sb.append("class TemporaryClass {\n");
137 sb.append(" private " + field.getFieldType() + " " + field.getFieldName() + " = " + field.getFieldInitializer() + ";\n");
138 sb.append("}\n");
139 ByteArrayInputStream bais = new ByteArrayInputStream(sb.toString().getBytes());
140 CompilationUnit ci;
141 try {
142 ci = JavaParser.parse(bais);
143 } catch (ParseException pe) {
144 throw new IllegalStateException("Illegal state: JavaParser did not parse correctly", pe);
145 }
146 List<TypeDeclaration> types = ci.getTypes();
147 if (types == null || types.size() != 1) {
148 throw new IllegalArgumentException("Field member invalid");
149 }
150 TypeDeclaration td = types.get(0);
151 List<BodyDeclaration> bodyDeclarations = td.getMembers();
152 if (bodyDeclarations == null || bodyDeclarations.size() != 1) {
153 throw new IllegalStateException("Illegal state: JavaParser did not return body declarations correctly");
154 }
155 BodyDeclaration bd = bodyDeclarations.get(0);
156 if (!(bd instanceof FieldDeclaration)) {
157 throw new IllegalStateException("Illegal state: JavaParser did not return a field declaration correctly");
158 }
159 FieldDeclaration fd = (FieldDeclaration) bd;
160 if (fd.getVariables() == null || fd.getVariables().size() != 1) {
161 throw new IllegalStateException("Illegal state: JavaParser did not return a field declaration correctly");
162 }
163
164 Expression init = fd.getVariables().get(0).getInit();
165
166
167
168 vd.setInit(init);
169 }
170
171
172 List<AnnotationExpr> annotations = new ArrayList<AnnotationExpr>();
173 newField.setAnnotations(annotations);
174 for (AnnotationMetadata annotation : field.getAnnotations()) {
175 JavaParserAnnotationMetadata.addAnnotationToList(compilationUnitServices, annotations, annotation, false);
176 }
177
178
179
180 int nextFieldIndex = 0;
181 int i = -1;
182 for (BodyDeclaration bd : members) {
183 i++;
184 if (bd instanceof FieldDeclaration) {
185
186 nextFieldIndex = i + 1;
187 FieldDeclaration bdf = (FieldDeclaration) bd;
188 for (VariableDeclarator v : bdf.getVariables()) {
189 Assert.isTrue(!field.getFieldName().getSymbolName().equals(v.getId().getName()), "A field with name '" + field.getFieldName().getSymbolName() + "' already exists");
190 }
191 }
192 }
193
194
195 members.add(nextFieldIndex, newField);
196
197 if (permitFlush) {
198 compilationUnitServices.flush();
199 }
200 }
201
202 public static void removeField(CompilationUnitServices compilationUnitServices, List<BodyDeclaration> members, JavaSymbolName fieldName) {
203 Assert.notNull(compilationUnitServices, "Compilation unit services required");
204 Assert.notNull(members, "Members required");
205 Assert.notNull(fieldName, "Field name to remove is required");
206
207
208 int i = -1;
209 int toDelete = -1;
210 for (BodyDeclaration bd : members) {
211 i++;
212 if (bd instanceof FieldDeclaration) {
213 FieldDeclaration fieldDeclaration = (FieldDeclaration) bd;
214 for (VariableDeclarator var : fieldDeclaration.getVariables()) {
215 if (var.getId().getName().equals(fieldName.getSymbolName())) {
216 toDelete = i;
217 break;
218 }
219 }
220 }
221 }
222
223 Assert.isTrue(toDelete > -1, "Could not locate field '" + fieldName + "' to delete");
224
225
226 members.remove(toDelete);
227
228 compilationUnitServices.flush();
229 }
230
231 public String getFieldInitializer() {
232 return this.fieldInitializer;
233 }
234
235 public String toString() {
236 ToStringCreator tsc = new ToStringCreator(this);
237 tsc.append("declaredByMetadataId", declaredByMetadataId);
238 tsc.append("modifier", Modifier.toString(modifier));
239 tsc.append("fieldType", fieldType);
240 tsc.append("fieldName", fieldName);
241 tsc.append("fieldInitializer", fieldInitializer);
242 tsc.append("annotations", annotations);
243 return tsc.toString();
244 }
245
246 }