1 | /* |
---|---|
2 | * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser. |
3 | * Copyright (C) 2011, 2013-2020 The JavaParser Team. |
4 | * |
5 | * This file is part of JavaParser. |
6 | * |
7 | * JavaParser can be used either under the terms of |
8 | * a) the GNU Lesser General Public License as published by |
9 | * the Free Software Foundation, either version 3 of the License, or |
10 | * (at your option) any later version. |
11 | * b) the terms of the Apache License |
12 | * |
13 | * You should have received a copy of both licenses in LICENCE.LGPL and |
14 | * LICENCE.APACHE. Please refer to those files for details. |
15 | * |
16 | * JavaParser is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU Lesser General Public License for more details. |
20 | */ |
21 | package com.github.javaparser.ast.nodeTypes; |
22 | |
23 | import com.github.javaparser.ast.Modifier; |
24 | import com.github.javaparser.ast.Node; |
25 | import com.github.javaparser.ast.NodeList; |
26 | import com.github.javaparser.ast.body.*; |
27 | import com.github.javaparser.ast.expr.Expression; |
28 | import com.github.javaparser.ast.stmt.BlockStmt; |
29 | import com.github.javaparser.ast.type.Type; |
30 | import com.github.javaparser.ast.type.VoidType; |
31 | |
32 | import java.util.List; |
33 | import java.util.Optional; |
34 | |
35 | import static com.github.javaparser.StaticJavaParser.parseType; |
36 | import static com.github.javaparser.ast.Modifier.Keyword; |
37 | import static com.github.javaparser.ast.Modifier.Keyword.*; |
38 | import static com.github.javaparser.ast.Modifier.createModifierList; |
39 | import static java.util.Collections.unmodifiableList; |
40 | import static java.util.stream.Collectors.toList; |
41 | |
42 | /** |
43 | * A node having members. |
44 | * <p> |
45 | * The main reason for this interface is to permit users to manipulate homogeneously all nodes with a getMembers |
46 | * method. |
47 | */ |
48 | public interface NodeWithMembers<N extends Node> extends NodeWithSimpleName<N> { |
49 | /** |
50 | * @return all members inside the braces of this node, |
51 | * like fields, methods, nested types, etc. |
52 | */ |
53 | NodeList<BodyDeclaration<?>> getMembers(); |
54 | |
55 | void tryAddImportToParentCompilationUnit(Class<?> clazz); |
56 | |
57 | default BodyDeclaration<?> getMember(int i) { |
58 | return getMembers().get(i); |
59 | } |
60 | |
61 | @SuppressWarnings("unchecked") |
62 | default N setMember(int i, BodyDeclaration<?> member) { |
63 | getMembers().set(i, member); |
64 | return (N) this; |
65 | } |
66 | |
67 | @SuppressWarnings("unchecked") |
68 | default N addMember(BodyDeclaration<?> member) { |
69 | getMembers().add(member); |
70 | return (N) this; |
71 | } |
72 | |
73 | N setMembers(NodeList<BodyDeclaration<?>> members); |
74 | |
75 | /** |
76 | * Add a field to this and automatically add the import of the type if needed |
77 | * |
78 | * @param typeClass the type of the field |
79 | * @param name the name of the field |
80 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
81 | * @return the {@link FieldDeclaration} created |
82 | */ |
83 | default FieldDeclaration addField(Class<?> typeClass, String name, Modifier.Keyword... modifiers) { |
84 | tryAddImportToParentCompilationUnit(typeClass); |
85 | return addField(typeClass.getSimpleName(), name, modifiers); |
86 | } |
87 | |
88 | /** |
89 | * Add a field to this. |
90 | * |
91 | * @param type the type of the field |
92 | * @param name the name of the field |
93 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
94 | * @return the {@link FieldDeclaration} created |
95 | */ |
96 | default FieldDeclaration addField(String type, String name, Modifier.Keyword... modifiers) { |
97 | return addField(parseType(type), name, modifiers); |
98 | } |
99 | |
100 | /** |
101 | * Add a field to this. |
102 | * |
103 | * @param type the type of the field |
104 | * @param name the name of the field |
105 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
106 | * @return the {@link FieldDeclaration} created |
107 | */ |
108 | default FieldDeclaration addField(Type type, String name, Modifier.Keyword... modifiers) { |
109 | FieldDeclaration fieldDeclaration = new FieldDeclaration(); |
110 | VariableDeclarator variable = new VariableDeclarator(type, name); |
111 | fieldDeclaration.getVariables().add(variable); |
112 | fieldDeclaration.setModifiers(createModifierList(modifiers)); |
113 | getMembers().add(fieldDeclaration); |
114 | return fieldDeclaration; |
115 | } |
116 | |
117 | /** |
118 | * Add a field to this and automatically add the import of the type if needed |
119 | * |
120 | * @param typeClass the type of the field |
121 | * @param name the name of the field |
122 | * @param initializer the initializer of the field |
123 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
124 | * @return the {@link FieldDeclaration} created |
125 | */ |
126 | default FieldDeclaration addFieldWithInitializer(Class<?> typeClass, String name, Expression initializer, Modifier.Keyword... modifiers) { |
127 | tryAddImportToParentCompilationUnit(typeClass); |
128 | return addFieldWithInitializer(typeClass.getSimpleName(), name, initializer, modifiers); |
129 | } |
130 | |
131 | /** |
132 | * Add a field to this. |
133 | * |
134 | * @param type the type of the field |
135 | * @param name the name of the field |
136 | * @param initializer the initializer of the field |
137 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
138 | * @return the {@link FieldDeclaration} created |
139 | */ |
140 | default FieldDeclaration addFieldWithInitializer(String type, String name, Expression initializer, Modifier.Keyword... modifiers) { |
141 | return addFieldWithInitializer(parseType(type), name, initializer, modifiers); |
142 | } |
143 | |
144 | /** |
145 | * Add a field to this. |
146 | * |
147 | * @param type the type of the field |
148 | * @param name the name of the field |
149 | * @param initializer the initializer of the field |
150 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
151 | * @return the {@link FieldDeclaration} created |
152 | */ |
153 | default FieldDeclaration addFieldWithInitializer(Type type, String name, Expression initializer, Modifier.Keyword... modifiers) { |
154 | FieldDeclaration declaration = addField(type, name, modifiers); |
155 | declaration.getVariables().iterator().next().setInitializer(initializer); |
156 | return declaration; |
157 | } |
158 | |
159 | /** |
160 | * Add a private field to this. |
161 | * |
162 | * @param typeClass the type of the field |
163 | * @param name the name of the field |
164 | * @return the {@link FieldDeclaration} created |
165 | */ |
166 | default FieldDeclaration addPrivateField(Class<?> typeClass, String name) { |
167 | return addField(typeClass, name, PRIVATE); |
168 | } |
169 | |
170 | /** |
171 | * Add a private field to this and automatically add the import of the type if |
172 | * needed. |
173 | * |
174 | * @param type the type of the field |
175 | * @param name the name of the field |
176 | * @return the {@link FieldDeclaration} created |
177 | */ |
178 | default FieldDeclaration addPrivateField(String type, String name) { |
179 | return addField(type, name, PRIVATE); |
180 | } |
181 | |
182 | /** |
183 | * Add a private field to this. |
184 | * |
185 | * @param type the type of the field |
186 | * @param name the name of the field |
187 | * @return the {@link FieldDeclaration} created |
188 | */ |
189 | default FieldDeclaration addPrivateField(Type type, String name) { |
190 | return addField(type, name, PRIVATE); |
191 | } |
192 | |
193 | /** |
194 | * Add a public field to this. |
195 | * |
196 | * @param typeClass the type of the field |
197 | * @param name the name of the field |
198 | * @return the {@link FieldDeclaration} created |
199 | */ |
200 | default FieldDeclaration addPublicField(Class<?> typeClass, String name) { |
201 | return addField(typeClass, name, PUBLIC); |
202 | } |
203 | |
204 | /** |
205 | * Add a public field to this and automatically add the import of the type if |
206 | * needed. |
207 | * |
208 | * @param type the type of the field |
209 | * @param name the name of the field |
210 | * @return the {@link FieldDeclaration} created |
211 | */ |
212 | default FieldDeclaration addPublicField(String type, String name) { |
213 | return addField(type, name, PUBLIC); |
214 | } |
215 | |
216 | /** |
217 | * Add a public field to this. |
218 | * |
219 | * @param type the type of the field |
220 | * @param name the name of the field |
221 | * @return the {@link FieldDeclaration} created |
222 | */ |
223 | default FieldDeclaration addPublicField(Type type, String name) { |
224 | return addField(type, name, PUBLIC); |
225 | } |
226 | |
227 | /** |
228 | * Add a protected field to this. |
229 | * |
230 | * @param typeClass the type of the field |
231 | * @param name the name of the field |
232 | * @return the {@link FieldDeclaration} created |
233 | */ |
234 | default FieldDeclaration addProtectedField(Class<?> typeClass, String name) { |
235 | return addField(typeClass, name, PROTECTED); |
236 | } |
237 | |
238 | /** |
239 | * Add a protected field to this and automatically add the import of the type |
240 | * if needed. |
241 | * |
242 | * @param type the type of the field |
243 | * @param name the name of the field |
244 | * @return the {@link FieldDeclaration} created |
245 | */ |
246 | default FieldDeclaration addProtectedField(String type, String name) { |
247 | return addField(type, name, PROTECTED); |
248 | } |
249 | |
250 | /** |
251 | * Add a protected field to this. |
252 | * |
253 | * @param type the type of the field |
254 | * @param name the name of the field |
255 | * @return the {@link FieldDeclaration} created |
256 | */ |
257 | default FieldDeclaration addProtectedField(Type type, String name) { |
258 | return addField(type, name, PROTECTED); |
259 | } |
260 | |
261 | /** |
262 | * Adds a methods with void return by default to this. |
263 | * |
264 | * @param methodName the method name |
265 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
266 | * @return the {@link MethodDeclaration} created |
267 | */ |
268 | default MethodDeclaration addMethod(String methodName, Keyword... modifiers) { |
269 | MethodDeclaration methodDeclaration = new MethodDeclaration(); |
270 | methodDeclaration.setName(methodName); |
271 | methodDeclaration.setType(new VoidType()); |
272 | methodDeclaration.setModifiers(createModifierList(modifiers)); |
273 | getMembers().add(methodDeclaration); |
274 | return methodDeclaration; |
275 | } |
276 | |
277 | /** |
278 | * Adds a constructor to this node with members. |
279 | * |
280 | * @param modifiers the modifiers like {@link Modifier.Keyword#PUBLIC} |
281 | * @return the created constructor |
282 | */ |
283 | default ConstructorDeclaration addConstructor(Modifier.Keyword... modifiers) { |
284 | ConstructorDeclaration constructorDeclaration = new ConstructorDeclaration(); |
285 | constructorDeclaration.setModifiers(createModifierList(modifiers)); |
286 | constructorDeclaration.setName(getName()); |
287 | getMembers().add(constructorDeclaration); |
288 | return constructorDeclaration; |
289 | } |
290 | |
291 | /** |
292 | * Add an initializer block ({@link InitializerDeclaration}) to this. |
293 | */ |
294 | default BlockStmt addInitializer() { |
295 | BlockStmt block = new BlockStmt(); |
296 | InitializerDeclaration initializerDeclaration = new InitializerDeclaration(false, block); |
297 | getMembers().add(initializerDeclaration); |
298 | return block; |
299 | } |
300 | |
301 | /** |
302 | * Add a static initializer block ({@link InitializerDeclaration}) to this. |
303 | */ |
304 | default BlockStmt addStaticInitializer() { |
305 | BlockStmt block = new BlockStmt(); |
306 | InitializerDeclaration initializerDeclaration = new InitializerDeclaration(true, block); |
307 | getMembers().add(initializerDeclaration); |
308 | return block; |
309 | } |
310 | |
311 | /** |
312 | * Try to find a {@link MethodDeclaration} by its name |
313 | * |
314 | * @param name the name of the method |
315 | * @return the methods found (multiple in case of overloading) |
316 | */ |
317 | default List<MethodDeclaration> getMethodsByName(String name) { |
318 | return unmodifiableList(getMethods().stream() |
319 | .filter(m -> m.getNameAsString().equals(name)) |
320 | .collect(toList())); |
321 | } |
322 | |
323 | /** |
324 | * Find all methods in the members of this node. |
325 | * |
326 | * @return the methods found. This list is immutable. |
327 | */ |
328 | default List<MethodDeclaration> getMethods() { |
329 | return unmodifiableList(getMembers().stream() |
330 | .filter(m -> m instanceof MethodDeclaration) |
331 | .map(m -> (MethodDeclaration) m) |
332 | .collect(toList())); |
333 | } |
334 | |
335 | /** |
336 | * Try to find a {@link MethodDeclaration} by its parameter types. The given parameter types must <i>literally</i> |
337 | * match the declared types of this node's parameters, so passing the string {@code "List"} to this method will find |
338 | * all methods that have exactly one parameter whose type is declared as {@code List}, but not methods with exactly |
339 | * one parameter whose type is declared as {@code java.util.List} or {@code java.awt.List}. Conversely, passing the |
340 | * string {@code "java.util.List"} to this method will find all methods that have exactly one parameter whose type |
341 | * is declared as {@code java.util.List}, but not if the parameter type is declared as {@code List}. Similarly, |
342 | * note that generics are matched as well: If there is a method that has a parameter declared as |
343 | * {@code List<String>}, then it will be considered as a match only if the given string is |
344 | * {@code "List<String>"}, but not if the given string is only {@code "List"}. |
345 | * |
346 | * @param paramTypes the types of parameters like {@code "Map<Integer, String>", "int"} to match |
347 | * {@code void foo(Map<Integer,String> myMap, int number)} |
348 | * @return the methods found |
349 | */ |
350 | default List<MethodDeclaration> getMethodsByParameterTypes(String... paramTypes) { |
351 | return unmodifiableList(getMethods().stream() |
352 | .filter(m -> m.hasParametersOfType(paramTypes)) |
353 | .collect(toList())); |
354 | } |
355 | |
356 | /** |
357 | * Try to find {@link MethodDeclaration}s by their name and parameter types. Parameter types are matched exactly as |
358 | * in the case of {@link #getMethodsByParameterTypes(String...)}. |
359 | * |
360 | * @param paramTypes the types of parameters like {@code "Map<Integer, String>", "int"} to match |
361 | * {@code void foo(Map<Integer,String> myMap, int number)} |
362 | * @return the methods found |
363 | */ |
364 | default List<MethodDeclaration> getMethodsBySignature(String name, String... paramTypes) { |
365 | return unmodifiableList(getMethodsByName(name).stream() |
366 | .filter(m -> m.hasParametersOfType(paramTypes)) |
367 | .collect(toList())); |
368 | } |
369 | |
370 | /** |
371 | * Try to find a {@link MethodDeclaration} by its parameter types. Note that this is a match in SimpleName, so |
372 | * {@code java.awt.List} and {@code java.util.List} are identical to this algorithm. In addition, note that it is |
373 | * the erasure of each type which is considered, so passing {@code List.class} to this method will return all |
374 | * methods that have exactly one parameter whose type is named {@code List}, regardless of whether the parameter |
375 | * type is declared without generics as {@code List}, or with generics as {@code List<String>}, or |
376 | * {@code List<Integer>}, etc. |
377 | * |
378 | * @param paramTypes the types of parameters like {@code Map.class, int.class} to match |
379 | * {@code void foo(Map<Integer,String> myMap, int number)} |
380 | * @return the methods found |
381 | */ |
382 | default List<MethodDeclaration> getMethodsByParameterTypes(Class<?>... paramTypes) { |
383 | return unmodifiableList(getMethods().stream() |
384 | .filter(m -> m.hasParametersOfType(paramTypes)) |
385 | .collect(toList())); |
386 | } |
387 | |
388 | /** |
389 | * Find all constructors in the members of this node. |
390 | * |
391 | * @return the constructors found. This list is immutable. |
392 | */ |
393 | default List<ConstructorDeclaration> getConstructors() { |
394 | return unmodifiableList(getMembers().stream() |
395 | .filter(m -> m instanceof ConstructorDeclaration) |
396 | .map(m -> (ConstructorDeclaration) m) |
397 | .collect(toList())); |
398 | } |
399 | |
400 | /** |
401 | * Try to find a {@link ConstructorDeclaration} with no parameters. |
402 | * |
403 | * @return the constructor found, if any. |
404 | */ |
405 | default Optional<ConstructorDeclaration> getDefaultConstructor() { |
406 | return getMembers().stream() |
407 | .filter(m -> m instanceof ConstructorDeclaration) |
408 | .map(m -> (ConstructorDeclaration) m) |
409 | .filter(cd -> cd.getParameters().isEmpty()) |
410 | .findFirst(); |
411 | } |
412 | |
413 | /** |
414 | * Try to find a {@link ConstructorDeclaration} by its parameter types. The given parameter types must |
415 | * <i>literally</i> match the declared types of the desired constructor, so passing the string {@code "List"} to |
416 | * this method will search for a constructor that has exactly one parameter whose type is declared as {@code List}, |
417 | * but not for a constructor with exactly one parameter whose type is declared as {@code java.util.List} or |
418 | * {@code java.awt.List}. Conversely, passing the string {@code "java.util.List"} to this method will search for a |
419 | * constructor that has exactly one parameter whose type is declared as {@code java.util.List}, but not for a |
420 | * constructor whose type is declared as {@code List}. Similarly, note that generics are matched as well: If there |
421 | * is a constructor that has a parameter declared as {@code List<String>}, then it will be considered as a |
422 | * match only if the given string is {@code "List<String>"}, but not if the given string is only |
423 | * {@code "List"}. |
424 | * |
425 | * @param paramTypes the types of parameters like {@code "Map<Integer, String>", "int"} to match |
426 | * {@code Foo(Map<Integer,String> myMap, int number)} |
427 | * @return the constructor found, if any. |
428 | */ |
429 | default Optional<ConstructorDeclaration> getConstructorByParameterTypes(String... paramTypes) { |
430 | return getConstructors().stream() |
431 | .filter(m -> m.hasParametersOfType(paramTypes)) |
432 | .findFirst(); |
433 | } |
434 | |
435 | /** |
436 | * Try to find a {@link ConstructorDeclaration} by its parameter types. Note that this is a match in SimpleName, |
437 | * so {@code java.awt.List} and {@code java.util.List} are identical to this algorithm. In addition, note that it is |
438 | * the erasure of each type which is considered, so passing {@code List.class} to this method will search for a |
439 | * constructor that has exactly one parameter whose type is named {@code List}, regardless of whether the parameter |
440 | * type is declared without generics as {@code List}, or with generics as {@code List<String>}, or |
441 | * {@code List<Integer>}, etc. |
442 | * |
443 | * @param paramTypes the types of parameters like {@code Map.class, int.class} to match |
444 | * {@code Foo(Map<Integer,String> myMap, int number)} |
445 | * @return the constructor found, if any. |
446 | */ |
447 | default Optional<ConstructorDeclaration> getConstructorByParameterTypes(Class<?>... paramTypes) { |
448 | return getConstructors().stream() |
449 | .filter(m -> m.hasParametersOfType(paramTypes)) |
450 | .findFirst(); |
451 | } |
452 | |
453 | /** |
454 | * Try to find a {@link FieldDeclaration} by its name |
455 | * |
456 | * @param name the name of the field |
457 | * @return null if not found, the FieldDeclaration otherwise |
458 | */ |
459 | default Optional<FieldDeclaration> getFieldByName(String name) { |
460 | return getMembers().stream() |
461 | .filter(m -> m instanceof FieldDeclaration) |
462 | .map(f -> (FieldDeclaration) f) |
463 | .filter(f -> f.getVariables().stream() |
464 | .anyMatch(var -> var.getNameAsString().equals(name))) |
465 | .findFirst(); |
466 | } |
467 | |
468 | /** |
469 | * Find all fields in the members of this node. |
470 | * |
471 | * @return the fields found. This list is immutable. |
472 | */ |
473 | default List<FieldDeclaration> getFields() { |
474 | return unmodifiableList(getMembers().stream() |
475 | .filter(m -> m instanceof FieldDeclaration) |
476 | .map(m -> (FieldDeclaration) m) |
477 | .collect(toList())); |
478 | } |
479 | |
480 | /** |
481 | * @return true if there are no members contained in this node. |
482 | */ |
483 | default boolean isEmpty() { |
484 | return getMembers().isEmpty(); |
485 | } |
486 | } |
487 |
Members