1 package org.onap.graphinventory.generate;
3 import java.io.IOException;
4 import java.nio.file.Paths;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Comparator;
10 import java.util.Map.Entry;
11 import java.util.stream.Collectors;
12 import javax.lang.model.element.Modifier;
13 import org.apache.commons.lang3.ArrayUtils;
14 import org.apache.commons.lang3.tuple.Pair;
15 import org.apache.maven.plugin.logging.Log;
16 import com.fasterxml.jackson.core.JsonProcessingException;
17 import com.google.common.base.CaseFormat;
18 import com.squareup.javapoet.ClassName;
19 import com.squareup.javapoet.CodeBlock;
20 import com.squareup.javapoet.FieldSpec;
21 import com.squareup.javapoet.JavaFile;
22 import com.squareup.javapoet.MethodSpec;
23 import com.squareup.javapoet.ParameterSpec;
24 import com.squareup.javapoet.ParameterizedTypeName;
25 import com.squareup.javapoet.TypeSpec;
27 public class FluentGenerator {
29 private final Map<String, ObjectType> doc;
30 private final String location;
31 private final String CLASSPATH;
33 private final String singularBuilderClass;
34 private final String pluralBuilderClass;
35 private final String topLevelBuilderClass;
36 private final String baseBuilderClass;
37 private final String singularClass;
38 private final String pluralClass;
39 private final String builderName;
40 private final String nameClass;
42 public FluentGenerator(Log log, String location, String destinationClasspath, String swaggerLocation,
43 String builderName, String singularBuilderClass, String pluralBuilderClass, String topLevelBuilderClass,
44 String baseBuilderClass, String singularClass, String pluralClass, String nameClass)
45 throws JsonProcessingException {
47 this.location = location;
48 this.CLASSPATH = destinationClasspath;
49 this.builderName = builderName;
50 this.singularBuilderClass = singularBuilderClass;
51 this.pluralBuilderClass = pluralBuilderClass;
52 this.topLevelBuilderClass = topLevelBuilderClass;
53 this.baseBuilderClass = baseBuilderClass;
54 this.singularClass = singularClass;
55 this.pluralClass = pluralClass;
56 this.nameClass = nameClass;
57 doc = new SwaggerConverter(log).getDoc(swaggerLocation);
60 public void run() throws IOException {
61 List<JavaFile> files = new ArrayList<>();
62 for (Entry<String, ObjectType> entry : doc.entrySet()) {
63 // String key = "routing-instance";
64 // ObjectType oType = test;
65 String key = entry.getKey();
66 ObjectType oType = entry.getValue();
67 MethodSpec.Builder constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PROTECTED);
68 List<ParameterSpec> constructorParams = new ArrayList<>();
69 List<FieldSpec> classFields = new ArrayList<>();
71 if (!oType.getType().equals("top level")) {
72 Pair<String, String> path = splitClasspath(this.baseBuilderClass);
73 ClassName parameterizedTypeName = ClassName.get(path.getLeft(), path.getRight());
74 constructorParams.add(ParameterSpec.builder(parameterizedTypeName, "parentObj").build());
75 classFields.add(FieldSpec.builder(parameterizedTypeName, "parentObj")
76 .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
78 List<ParameterSpec> typeParams = new ArrayList<>();
80 for (ObjectField oF : oType.getFields()) {
81 if (oF.getType().equals("string")) {
82 typeParams.add(ParameterSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName())))
84 classFields.add(FieldSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName())))
85 .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
86 } else if (oF.getType().equals("integer")) {
88 ParameterSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
89 classFields.add(FieldSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName())))
90 .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
93 constructorParams.addAll(typeParams);
94 constructor.addParameters(constructorParams);
95 for (ParameterSpec p : constructorParams) {
96 constructor.addStatement("this.$L = $L", p.name, p.name);
99 List<MethodSpec> methods = new ArrayList<>();
100 methods.add(constructor.build());
102 methods.addAll(createChildMethods(oType));
104 methods.addAll(createInterfaceMethods(oType, typeParams));
106 ClassName superType = null;
107 if (oType.getType().equals("top level")) {
108 Pair<String, String> path = splitClasspath(this.topLevelBuilderClass);
109 superType = ClassName.get(path.getLeft(), path.getRight());
111 if (oType.getType().equals("singular")) {
112 Pair<String, String> path = splitClasspath(this.singularBuilderClass);
113 superType = ClassName.get(path.getLeft(), path.getRight());
115 } else if (oType.getType().equals("plural")) {
116 Pair<String, String> path = splitClasspath(this.pluralBuilderClass);
117 superType = ClassName.get(path.getLeft(), path.getRight());
121 TypeSpec type = TypeSpec.classBuilder(upperCamel(key)).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
122 .addType(createInnerInfoClass(oType)).addSuperinterface(superType).addFields(classFields)
123 .addMethods(methods).build();
125 files.add(JavaFile.builder(CLASSPATH, type).build());
129 files.add(createBuilderClass());
131 files.stream().forEach(javaFile -> {
133 javaFile.writeTo(Paths.get(location, "fluent"));
134 } catch (IOException e) {
135 throw new RuntimeException(e);
141 protected List<MethodSpec> createInterfaceMethods(ObjectType oType, List<ParameterSpec> typeParams) {
143 List<MethodSpec> methods = new ArrayList<>();
145 CodeBlock.Builder uriTemplateCodeBlock = CodeBlock.builder();
146 if (!oType.getType().equals("top level")) {
147 uriTemplateCodeBlock.add("return this.parentObj.uriTemplate() + Info.partialUri");
149 uriTemplateCodeBlock.add("return Info.partialUri");
152 methods.add(MethodSpec.methodBuilder("uriTemplate").returns(String.class).addModifiers(Modifier.PUBLIC)
153 .addStatement(uriTemplateCodeBlock.build()).addAnnotation(Override.class).build());
155 ClassName arrayUtils = ClassName.get(ArrayUtils.class);
157 CodeBlock.Builder valuesReturn = CodeBlock.builder();
159 if (oType.getType().equals("top level")) {
160 valuesReturn.add("return new Object[0]");
162 if (!typeParams.isEmpty()) {
163 valuesReturn.add("return $T.addAll(this.parentObj.values(), $L)", arrayUtils, String.join(", ",
164 typeParams.stream().map(item -> "this." + item.name).collect(Collectors.toList())));
166 valuesReturn.add("return this.parentObj.values()");
169 methods.add(MethodSpec.methodBuilder("values").returns(Object[].class).addModifiers(Modifier.PUBLIC)
170 .addAnnotation(Override.class).addStatement(valuesReturn.build()).build());
172 if (!oType.getType().equals("top level")) {
173 ClassName returnType = null;
174 CodeBlock.Builder block = CodeBlock.builder();
175 if (oType.getType().equals("singular")) {
176 Pair<String, String> path = splitClasspath(this.singularClass);
177 returnType = ClassName.get(path.getLeft(), path.getRight());
178 block.add("return new $T(this.parentObj.uriTemplate(), Info.partialUri, Info.name, false)", returnType);
179 } else if (oType.getType().equals("plural")) {
180 Pair<String, String> path = splitClasspath(this.pluralClass);
181 returnType = ClassName.get(path.getLeft(), path.getRight());
182 block.add("return new $T(Info.name, this.parentObj.uriTemplate(), Info.partialUri)", returnType);
185 methods.add(MethodSpec.methodBuilder("build").returns(returnType).addModifiers(Modifier.PUBLIC)
186 .addAnnotation(Override.class).addStatement(block.build()).build());
193 protected List<MethodSpec> createChildMethods(ObjectType oType) {
194 List<MethodSpec> methods = new ArrayList<>();
195 for (String child : oType.getChildren()) {
196 methods.add(createAccessMethod(doc.get(child), true, false));
202 protected MethodSpec createAccessMethod(ObjectType oType, boolean isChild, boolean isStatic) {
204 ClassName childClass = ClassName.get(CLASSPATH, upperCamel(oType.getName()));
205 MethodSpec.Builder b = MethodSpec.methodBuilder(lowerCamel(oType.getName())).returns(childClass);
206 List<Modifier> modifiers = new ArrayList<>();
208 modifiers.add(Modifier.STATIC);
210 modifiers.add(Modifier.PUBLIC);
211 b.addModifiers(modifiers);
212 List<ParameterSpec> params = new ArrayList<>();
213 for (ObjectField oF : doc.get(oType.getName()).getFields()) {
214 if (oF.getType().equals("string")) {
216 ParameterSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
217 } else if (oF.getType().equals("integer")) {
218 params.add(ParameterSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
221 List<String> paramNames = params.stream().map(item -> item.name).collect(Collectors.toList());
223 paramNames.add(0, "this");
225 b.addParameters(params).addStatement("return new $T($L)", childClass, String.join(", ", paramNames));
230 protected JavaFile createBuilderClass() {
232 List<MethodSpec> methods = doc.values().stream().filter(item -> item.getType().equals("top level"))
233 .map(item -> createAccessMethod(item, false, true)).collect(Collectors.toList());
235 TypeSpec type = TypeSpec.classBuilder(this.builderName).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
236 .addMethods(methods).addType(createTypes()).build();
238 return JavaFile.builder(CLASSPATH, type).build();
242 protected TypeSpec createTypes() {
243 Pair<String, String> path = splitClasspath(this.nameClass);
244 ClassName nameType = ClassName.get(path.getLeft(), path.getRight());
246 List<FieldSpec> params =
247 doc.values().stream().filter(item -> item.getType().equals("singular"))
249 .comparing(item -> item.getName()))
250 .map(item -> FieldSpec
252 CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, item.getName()),
253 Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
254 .initializer("new $T($S)", nameType, item.getName()).build())
255 .collect(Collectors.toList());
257 TypeSpec type = TypeSpec.classBuilder("Types").addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC)
258 .addFields(params).build();
264 protected TypeSpec createInnerInfoClass(ObjectType oType) {
265 List<FieldSpec> classFields = new ArrayList<>();
266 List<MethodSpec> methods = new ArrayList<>();
268 classFields.add(FieldSpec.builder(String.class, "partialUri")
269 .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
270 .initializer("$S", oType.getPartialUri()).build());
272 classFields.add(FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class), "paths")
273 .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
274 .initializer("$T.asList($L)", ClassName.get(Arrays.class),
275 "\"" + oType.getPaths().stream().collect(Collectors.joining("\", \"")) + "\"")
278 ClassName superInterface;
279 if (oType.getType().equals("plural")) {
280 classFields.add(FieldSpec.builder(String.class, "name")
281 .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
282 .initializer("$S", oType.getAdditionalName()).build());
283 superInterface = ClassName.get(this.pluralBuilderClass, "Info");
284 } else if (oType.getType().equals("singular")) {
285 classFields.add(FieldSpec.builder(String.class, "name")
286 .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC).initializer("$S", oType.getName())
288 superInterface = ClassName.get(this.singularBuilderClass, "Info");
290 superInterface = ClassName.get(this.topLevelBuilderClass, "Info");
292 methods.add(MethodSpec.methodBuilder("getPaths").returns(ParameterizedTypeName.get(List.class, String.class))
293 .addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).addStatement("return Info.paths").build());
294 methods.add(MethodSpec.methodBuilder("getPartialUri").returns(String.class).addModifiers(Modifier.PUBLIC)
295 .addAnnotation(Override.class).addStatement("return Info.partialUri").build());
296 if (!oType.getType().equals("top level")) {
297 methods.add(MethodSpec.methodBuilder("getName").returns(String.class).addModifiers(Modifier.PUBLIC)
298 .addAnnotation(Override.class).addStatement("return Info.name").build());
300 return TypeSpec.classBuilder("Info").addModifiers(Modifier.PUBLIC, Modifier.STATIC)
301 .addSuperinterface(superInterface).addFields(classFields).addMethods(methods).build();
305 protected String makeValidJavaVariable(String name) {
307 return name.replace(".", "_");
310 protected Pair<String, String> splitClasspath(String path) {
312 return Pair.of(path.substring(0, path.lastIndexOf(".")),
313 path.substring(path.lastIndexOf(".") + 1, path.length()));
316 protected String lowerCamel(String s) {
317 return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, s);
320 protected String upperCamel(String s) {
321 return CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, s);