CompilationUnit.java revision e4610d5f3acd6d03bf51e8c70584a065d3233387
1/*
2 * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3 * Copyright (C) 2011, 2013-2016 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 */
21package com.github.javaparser.ast;
22
23import com.github.javaparser.JavaParser;
24import com.github.javaparser.Range;
25import com.github.javaparser.ast.body.AnnotationDeclaration;
26import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
27import com.github.javaparser.ast.body.EnumDeclaration;
28import com.github.javaparser.ast.body.TypeDeclaration;
29import com.github.javaparser.ast.comments.Comment;
30import com.github.javaparser.ast.comments.JavadocComment;
31import com.github.javaparser.ast.expr.Name;
32import com.github.javaparser.ast.modules.ModuleDeclaration;
33import com.github.javaparser.ast.observer.ObservableProperty;
34import com.github.javaparser.ast.visitor.CloneVisitor;
35import com.github.javaparser.ast.visitor.GenericVisitor;
36import com.github.javaparser.ast.visitor.VoidVisitor;
37import com.github.javaparser.metamodel.CompilationUnitMetaModel;
38import com.github.javaparser.metamodel.InternalProperty;
39import com.github.javaparser.metamodel.JavaParserMetaModel;
40import com.github.javaparser.utils.ClassUtils;
41import java.util.Arrays;
42import java.util.EnumSet;
43import java.util.List;
44import java.util.Optional;
45import java.util.stream.Collectors;
46import static com.github.javaparser.JavaParser.parseName;
47import static com.github.javaparser.utils.Utils.assertNotNull;
48import javax.annotation.Generated;
49
50/**
51 * <p>
52 * This class represents the entire compilation unit. Each java file denotes a
53 * compilation unit.
54 * </p>
55 * A compilation unit start with an optional package declaration,
56 * followed by zero or more import declarations,
57 * followed by zero or more type declarations.
58 *
59 * @author Julio Vilmar Gesser
60 * @see PackageDeclaration
61 * @see ImportDeclaration
62 * @see TypeDeclaration
63 */
64public final class CompilationUnit extends Node {
65
66    private PackageDeclaration packageDeclaration;
67
68    private NodeList<ImportDeclaration> imports;
69
70    private NodeList<TypeDeclaration<?>> types;
71
72    private ModuleDeclaration module;
73
74    public CompilationUnit() {
75        this(null, null, new NodeList<>(), new NodeList<>(), null);
76    }
77
78    public CompilationUnit(String packageDeclaration) {
79        this(null, new PackageDeclaration(new Name(packageDeclaration)), new NodeList<>(), new NodeList<>(), null);
80    }
81
82    @AllFieldsConstructor
83    public CompilationUnit(PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module) {
84        this(null, packageDeclaration, imports, types, module);
85    }
86
87    /**This constructor is used by the parser and is considered private.*/
88    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
89    public CompilationUnit(Range range, PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module) {
90        super(range);
91        setPackageDeclaration(packageDeclaration);
92        setImports(imports);
93        setTypes(types);
94        setModule(module);
95        customInitialization();
96    }
97
98    @Override
99    public <R, A> R accept(GenericVisitor<R, A> v, A arg) {
100        return v.visit(this, arg);
101    }
102
103    @Override
104    public <A> void accept(VoidVisitor<A> v, A arg) {
105        v.visit(this, arg);
106    }
107
108    /**
109     * Return a list containing all comments declared in this compilation unit.
110     * Including javadocs, line comments and block comments of all types,
111     * inner-classes and other members.<br>
112     * If there is no comment, an empty list is returned.
113     *
114     * @return list with all comments of this compilation unit.
115     * @see JavadocComment
116     * @see com.github.javaparser.ast.comments.LineComment
117     * @see com.github.javaparser.ast.comments.BlockComment
118     */
119    public List<Comment> getComments() {
120        return this.getAllContainedComments();
121    }
122
123    /**
124     * Retrieves the list of imports declared in this compilation unit or
125     * <code>null</code> if there is no import.
126     *
127     * @return the list of imports or <code>none</code> if there is no import
128     */
129    public NodeList<ImportDeclaration> getImports() {
130        return imports;
131    }
132
133    public ImportDeclaration getImport(int i) {
134        return getImports().get(i);
135    }
136
137    /**
138     * Retrieves the package declaration of this compilation unit.<br>
139     * If this compilation unit has no package declaration (default package),
140     * <code>Optional.none()</code> is returned.
141     *
142     * @return the package declaration or <code>none</code>
143     */
144    public Optional<PackageDeclaration> getPackageDeclaration() {
145        return Optional.ofNullable(packageDeclaration);
146    }
147
148    /**
149     * Return the list of types declared in this compilation unit.<br>
150     * If there is no types declared, <code>none</code> is returned.
151     *
152     * @return the list of types or <code>none</code> null if there is no type
153     * @see AnnotationDeclaration
154     * @see ClassOrInterfaceDeclaration
155     * @see EnumDeclaration
156     */
157    public NodeList<TypeDeclaration<?>> getTypes() {
158        return types;
159    }
160
161    /**
162     * Convenience method that wraps <code>getTypes()</code>.<br>
163     * If <code>i</code> is out of bounds, throws <code>IndexOutOfBoundsException.</code>
164     *
165     * @param i the index of the type declaration to retrieve
166     */
167    public TypeDeclaration<?> getType(int i) {
168        return getTypes().get(i);
169    }
170
171    /**
172     * Sets the list of imports of this compilation unit. The list is initially
173     * <code>null</code>.
174     *
175     * @param imports the list of imports
176     */
177    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
178    public CompilationUnit setImports(final NodeList<ImportDeclaration> imports) {
179        assertNotNull(imports);
180        if (imports == this.imports) {
181            return (CompilationUnit) this;
182        }
183        notifyPropertyChange(ObservableProperty.IMPORTS, this.imports, imports);
184        if (this.imports != null)
185            this.imports.setParentNode(null);
186        this.imports = imports;
187        setAsParentNodeOf(imports);
188        return this;
189    }
190
191    public CompilationUnit setImport(int i, ImportDeclaration imports) {
192        getImports().set(i, imports);
193        return this;
194    }
195
196    public CompilationUnit addImport(ImportDeclaration imports) {
197        getImports().add(imports);
198        return this;
199    }
200
201    /**
202     * Sets or clear the package declarations of this compilation unit.
203     *
204     * @param packageDeclaration the packageDeclaration declaration to set or <code>null</code> to default package
205     */
206    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
207    public CompilationUnit setPackageDeclaration(final PackageDeclaration packageDeclaration) {
208        if (packageDeclaration == this.packageDeclaration) {
209            return (CompilationUnit) this;
210        }
211        notifyPropertyChange(ObservableProperty.PACKAGE_DECLARATION, this.packageDeclaration, packageDeclaration);
212        if (this.packageDeclaration != null)
213            this.packageDeclaration.setParentNode(null);
214        this.packageDeclaration = packageDeclaration;
215        setAsParentNodeOf(packageDeclaration);
216        return this;
217    }
218
219    /**
220     * Sets the list of types declared in this compilation unit.
221     */
222    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
223    public CompilationUnit setTypes(final NodeList<TypeDeclaration<?>> types) {
224        assertNotNull(types);
225        if (types == this.types) {
226            return (CompilationUnit) this;
227        }
228        notifyPropertyChange(ObservableProperty.TYPES, this.types, types);
229        if (this.types != null)
230            this.types.setParentNode(null);
231        this.types = types;
232        setAsParentNodeOf(types);
233        return this;
234    }
235
236    public CompilationUnit setType(int i, TypeDeclaration<?> type) {
237        NodeList<TypeDeclaration<?>> copy = new NodeList<>();
238        copy.addAll(getTypes());
239        getTypes().set(i, type);
240        notifyPropertyChange(ObservableProperty.TYPES, copy, types);
241        return this;
242    }
243
244    public CompilationUnit addType(TypeDeclaration<?> type) {
245        NodeList<TypeDeclaration<?>> copy = new NodeList<>();
246        copy.addAll(getTypes());
247        getTypes().add(type);
248        notifyPropertyChange(ObservableProperty.TYPES, copy, types);
249        return this;
250    }
251
252    /**
253     * sets the package declaration of this compilation unit
254     *
255     * @param name the name of the package
256     * @return this, the {@link CompilationUnit}
257     */
258    public CompilationUnit setPackageDeclaration(String name) {
259        setPackageDeclaration(new PackageDeclaration(parseName(name)));
260        return this;
261    }
262
263    /**
264     * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
265     * shorthand for {@link #addImport(String, boolean, boolean)} with name,false,false
266     *
267     * @param name the import name
268     * @return this, the {@link CompilationUnit}
269     */
270    public CompilationUnit addImport(String name) {
271        return addImport(name, false, false);
272    }
273
274    /**
275     * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
276     * shorthand for {@link #addImport(String)} with clazz.getName()
277     *
278     * @param clazz the class to import
279     * @return this, the {@link CompilationUnit}
280     */
281    public CompilationUnit addImport(Class<?> clazz) {
282        if (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.getName().startsWith("java.lang"))
283            return this;
284        else if (clazz.isArray() && !ClassUtils.isPrimitiveOrWrapper(clazz.getComponentType()) && !clazz.getComponentType().getName().startsWith("java.lang"))
285            return addImport(clazz.getComponentType().getName());
286        return addImport(clazz.getName());
287    }
288
289    /**
290     * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
291     * <b>This method check if no import with the same name is already in the list</b>
292     *
293     * @param name the import name
294     * @param isStatic is it an "import static"
295     * @param isAsterisk does the import end with ".*"
296     * @return this, the {@link CompilationUnit}
297     */
298    public CompilationUnit addImport(String name, boolean isStatic, boolean isAsterisk) {
299        final StringBuilder i = new StringBuilder("import ");
300        if (isStatic) {
301            i.append("static ");
302        }
303        i.append(name);
304        if (isAsterisk) {
305            i.append(".*");
306        }
307        i.append(";");
308        ImportDeclaration importDeclaration = JavaParser.parseImport(i.toString());
309        if (getImports().stream().anyMatch(im -> im.toString().equals(importDeclaration.toString())))
310            return this;
311        else {
312            getImports().add(importDeclaration);
313            return this;
314        }
315    }
316
317    /**
318     * Add a public class to the types of this compilation unit
319     *
320     * @param name the class name
321     * @return the newly created class
322     */
323    public ClassOrInterfaceDeclaration addClass(String name) {
324        return addClass(name, Modifier.PUBLIC);
325    }
326
327    /**
328     * Add a class to the types of this compilation unit
329     *
330     * @param name the class name
331     * @param modifiers the modifiers (like Modifier.PUBLIC)
332     * @return the newly created class
333     */
334    public ClassOrInterfaceDeclaration addClass(String name, Modifier... modifiers) {
335        ClassOrInterfaceDeclaration classOrInterfaceDeclaration = new ClassOrInterfaceDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), false, name);
336        getTypes().add(classOrInterfaceDeclaration);
337        return classOrInterfaceDeclaration;
338    }
339
340    /**
341     * Add a public interface class to the types of this compilation unit
342     *
343     * @param name the interface name
344     * @return the newly created class
345     */
346    public ClassOrInterfaceDeclaration addInterface(String name) {
347        return addInterface(name, Modifier.PUBLIC);
348    }
349
350    /**
351     * Add an interface to the types of this compilation unit
352     *
353     * @param name the interface name
354     * @param modifiers the modifiers (like Modifier.PUBLIC)
355     * @return the newly created class
356     */
357    public ClassOrInterfaceDeclaration addInterface(String name, Modifier... modifiers) {
358        ClassOrInterfaceDeclaration classOrInterfaceDeclaration = new ClassOrInterfaceDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), true, name);
359        getTypes().add(classOrInterfaceDeclaration);
360        return classOrInterfaceDeclaration;
361    }
362
363    /**
364     * Add a public enum to the types of this compilation unit
365     *
366     * @param name the enum name
367     * @return the newly created class
368     */
369    public EnumDeclaration addEnum(String name) {
370        return addEnum(name, Modifier.PUBLIC);
371    }
372
373    /**
374     * Add an enum to the types of this compilation unit
375     *
376     * @param name the enum name
377     * @param modifiers the modifiers (like Modifier.PUBLIC)
378     * @return the newly created class
379     */
380    public EnumDeclaration addEnum(String name, Modifier... modifiers) {
381        EnumDeclaration enumDeclaration = new EnumDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), name);
382        getTypes().add(enumDeclaration);
383        return enumDeclaration;
384    }
385
386    /**
387     * Add a public annotation declaration to the types of this compilation unit
388     *
389     * @param name the annotation name
390     * @return the newly created class
391     */
392    public AnnotationDeclaration addAnnotationDeclaration(String name) {
393        return addAnnotationDeclaration(name, Modifier.PUBLIC);
394    }
395
396    /**
397     * Add an annotation declaration to the types of this compilation unit
398     *
399     * @param name the annotation name
400     * @param modifiers the modifiers (like Modifier.PUBLIC)
401     * @return the newly created class
402     */
403    public AnnotationDeclaration addAnnotationDeclaration(String name, Modifier... modifiers) {
404        AnnotationDeclaration annotationDeclaration = new AnnotationDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), name);
405        getTypes().add(annotationDeclaration);
406        return annotationDeclaration;
407    }
408
409    /**
410     * Try to get a class by its name
411     *
412     * @param className the class name (case-sensitive)
413     */
414    public Optional<ClassOrInterfaceDeclaration> getClassByName(String className) {
415        return getTypes().stream().filter(type -> type.getNameAsString().equals(className) && type instanceof ClassOrInterfaceDeclaration && !((ClassOrInterfaceDeclaration) type).isInterface()).findFirst().map(t -> (ClassOrInterfaceDeclaration) t);
416    }
417
418    /**
419     * Try to get an interface by its name
420     *
421     * @param interfaceName the interface name (case-sensitive)
422     */
423    public Optional<ClassOrInterfaceDeclaration> getInterfaceByName(String interfaceName) {
424        return getTypes().stream().filter(type -> type.getNameAsString().equals(interfaceName) && type instanceof ClassOrInterfaceDeclaration && ((ClassOrInterfaceDeclaration) type).isInterface()).findFirst().map(t -> (ClassOrInterfaceDeclaration) t);
425    }
426
427    /**
428     * Try to get an enum by its name
429     *
430     * @param enumName the enum name (case-sensitive)
431     */
432    public Optional<EnumDeclaration> getEnumByName(String enumName) {
433        return getTypes().stream().filter(type -> type.getNameAsString().equals(enumName) && type instanceof EnumDeclaration).findFirst().map(t -> (EnumDeclaration) t);
434    }
435
436    /**
437     * Try to get an annotation by its name
438     *
439     * @param annotationName the annotation name (case-sensitive)
440     */
441    public Optional<AnnotationDeclaration> getAnnotationDeclarationByName(String annotationName) {
442        return getTypes().stream().filter(type -> type.getNameAsString().equals(annotationName) && type instanceof AnnotationDeclaration).findFirst().map(t -> (AnnotationDeclaration) t);
443    }
444
445    @Override
446    @Generated("com.github.javaparser.generator.core.node.GetNodeListsGenerator")
447    public List<NodeList<?>> getNodeLists() {
448        return Arrays.asList(getImports(), getTypes());
449    }
450
451    @Override
452    public boolean remove(Node node) {
453        if (node == null)
454            return false;
455        for (int i = 0; i < imports.size(); i++) {
456            if (imports.get(i) == node) {
457                imports.remove(i);
458                return true;
459            }
460        }
461        if (module != null) {
462            if (node == module) {
463                removeModule();
464                return true;
465            }
466        }
467        if (packageDeclaration != null) {
468            if (node == packageDeclaration) {
469                removePackageDeclaration();
470                return true;
471            }
472        }
473        for (int i = 0; i < types.size(); i++) {
474            if (types.get(i) == node) {
475                types.remove(i);
476                return true;
477            }
478        }
479        return super.remove(node);
480    }
481
482    public CompilationUnit removePackageDeclaration() {
483        return setPackageDeclaration((PackageDeclaration) null);
484    }
485
486    public Optional<ModuleDeclaration> getModule() {
487        return Optional.ofNullable(module);
488    }
489
490    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
491    public CompilationUnit setModule(final ModuleDeclaration module) {
492        if (module == this.module) {
493            return (CompilationUnit) this;
494        }
495        notifyPropertyChange(ObservableProperty.MODULE, this.module, module);
496        if (this.module != null)
497            this.module.setParentNode(null);
498        this.module = module;
499        setAsParentNodeOf(module);
500        return this;
501    }
502
503    public CompilationUnit removeModule() {
504        return setModule((ModuleDeclaration) null);
505    }
506
507    @Override
508    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
509    public CompilationUnit clone() {
510        return (CompilationUnit) accept(new CloneVisitor(), null);
511    }
512
513    @Override
514    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
515    public CompilationUnitMetaModel getMetaModel() {
516        return JavaParserMetaModel.compilationUnitMetaModel;
517    }
518}
519