aboutsummaryrefslogtreecommitdiffstats
path: root/graph-inventory/fluent-builder-maven-plugin/src
diff options
context:
space:
mode:
authorBenjamin, Max <max.benjamin@att.com>2020-04-30 10:41:46 -0400
committerBenjamin, Max (mb388a) <mb388a@att.com>2020-04-30 11:08:10 -0400
commite7f7527a7ad0397f9f98c739f6f4dfba357bcf3a (patch)
tree96db50b73b0a7d096683ecb0672c79cf6897ee90 /graph-inventory/fluent-builder-maven-plugin/src
parent0fdf096ae4ff4ee4b7a644549bd67d75e4aa82b1 (diff)
add fluent type builder support to A&AI client
add fluent type builder support to A&AI client Issue-ID: SO-2856 Signed-off-by: Benjamin, Max (mb388a) <mb388a@att.com> Change-Id: I2957aedb84a1c6b23979ff2e1c4dfb16b3a646c7
Diffstat (limited to 'graph-inventory/fluent-builder-maven-plugin/src')
-rw-r--r--graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java324
-rw-r--r--graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java53
-rw-r--r--graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java26
-rw-r--r--graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java91
-rw-r--r--graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java176
5 files changed, 670 insertions, 0 deletions
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java
new file mode 100644
index 0000000000..f9c664389b
--- /dev/null
+++ b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java
@@ -0,0 +1,324 @@
+package org.onap.graphinventory.generate;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.maven.plugin.logging.Log;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.base.CaseFormat;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeSpec;
+
+public class FluentGenerator {
+
+ private final Map<String, ObjectType> doc;
+ private final String location;
+ private final String CLASSPATH;
+
+ private final String singularBuilderClass;
+ private final String pluralBuilderClass;
+ private final String topLevelBuilderClass;
+ private final String baseBuilderClass;
+ private final String singularClass;
+ private final String pluralClass;
+ private final String builderName;
+ private final String nameClass;
+
+ public FluentGenerator(Log log, String location, String destinationClasspath, String swaggerLocation,
+ String builderName, String singularBuilderClass, String pluralBuilderClass, String topLevelBuilderClass,
+ String baseBuilderClass, String singularClass, String pluralClass, String nameClass)
+ throws JsonProcessingException {
+
+ this.location = location;
+ this.CLASSPATH = destinationClasspath;
+ this.builderName = builderName;
+ this.singularBuilderClass = singularBuilderClass;
+ this.pluralBuilderClass = pluralBuilderClass;
+ this.topLevelBuilderClass = topLevelBuilderClass;
+ this.baseBuilderClass = baseBuilderClass;
+ this.singularClass = singularClass;
+ this.pluralClass = pluralClass;
+ this.nameClass = nameClass;
+ doc = new SwaggerConverter(log).getDoc(swaggerLocation);
+ }
+
+ public void run() throws IOException {
+ List<JavaFile> files = new ArrayList<>();
+ for (Entry<String, ObjectType> entry : doc.entrySet()) {
+ // String key = "routing-instance";
+ // ObjectType oType = test;
+ String key = entry.getKey();
+ ObjectType oType = entry.getValue();
+ MethodSpec.Builder constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PROTECTED);
+ List<ParameterSpec> constructorParams = new ArrayList<>();
+ List<FieldSpec> classFields = new ArrayList<>();
+
+ if (!oType.getType().equals("top level")) {
+ Pair<String, String> path = splitClasspath(this.baseBuilderClass);
+ ClassName parameterizedTypeName = ClassName.get(path.getLeft(), path.getRight());
+ constructorParams.add(ParameterSpec.builder(parameterizedTypeName, "parentObj").build());
+ classFields.add(FieldSpec.builder(parameterizedTypeName, "parentObj")
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
+ }
+ List<ParameterSpec> typeParams = new ArrayList<>();
+
+ for (ObjectField oF : oType.getFields()) {
+ if (oF.getType().equals("string")) {
+ typeParams.add(ParameterSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName())))
+ .build());
+ classFields.add(FieldSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName())))
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
+ } else if (oF.getType().equals("integer")) {
+ typeParams.add(
+ ParameterSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
+ classFields.add(FieldSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName())))
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
+ }
+ }
+ constructorParams.addAll(typeParams);
+ constructor.addParameters(constructorParams);
+ for (ParameterSpec p : constructorParams) {
+ constructor.addStatement("this.$L = $L", p.name, p.name);
+
+ }
+ List<MethodSpec> methods = new ArrayList<>();
+ methods.add(constructor.build());
+
+ methods.addAll(createChildMethods(oType));
+
+ methods.addAll(createInterfaceMethods(oType, typeParams));
+
+ ClassName superType = null;
+ if (oType.getType().equals("top level")) {
+ Pair<String, String> path = splitClasspath(this.topLevelBuilderClass);
+ superType = ClassName.get(path.getLeft(), path.getRight());
+ } else {
+ if (oType.getType().equals("singular")) {
+ Pair<String, String> path = splitClasspath(this.singularBuilderClass);
+ superType = ClassName.get(path.getLeft(), path.getRight());
+
+ } else if (oType.getType().equals("plural")) {
+ Pair<String, String> path = splitClasspath(this.pluralBuilderClass);
+ superType = ClassName.get(path.getLeft(), path.getRight());
+ }
+ }
+
+ TypeSpec type = TypeSpec.classBuilder(upperCamel(key)).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .addType(createInnerInfoClass(oType)).addSuperinterface(superType).addFields(classFields)
+ .addMethods(methods).build();
+
+ files.add(JavaFile.builder(CLASSPATH, type).build());
+
+ }
+
+ files.add(createBuilderClass());
+
+ files.stream().forEach(javaFile -> {
+ try {
+ javaFile.writeTo(Paths.get(location, "fluent"));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ }
+
+ protected List<MethodSpec> createInterfaceMethods(ObjectType oType, List<ParameterSpec> typeParams) {
+
+ List<MethodSpec> methods = new ArrayList<>();
+
+ CodeBlock.Builder uriTemplateCodeBlock = CodeBlock.builder();
+ if (!oType.getType().equals("top level")) {
+ uriTemplateCodeBlock.add("return this.parentObj.uriTemplate() + Info.partialUri");
+ } else {
+ uriTemplateCodeBlock.add("return Info.partialUri");
+
+ }
+ methods.add(MethodSpec.methodBuilder("uriTemplate").returns(String.class).addModifiers(Modifier.PUBLIC)
+ .addStatement(uriTemplateCodeBlock.build()).addAnnotation(Override.class).build());
+
+ ClassName arrayUtils = ClassName.get(ArrayUtils.class);
+
+ CodeBlock.Builder valuesReturn = CodeBlock.builder();
+
+ if (oType.getType().equals("top level")) {
+ valuesReturn.add("return new Object[0]");
+ } else {
+ if (!typeParams.isEmpty()) {
+ valuesReturn.add("return $T.addAll(this.parentObj.values(), $L)", arrayUtils, String.join(", ",
+ typeParams.stream().map(item -> "this." + item.name).collect(Collectors.toList())));
+ } else {
+ valuesReturn.add("return this.parentObj.values()");
+ }
+ }
+ methods.add(MethodSpec.methodBuilder("values").returns(Object[].class).addModifiers(Modifier.PUBLIC)
+ .addAnnotation(Override.class).addStatement(valuesReturn.build()).build());
+
+ if (!oType.getType().equals("top level")) {
+ ClassName returnType = null;
+ CodeBlock.Builder block = CodeBlock.builder();
+ if (oType.getType().equals("singular")) {
+ Pair<String, String> path = splitClasspath(this.singularClass);
+ returnType = ClassName.get(path.getLeft(), path.getRight());
+ block.add("return new $T(this.parentObj.uriTemplate(), Info.partialUri, Info.name, false)", returnType);
+ } else if (oType.getType().equals("plural")) {
+ Pair<String, String> path = splitClasspath(this.pluralClass);
+ returnType = ClassName.get(path.getLeft(), path.getRight());
+ block.add("return new $T(Info.name, this.parentObj.uriTemplate(), Info.partialUri)", returnType);
+ }
+
+ methods.add(MethodSpec.methodBuilder("build").returns(returnType).addModifiers(Modifier.PUBLIC)
+ .addAnnotation(Override.class).addStatement(block.build()).build());
+
+ }
+
+ return methods;
+ }
+
+ protected List<MethodSpec> createChildMethods(ObjectType oType) {
+ List<MethodSpec> methods = new ArrayList<>();
+ for (String child : oType.getChildren()) {
+ methods.add(createAccessMethod(doc.get(child), true, false));
+ }
+
+ return methods;
+ }
+
+ protected MethodSpec createAccessMethod(ObjectType oType, boolean isChild, boolean isStatic) {
+
+ ClassName childClass = ClassName.get(CLASSPATH, upperCamel(oType.getName()));
+ MethodSpec.Builder b = MethodSpec.methodBuilder(lowerCamel(oType.getName())).returns(childClass);
+ List<Modifier> modifiers = new ArrayList<>();
+ if (isStatic) {
+ modifiers.add(Modifier.STATIC);
+ }
+ modifiers.add(Modifier.PUBLIC);
+ b.addModifiers(modifiers);
+ List<ParameterSpec> params = new ArrayList<>();
+ for (ObjectField oF : doc.get(oType.getName()).getFields()) {
+ if (oF.getType().equals("string")) {
+ params.add(
+ ParameterSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
+ } else if (oF.getType().equals("integer")) {
+ params.add(ParameterSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
+ }
+ }
+ List<String> paramNames = params.stream().map(item -> item.name).collect(Collectors.toList());
+ if (isChild) {
+ paramNames.add(0, "this");
+ }
+ b.addParameters(params).addStatement("return new $T($L)", childClass, String.join(", ", paramNames));
+
+ return b.build();
+ }
+
+ protected JavaFile createBuilderClass() {
+
+ List<MethodSpec> methods = doc.values().stream().filter(item -> item.getType().equals("top level"))
+ .map(item -> createAccessMethod(item, false, true)).collect(Collectors.toList());
+
+ TypeSpec type = TypeSpec.classBuilder(this.builderName).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .addMethods(methods).addType(createTypes()).build();
+
+ return JavaFile.builder(CLASSPATH, type).build();
+
+ }
+
+ protected TypeSpec createTypes() {
+ Pair<String, String> path = splitClasspath(this.nameClass);
+ ClassName nameType = ClassName.get(path.getLeft(), path.getRight());
+
+ List<FieldSpec> params =
+ doc.values().stream().filter(item -> item.getType().equals("singular"))
+ .sorted(Comparator
+ .comparing(item -> item.getName()))
+ .map(item -> FieldSpec
+ .builder(nameType,
+ CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, item.getName()),
+ Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
+ .initializer("new $T($S)", nameType, item.getName()).build())
+ .collect(Collectors.toList());
+
+ TypeSpec type = TypeSpec.classBuilder("Types").addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC)
+ .addFields(params).build();
+
+ return type;
+
+ }
+
+ protected TypeSpec createInnerInfoClass(ObjectType oType) {
+ List<FieldSpec> classFields = new ArrayList<>();
+ List<MethodSpec> methods = new ArrayList<>();
+
+ classFields.add(FieldSpec.builder(String.class, "partialUri")
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
+ .initializer("$S", oType.getPartialUri()).build());
+
+ classFields.add(FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class), "paths")
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
+ .initializer("$T.asList($L)", ClassName.get(Arrays.class),
+ "\"" + oType.getPaths().stream().collect(Collectors.joining("\", \"")) + "\"")
+ .build());
+
+ ClassName superInterface;
+ if (oType.getType().equals("plural")) {
+ classFields.add(FieldSpec.builder(String.class, "name")
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
+ .initializer("$S", oType.getAdditionalName()).build());
+ superInterface = ClassName.get(this.pluralBuilderClass, "Info");
+ } else if (oType.getType().equals("singular")) {
+ classFields.add(FieldSpec.builder(String.class, "name")
+ .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC).initializer("$S", oType.getName())
+ .build());
+ superInterface = ClassName.get(this.singularBuilderClass, "Info");
+ } else {
+ superInterface = ClassName.get(this.topLevelBuilderClass, "Info");
+ }
+ methods.add(MethodSpec.methodBuilder("getPaths").returns(ParameterizedTypeName.get(List.class, String.class))
+ .addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).addStatement("return Info.paths").build());
+ methods.add(MethodSpec.methodBuilder("getPartialUri").returns(String.class).addModifiers(Modifier.PUBLIC)
+ .addAnnotation(Override.class).addStatement("return Info.partialUri").build());
+ if (!oType.getType().equals("top level")) {
+ methods.add(MethodSpec.methodBuilder("getName").returns(String.class).addModifiers(Modifier.PUBLIC)
+ .addAnnotation(Override.class).addStatement("return Info.name").build());
+ }
+ return TypeSpec.classBuilder("Info").addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+ .addSuperinterface(superInterface).addFields(classFields).addMethods(methods).build();
+
+ }
+
+ protected String makeValidJavaVariable(String name) {
+
+ return name.replace(".", "_");
+ }
+
+ protected Pair<String, String> splitClasspath(String path) {
+
+ return Pair.of(path.substring(0, path.lastIndexOf(".")),
+ path.substring(path.lastIndexOf(".") + 1, path.length()));
+ }
+
+ protected String lowerCamel(String s) {
+ return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, s);
+ }
+
+ protected String upperCamel(String s) {
+ return CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, s);
+ }
+
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java
new file mode 100644
index 0000000000..9de249faa2
--- /dev/null
+++ b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java
@@ -0,0 +1,53 @@
+package org.onap.graphinventory.generate;
+
+import java.io.IOException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+@Mojo(name = "generate-builders", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
+public class FluentGeneratorMojo extends AbstractMojo {
+
+ @Parameter
+ private String destination;
+ @Parameter
+ private String destinationClasspath;
+ @Parameter
+ private String builderName;
+ @Parameter
+ private String swaggerLocation;
+ @Parameter
+ private String singularBuilderClass;
+ @Parameter
+ private String pluralBuilderClass;
+ @Parameter
+ private String topLevelBuilderClass;
+ @Parameter
+ private String baseBuilderClass;
+ @Parameter
+ private String singularClass;
+ @Parameter
+ private String pluralClass;
+ @Parameter
+ private String nameClass;
+
+ public void execute() throws MojoExecutionException, MojoFailureException {
+
+ try {
+ new FluentGenerator(getLog(), destination, destinationClasspath, swaggerLocation, builderName,
+ singularBuilderClass, pluralBuilderClass, topLevelBuilderClass, baseBuilderClass, singularClass,
+ pluralClass, nameClass).run();
+ } catch (JsonProcessingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java
new file mode 100644
index 0000000000..7c93804bd1
--- /dev/null
+++ b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java
@@ -0,0 +1,26 @@
+package org.onap.graphinventory.generate;
+
+public class ObjectField {
+
+
+ private String name;
+ private String type;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java
new file mode 100644
index 0000000000..3e7f7dcd46
--- /dev/null
+++ b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java
@@ -0,0 +1,91 @@
+package org.onap.graphinventory.generate;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ObjectType {
+
+ private List<String> paths = new ArrayList<>();
+
+ private Set<String> children = new HashSet<>();
+
+ private String name;
+
+ private String additionalName;
+
+ private String topLevel;
+
+ private String type;
+
+ private String partialUri;
+
+ private List<ObjectField> fields = new ArrayList<>();
+
+ public List<String> getPaths() {
+ return paths;
+ }
+
+ public void setPaths(List<String> paths) {
+ this.paths = paths;
+ }
+
+ public String getTopLevel() {
+ return topLevel;
+ }
+
+ public void setTopLevel(String topLevel) {
+ this.topLevel = topLevel;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public List<ObjectField> getFields() {
+ return fields;
+ }
+
+ public void setFields(List<ObjectField> fields) {
+ this.fields = fields;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set<String> getChildren() {
+ return children;
+ }
+
+ public void setChildren(Set<String> children) {
+ this.children = children;
+ }
+
+ public String getPartialUri() {
+ return partialUri;
+ }
+
+ public void setPartialUri(String partialUri) {
+ this.partialUri = partialUri;
+ }
+
+ public String getAdditionalName() {
+ return additionalName;
+ }
+
+ public void setAdditionalName(String additionalName) {
+ this.additionalName = additionalName;
+ }
+
+
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java
new file mode 100644
index 0000000000..b3ced65390
--- /dev/null
+++ b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java
@@ -0,0 +1,176 @@
+package org.onap.graphinventory.generate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import org.apache.maven.plugin.logging.Log;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.models.Path;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.SerializableParameter;
+import io.swagger.parser.SwaggerParser;
+
+public class SwaggerConverter {
+
+ private final Log log;
+
+ public SwaggerConverter(Log log) {
+ this.log = log;
+ }
+
+ public Map<String, ObjectType> getDoc(String swaggerLocation) throws JsonProcessingException {
+ Swagger swagger = new SwaggerParser().read(swaggerLocation);
+
+ Map<String, Path> paths = swagger.getPaths().entrySet().stream()
+ .filter(item -> !item.getKey().endsWith("/relationship-list/relationship"))
+ .collect(Collectors.toMap(item -> item.getKey(), item -> item.getValue()));
+
+ Pattern pluralPattern = Pattern.compile(".*(?<partial>/(?<name>[^{]*$))");
+ Pattern singularPattern = Pattern.compile(".*(?<partial>/(?<name>[^/{}]*)/\\{.*$)");
+ Pattern topLevelPattern = Pattern.compile("^/([^/]+)/.*");
+ Pattern urlTemplatePattern = Pattern.compile("\\{([^}]+)\\}");
+ Matcher pluralMatcher;
+ Matcher singularMatcher;
+ Matcher topLevelMatcher;
+
+ Map<String, ObjectType> output = new HashMap<>();
+ for (Map.Entry<String, Path> entry : paths.entrySet()) {
+
+ pluralMatcher = pluralPattern.matcher(entry.getKey());
+ singularMatcher = singularPattern.matcher(entry.getKey());
+ topLevelMatcher = topLevelPattern.matcher(entry.getKey());
+ ObjectType item;
+ if (pluralMatcher.matches()) {
+ if (!output.containsKey(pluralMatcher.group("name"))) {
+ output.put(pluralMatcher.group("name"), new ObjectType());
+ }
+ item = output.get(pluralMatcher.group("name"));
+ item.setType("plural");
+ item.setName(pluralMatcher.group("name"));
+ item.setPartialUri(pluralMatcher.group("partial"));
+ item.getPaths().add(entry.getKey());
+
+ if (topLevelMatcher.matches()) {
+ item.setTopLevel(topLevelMatcher.group(1));
+ if (!output.containsKey(topLevelMatcher.group(1))) {
+ output.put(topLevelMatcher.group(1), new ObjectType());
+ output.get(topLevelMatcher.group(1)).setType("top level");
+ output.get(topLevelMatcher.group(1)).setName(topLevelMatcher.group(1));
+ output.get(topLevelMatcher.group(1)).setPartialUri("/" + topLevelMatcher.group(1));
+ output.get(topLevelMatcher.group(1)).getPaths().add("/" + topLevelMatcher.group(1));
+
+ }
+ }
+ } else if (singularMatcher.matches()) {
+
+ if (!output.containsKey(singularMatcher.group("name"))) {
+ output.put(singularMatcher.group("name"), new ObjectType());
+
+ item = output.get(singularMatcher.group("name"));
+
+ item.setType("singular");
+ item.setName(singularMatcher.group("name"));
+ item.setPartialUri(singularMatcher.group("partial"));
+
+ item.getPaths().add(entry.getKey());
+
+ if (topLevelMatcher.matches()) {
+ item.setTopLevel(topLevelMatcher.group(1));
+ if (!output.containsKey(topLevelMatcher.group(1))) {
+ output.put(topLevelMatcher.group(1), new ObjectType());
+ output.get(topLevelMatcher.group(1)).setType("top level");
+ output.get(topLevelMatcher.group(1)).setName(topLevelMatcher.group(1));
+ output.get(topLevelMatcher.group(1)).setPartialUri("/" + topLevelMatcher.group(1));
+ output.get(topLevelMatcher.group(1)).getPaths().add("/" + topLevelMatcher.group(1));
+ }
+ }
+ List<Parameter> parameters = entry.getValue().getGet().getParameters();
+
+ if (parameters != null) {
+ parameters.stream().filter(param -> "path".equals(param.getIn())).collect(Collectors.toList());
+ }
+ for (Parameter p : parameters) {
+ ObjectField field = new ObjectField();
+
+ field.setName(p.getName());
+ field.setType(((SerializableParameter) p).getType());
+ item.getFields().add(field);
+ }
+
+ } else {
+ item = output.get(singularMatcher.group("name"));
+ if (singularMatcher.group("partial").contains(item.getName() + ".")) {
+ item.setPartialUri(singularMatcher.group("partial"));
+ }
+ item.getPaths().add(entry.getKey());
+ }
+ }
+
+ }
+ ObjectMapper mapper = new ObjectMapper();
+
+ for (ObjectType item : output.values()) {
+ for (String path : item.getPaths()) {
+ String partialUriReplacer = item.getPartialUri().replaceAll("\\{[^}]+\\}", "[^/]+");
+ String childParentUri = path.replaceFirst(partialUriReplacer + "$", "");
+ for (ObjectType itemToUpdate : output.values()) {
+ if (itemToUpdate.getPaths().stream()
+ .anyMatch(itemToUpdateUri -> itemToUpdateUri.equals(childParentUri))) {
+ itemToUpdate.getChildren().add(item.getName());
+ }
+ }
+ }
+ }
+
+ log.debug(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(output));
+
+ for (Map.Entry<String, ObjectType> item : output.entrySet()) {
+
+ if (item.getValue().getType().equals("plural")) {
+ Set<String> children = item.getValue().getChildren();
+ // should only be one
+ if (!children.isEmpty()) {
+ item.getValue().setAdditionalName(children.iterator().next());
+ }
+ }
+ Set<String> pluralChildren = new HashSet<>();
+ for (String child : item.getValue().getChildren()) {
+ if (output.get(child).getType().equals("plural")) {
+ Set<String> children = output.get(child).getChildren();
+ pluralChildren.addAll(children);
+ }
+ }
+ item.getValue().getChildren().addAll(pluralChildren);
+
+ if (item.getValue().getType().equals("plural")) {
+ for (String child : item.getValue().getChildren()) {
+ output.get(child)
+ .setPartialUri(item.getValue().getPartialUri() + output.get(child).getPartialUri());
+ }
+ }
+
+ if (!item.getValue().getFields().isEmpty()) {
+ Matcher templates = urlTemplatePattern.matcher(item.getValue().getPartialUri());
+ List<String> localFields = new ArrayList<>();
+ while (templates.find()) {
+ localFields.add(templates.group(1));
+ }
+ item.getValue().setFields(item.getValue().getFields().stream()
+ .filter(f -> localFields.contains(f.getName())).collect(Collectors.toList()));
+ }
+ }
+
+ output.values().stream().filter(item -> item.getType().equals("plural"))
+ .forEach(item -> item.getChildren().clear());
+
+ return output;
+ }
+}