Improve often-used class imports
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / JavaFileTemplate.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.java.api.generator;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import java.util.Arrays;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Objects;
18 import java.util.Optional;
19 import java.util.regex.Pattern;
20 import java.util.stream.Collectors;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.mdsal.binding.model.api.ConcreteType;
23 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
24 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
25 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
26 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
27 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
28 import org.opendaylight.mdsal.binding.model.api.Restrictions;
29 import org.opendaylight.mdsal.binding.model.api.Type;
30 import org.opendaylight.mdsal.binding.model.util.Types;
31 import org.opendaylight.yangtools.yang.binding.CodeHelpers;
32
33 /**
34  * Base Java file template. Contains a non-null type and imports which the generated code refers to.
35  */
36 class JavaFileTemplate {
37     /**
38      * {@code java.lang.Class} as a JavaTypeName.
39      */
40     static final @NonNull JavaTypeName CLASS = JavaTypeName.create(Class.class);
41     /**
42      * {@code java.lang.Deprecated} as a JavaTypeName.
43      */
44     static final @NonNull JavaTypeName DEPRECATED = JavaTypeName.create(Deprecated.class);
45     /**
46      * {@code java.lang.Override} as a JavaTypeName.
47      */
48     static final @NonNull JavaTypeName OVERRIDE = JavaTypeName.create(Override.class);
49
50     /**
51      * {@code java.lang.SuppressWarnings} as a JavaTypeName.
52      */
53     static final @NonNull JavaTypeName SUPPRESS_WARNINGS = JavaTypeName.create(SuppressWarnings.class);
54
55     /**
56      * {@code java.util.Arrays} as a JavaTypeName.
57      */
58     static final @NonNull JavaTypeName JU_ARRAYS = JavaTypeName.create(Arrays.class);
59     /**
60      * {@code java.util.HashMap} as a JavaTypeName.
61      */
62     static final @NonNull JavaTypeName JU_HASHMAP = JavaTypeName.create(HashMap.class);
63     /**
64      * {@code java.util.List} as a JavaTypeName.
65      */
66     static final @NonNull JavaTypeName JU_LIST = JavaTypeName.create(List.class);
67     /**
68      * {@code java.util.Map} as a JavaTypeName.
69      */
70     static final @NonNull JavaTypeName JU_MAP = JavaTypeName.create(Map.class);
71     /**
72      * {@code java.util.Objects} as a JavaTypeName.
73      */
74     static final @NonNull JavaTypeName JU_OBJECTS = JavaTypeName.create(Objects.class);
75     /**
76      * {@code java.util.regex.Pattern} as a JavaTypeName.
77      */
78     static final @NonNull JavaTypeName JUR_PATTERN = JavaTypeName.create(Pattern.class);
79
80     /**
81      * {@code org.eclipse.jdt.annotation.NonNull} as a JavaTypeName.
82      */
83     static final @NonNull JavaTypeName NONNULL = JavaTypeName.create("org.eclipse.jdt.annotation", "NonNull");
84     /**
85      * {@code org.eclipse.jdt.annotation.Nullable} as a JavaTypeName.
86      */
87     static final @NonNull JavaTypeName NULLABLE = JavaTypeName.create("org.eclipse.jdt.annotation", "Nullable");
88
89     /**
90      * {@code org.opendaylight.yangtools.yang.binding.CodeHelpers} as a JavaTypeName.
91      */
92     static final @NonNull JavaTypeName CODEHELPERS = JavaTypeName.create(CodeHelpers.class);
93
94     private final AbstractJavaGeneratedType javaType;
95     private final GeneratedType type;
96
97     JavaFileTemplate(final @NonNull GeneratedType type) {
98         this(new TopLevelJavaGeneratedType(type), type);
99     }
100
101     JavaFileTemplate(final AbstractJavaGeneratedType javaType, final GeneratedType type) {
102         this.javaType = requireNonNull(javaType);
103         this.type = requireNonNull(type);
104     }
105
106     final AbstractJavaGeneratedType javaType() {
107         return javaType;
108     }
109
110     final GeneratedType type() {
111         return type;
112     }
113
114     final String generateImportBlock() {
115         verify(javaType instanceof TopLevelJavaGeneratedType);
116         return ((TopLevelJavaGeneratedType) javaType).imports().map(name -> "import " + name + ";\n")
117                 .collect(Collectors.joining());
118     }
119
120     final @NonNull String importedJavadocName(final @NonNull Type intype) {
121         return importedName(intype instanceof ParameterizedType ? ((ParameterizedType) intype).getRawType() : intype);
122     }
123
124     final @NonNull String importedName(final @NonNull Type intype) {
125         return javaType.getReferenceString(intype);
126     }
127
128     final @NonNull String importedName(final @NonNull Type intype, final @NonNull String annotation) {
129         return javaType.getReferenceString(intype, annotation);
130     }
131
132     final @NonNull String importedName(final Class<?> cls) {
133         return importedName(Types.typeForClass(cls));
134     }
135
136     final @NonNull String importedName(final @NonNull JavaTypeName intype) {
137         return javaType.getReferenceString(intype);
138     }
139
140     final @NonNull String importedNonNull(final @NonNull Type intype) {
141         return importedName(intype, importedName(NONNULL));
142     }
143
144     final @NonNull String importedNullable(final @NonNull Type intype) {
145         return importedName(intype, importedName(NULLABLE));
146     }
147
148     // Exposed for BuilderTemplate
149     boolean isLocalInnerClass(final JavaTypeName name) {
150         final Optional<JavaTypeName> optEnc = name.immediatelyEnclosingClass();
151         return optEnc.isPresent() && type.getIdentifier().equals(optEnc.get());
152     }
153
154     final CharSequence generateInnerClass(final GeneratedType innerClass) {
155         if (!(innerClass instanceof GeneratedTransferObject)) {
156             return "";
157         }
158
159         final GeneratedTransferObject gto = (GeneratedTransferObject) innerClass;
160         final NestedJavaGeneratedType innerJavaType = javaType.getEnclosedType(innerClass.getIdentifier());
161         return gto.isUnionType() ? new UnionTemplate(innerJavaType, gto).generateAsInnerClass()
162                 : new ClassTemplate(innerJavaType, gto).generateAsInnerClass();
163     }
164
165     /**
166      * Return imported name of java.util class, whose hashCode/equals methods we want to invoke on the property. Returns
167      * {@link Arrays} if the property is an array, {@link Objects} otherwise.
168      *
169      * @param property Generated property
170      * @return Imported class name
171      */
172     final String importedUtilClass(final GeneratedProperty property) {
173         return importedName(property.getReturnType().getName().indexOf('[') != -1 ? JU_ARRAYS : JU_OBJECTS);
174     }
175
176     static final Restrictions restrictionsForSetter(final Type actualType) {
177         return actualType instanceof GeneratedType ? null : getRestrictions(actualType);
178     }
179
180     static final Restrictions getRestrictions(final Type type) {
181         if (type instanceof ConcreteType) {
182             return ((ConcreteType) type).getRestrictions();
183         }
184         if (type instanceof GeneratedTransferObject) {
185             return ((GeneratedTransferObject) type).getRestrictions();
186         }
187         return null;
188     }
189 }