From be1e189d608787b37634c775fd268f8508437c01 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 20 May 2024 01:19:25 +0200 Subject: [PATCH] [FEAT] continue refacto of the model generator (base model generated, not the API, mission some control like optional, and limit size --- pom.xml | 2 +- .../archidata/externalRestApi/AnalyzeApi.java | 5 +- .../externalRestApi/AnalyzeModel.java | 27 + .../externalRestApi/GeneratePythonApi.java | 3 + .../externalRestApi/GenerateTsApi.java | 5 - .../externalRestApi/TsClassElement.java | 332 ++++++++++ .../externalRestApi/TsClassElementGroup.java | 27 + .../externalRestApi/TsGenerateApi.java | 130 ++++ .../externalRestApi/model/ApiGroupModel.java | 16 +- .../externalRestApi/model/ApiModel.java | 57 +- .../externalRestApi/model/ClassEnumModel.java | 32 +- .../externalRestApi/model/ClassListModel.java | 14 + .../externalRestApi/model/ClassMapModel.java | 20 + .../externalRestApi/model/ClassModel.java | 39 +- .../model/ClassObjectModel.java | 150 ++++- .../externalRestApi/model/ModelGroup.java | 7 +- .../externalRestApi/TestAnalyzeApiName.java | 47 ++ .../TestAnalyzeApiParameterType.java | 143 +++++ .../externalRestApi/TestAnalyzeApiPath.java | 107 ++++ .../externalRestApi/TestAnalyzeApiReturn.java | 605 ++++++++++++++++++ .../externalRestApi/TestAnalyzeModel.java | 43 ++ 21 files changed, 1758 insertions(+), 53 deletions(-) delete mode 100644 src/org/kar/archidata/externalRestApi/GenerateTsApi.java create mode 100644 src/org/kar/archidata/externalRestApi/TsClassElement.java create mode 100644 src/org/kar/archidata/externalRestApi/TsClassElementGroup.java create mode 100644 src/org/kar/archidata/externalRestApi/TsGenerateApi.java create mode 100644 test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiName.java create mode 100644 test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiParameterType.java create mode 100644 test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiPath.java create mode 100644 test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiReturn.java create mode 100644 test/src/test/kar/archidata/externalRestApi/TestAnalyzeModel.java diff --git a/pom.xml b/pom.xml index 6a703bf..a39dcc1 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 kangaroo-and-rabbit archidata - 0.8.9 + 0.8.10-SNAPSHOOT 21 3.1 diff --git a/src/org/kar/archidata/externalRestApi/AnalyzeApi.java b/src/org/kar/archidata/externalRestApi/AnalyzeApi.java index da33df0..fc15af0 100644 --- a/src/org/kar/archidata/externalRestApi/AnalyzeApi.java +++ b/src/org/kar/archidata/externalRestApi/AnalyzeApi.java @@ -6,8 +6,11 @@ import java.util.List; import org.kar.archidata.externalRestApi.model.ApiGroupModel; import org.kar.archidata.externalRestApi.model.ClassModel; import org.kar.archidata.externalRestApi.model.ModelGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AnalyzeApi { + static final Logger LOGGER = LoggerFactory.getLogger(AnalyzeApi.class); public List apiModels = new ArrayList<>(); public List classModels = new ArrayList<>(); @@ -17,7 +20,7 @@ public class AnalyzeApi { final ApiGroupModel parsed = new ApiGroupModel(clazz, previousModel); this.apiModels.add(parsed); } - + AnalyzeModel.fillModel(previousModel.previousModel); } } diff --git a/src/org/kar/archidata/externalRestApi/AnalyzeModel.java b/src/org/kar/archidata/externalRestApi/AnalyzeModel.java index 3918435..0642582 100644 --- a/src/org/kar/archidata/externalRestApi/AnalyzeModel.java +++ b/src/org/kar/archidata/externalRestApi/AnalyzeModel.java @@ -1,5 +1,32 @@ package org.kar.archidata.externalRestApi; +import java.util.ArrayList; +import java.util.List; + +import org.kar.archidata.externalRestApi.model.ClassModel; +import org.kar.archidata.externalRestApi.model.ModelGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class AnalyzeModel { + static final Logger LOGGER = LoggerFactory.getLogger(AnalyzeModel.class); + + public static void fillModel(final List models) throws Exception { + final ModelGroup previousModel = new ModelGroup(models); + final List dones = new ArrayList<>(); + while (dones.size() < previousModel.previousModel.size()) { + LOGGER.info("Do a cycle of annalyze : new model detected: {} < {}", dones.size(), + previousModel.previousModel.size()); + final List copyList = new ArrayList<>(previousModel.previousModel); + for (final ClassModel model : copyList) { + if (dones.contains(model)) { + continue; + } + LOGGER.info("Analyze: {}", model); + model.analyze(previousModel); + dones.add(model); + } + } + } } diff --git a/src/org/kar/archidata/externalRestApi/GeneratePythonApi.java b/src/org/kar/archidata/externalRestApi/GeneratePythonApi.java index d48e6a5..e6697e6 100644 --- a/src/org/kar/archidata/externalRestApi/GeneratePythonApi.java +++ b/src/org/kar/archidata/externalRestApi/GeneratePythonApi.java @@ -2,4 +2,7 @@ package org.kar.archidata.externalRestApi; public class GeneratePythonApi { + public static void generateApi(final AnalyzeApi api) { + + } } diff --git a/src/org/kar/archidata/externalRestApi/GenerateTsApi.java b/src/org/kar/archidata/externalRestApi/GenerateTsApi.java deleted file mode 100644 index 658f992..0000000 --- a/src/org/kar/archidata/externalRestApi/GenerateTsApi.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.kar.archidata.externalRestApi; - -public class GenerateTsApi { - -} diff --git a/src/org/kar/archidata/externalRestApi/TsClassElement.java b/src/org/kar/archidata/externalRestApi/TsClassElement.java new file mode 100644 index 0000000..f35a999 --- /dev/null +++ b/src/org/kar/archidata/externalRestApi/TsClassElement.java @@ -0,0 +1,332 @@ +package org.kar.archidata.externalRestApi; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import org.kar.archidata.externalRestApi.model.ClassEnumModel; +import org.kar.archidata.externalRestApi.model.ClassListModel; +import org.kar.archidata.externalRestApi.model.ClassMapModel; +import org.kar.archidata.externalRestApi.model.ClassModel; +import org.kar.archidata.externalRestApi.model.ClassObjectModel; +import org.kar.archidata.externalRestApi.model.ClassObjectModel.FieldProperty; + +public class TsClassElement { + public List models; + public String zodName; + public String tsTypeName; + public String tsCheckType; + public String declaration; + public String fileName = null; + public String comment = null; + public boolean isEnum = false; + public boolean nativeType; + + public TsClassElement(final List model, final String zodName, final String tsTypeName, + final String tsCheckType, final String declaration, final boolean nativeType) { + this.models = model; + this.zodName = zodName; + this.tsTypeName = tsTypeName; + this.tsCheckType = tsCheckType; + this.declaration = declaration; + this.nativeType = nativeType; + this.fileName = tsTypeName.replaceAll("([a-z])([A-Z])", "$1-$2").replaceAll("([A-Z])([A-Z][a-z])", "$1-$2") + .toLowerCase(); + } + + public TsClassElement(final ClassModel model) { + this.models = List.of(model); + this.zodName = "Zod" + model.getOriginClasses().getSimpleName(); + this.tsTypeName = model.getOriginClasses().getSimpleName(); + this.tsCheckType = "is" + model.getOriginClasses().getSimpleName(); + this.declaration = null; + this.nativeType = false; + this.fileName = this.tsTypeName.replaceAll("([a-z])([A-Z])", "$1-$2").replaceAll("([A-Z])([A-Z][a-z])", "$1-$2") + .toLowerCase(); + } + + public boolean isCompatible(final ClassModel model) { + return this.models.contains(model); + } + + public String getBaseHeader() { + return """ + /** + * Interface of the server (auto-generated code) + */ + import { z as zod } from \"zod\"; + + """; + } + + public String generateEnum(final ClassEnumModel model, final TsClassElementGroup tsGroup) throws IOException { + final StringBuilder out = new StringBuilder(); + out.append(getBaseHeader()); + out.append("\n"); + //out.append(generateComment(model)); + + if (System.getenv("ARCHIDATA_GENERATE_ZOD_ENUM") != null) { + boolean first = true; + out.append("export const "); + out.append(this.tsTypeName); + out.append(" = "); + out.append("zod.enum(["); + for (final String elem : model.getListOfValues()) { + if (!first) { + out.append(",\n\t"); + } else { + out.append("\n\t"); + first = false; + } + out.append("'"); + out.append(elem); + out.append("'"); + } + if (first) { + out.append("]}"); + } else { + out.append("\n\t])"); + } + out.append(";\n"); + + out.append("\nexport type "); + out.append(this.tsTypeName); + out.append(" = zod.infer;\n"); + } else { + boolean first = true; + out.append("export enum "); + out.append(this.tsTypeName); + out.append(" {"); + for (final String elem : model.getListOfValues()) { + if (!first) { + out.append(",\n\t"); + } else { + out.append("\n\t"); + first = false; + } + out.append(elem); + out.append(" = '"); + out.append(elem); + out.append("'"); + } + if (first) { + out.append("}"); + } else { + out.append(",\n\t}"); + } + out.append(";\n"); + out.append("\nexport const "); + out.append(this.zodName); + out.append(" = zod.nativeEnum("); + out.append(this.tsTypeName); + out.append(");\n"); + } + out.append(generateExportCheckFunction()); + return out.toString(); + } + + private Object generateExportCheckFunction() { + final StringBuilder out = new StringBuilder(); + out.append("\nexport function "); + out.append(this.tsCheckType); + out.append("(data: any): data is "); + out.append(this.tsTypeName); + out.append(" {\n\ttry {\n\t\t"); + out.append(this.zodName); + out.append(""" + .parse(data); + return true; + } catch (e: any) { + console.log(`Fail to parse data ${e}`); + return false; + } + } + """); + return out.toString(); + } + + public String generateImports(final List depModels, final TsClassElementGroup tsGroup) + throws IOException { + final StringBuilder out = new StringBuilder(); + for (final ClassModel depModel : depModels) { + final TsClassElement tsModel = tsGroup.find(depModel); + if (!tsModel.nativeType) { + out.append("import {"); + out.append(tsModel.zodName); + out.append("} from \""); + out.append(tsModel.fileName); + out.append("\";\n"); + } + } + return out.toString(); + } + + private Object generateComment(final ClassObjectModel model) { + final StringBuilder out = new StringBuilder(); + if (model.getDescription() != null || model.getExample() != null) { + out.append("/**\n"); + if (model.getDescription() != null) { + for (final String elem : model.getDescription().split("\n")) { + out.append(" * "); + out.append(elem); + out.append("\n"); + } + } + if (model.getExample() != null) { + out.append(" * Example:\n"); + out.append(" * ```\n"); + for (final String elem : model.getExample().split("\n")) { + out.append(" * "); + out.append(elem); + out.append("\n"); + } + out.append(" * ```\n"); + } + out.append(" */\n"); + } + return out.toString(); + } + + public String generateObject(final ClassObjectModel model, final TsClassElementGroup tsGroup) throws IOException { + final StringBuilder out = new StringBuilder(); + out.append(getBaseHeader()); + out.append(generateImports(model.getDependencyModels(), tsGroup)); + out.append("\n"); + + out.append(generateComment(model)); + out.append("export const "); + out.append(this.tsTypeName); + out.append(" = "); + + if (model.getExtendsClass() != null) { + final ClassModel parentClass = model.getExtendsClass(); + final TsClassElement tsParentModel = tsGroup.find(parentClass); + out.append(tsParentModel.zodName); + out.append(".extend({"); + } else { + out.append("zod.object({"); + } + out.append("\n"); + for (final FieldProperty field : model.getFields()) { + final ClassModel fieldModel = field.model(); + if (field.comment() != null) { + out.append("\t/*\n"); + out.append("\t * "); + out.append(field.comment()); + out.append("\n\t*/\n"); + } + out.append("\t"); + out.append(field.name()); + out.append(": "); + if (fieldModel instanceof ClassEnumModel || fieldModel instanceof ClassObjectModel) { + final TsClassElement tsFieldModel = tsGroup.find(fieldModel); + out.append(tsFieldModel.zodName); + } else if (fieldModel instanceof final ClassListModel fieldListModel) { + final String data = generateTsList(fieldListModel, tsGroup); + out.append(data); + } else if (fieldModel instanceof final ClassMapModel fieldMapModel) { + final String data = generateTsMap(fieldMapModel, tsGroup); + out.append(data); + } + out.append(";\n"); + } + out.append("\n});\n"); + out.append("\nexport type "); + out.append(this.tsTypeName); + out.append(" = zod.infer;\n"); + out.append(generateExportCheckFunction()); + return out.toString(); + } + + private String generateTsMap(final ClassMapModel model, final TsClassElementGroup tsGroup) { + final StringBuilder out = new StringBuilder(); + out.append("zod.record("); + if (model.keyModel instanceof final ClassListModel fieldListModel) { + final String tmp = generateTsList(fieldListModel, tsGroup); + out.append(tmp); + } else if (model.keyModel instanceof final ClassMapModel fieldMapModel) { + final String tmp = generateTsMap(fieldMapModel, tsGroup); + out.append(tmp); + } else if (model.keyModel instanceof final ClassObjectModel fieldObjectModel) { + final String tmp = generateTsObject(fieldObjectModel, tsGroup); + out.append(tmp); + } else if (model.keyModel instanceof final ClassEnumModel fieldEnumModel) { + final String tmp = generateTsEnum(fieldEnumModel, tsGroup); + out.append(tmp); + } + out.append(", "); + if (model.valueModel instanceof final ClassListModel fieldListModel) { + final String tmp = generateTsList(fieldListModel, tsGroup); + out.append(tmp); + } else if (model.valueModel instanceof final ClassMapModel fieldMapModel) { + final String tmp = generateTsMap(fieldMapModel, tsGroup); + out.append(tmp); + } else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) { + final String tmp = generateTsObject(fieldObjectModel, tsGroup); + out.append(tmp); + } else if (model.valueModel instanceof final ClassEnumModel fieldEnumModel) { + final String tmp = generateTsEnum(fieldEnumModel, tsGroup); + out.append(tmp); + } + out.append(")"); + return out.toString(); + } + + private String generateTsEnum(final ClassEnumModel model, final TsClassElementGroup tsGroup) { + final TsClassElement tsParentModel = tsGroup.find(model); + return tsParentModel.zodName; + } + + private String generateTsObject(final ClassObjectModel model, final TsClassElementGroup tsGroup) { + final TsClassElement tsParentModel = tsGroup.find(model); + return tsParentModel.zodName; + } + + private String generateTsList(final ClassListModel model, final TsClassElementGroup tsGroup) { + final StringBuilder out = new StringBuilder(); + out.append("zod.array("); + if (model.valueModel instanceof final ClassListModel fieldListModel) { + final String tmp = generateTsList(fieldListModel, tsGroup); + out.append(tmp); + } else if (model.valueModel instanceof final ClassMapModel fieldMapModel) { + final String tmp = generateTsMap(fieldMapModel, tsGroup); + out.append(tmp); + } else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) { + final String tmp = generateTsObject(fieldObjectModel, tsGroup); + out.append(tmp); + } + out.append(")"); + return out.toString(); + } + + public void generateFile(final String pathPackage, final TsClassElementGroup tsGroup) throws IOException { + if (this.nativeType) { + return; + } + final ClassModel model = this.models.get(0); + String data = ""; + if (model instanceof final ClassEnumModel modelEnum) { + data = generateEnum(modelEnum, tsGroup); + } + if (model instanceof final ClassObjectModel modelObject) { + data = generateObject(modelObject, tsGroup); + } + final Path path = Paths.get(pathPackage + File.separator + "model"); + if (Files.notExists(path)) { + Files.createDirectory(path); + } + final FileWriter myWriter = new FileWriter( + pathPackage + File.separator + "model" + File.separator + this.fileName + ".ts"); + myWriter.write(data); + myWriter.close(); + } + +} \ No newline at end of file diff --git a/src/org/kar/archidata/externalRestApi/TsClassElementGroup.java b/src/org/kar/archidata/externalRestApi/TsClassElementGroup.java new file mode 100644 index 0000000..289e62c --- /dev/null +++ b/src/org/kar/archidata/externalRestApi/TsClassElementGroup.java @@ -0,0 +1,27 @@ +package org.kar.archidata.externalRestApi; + +import java.util.List; + +import org.kar.archidata.externalRestApi.model.ClassModel; + +public class TsClassElementGroup { + private final List tsElements; + + public List getTsElements() { + return this.tsElements; + } + + public TsClassElementGroup(final List tsElements) { + this.tsElements = tsElements; + } + + public TsClassElement find(final ClassModel model) { + for (final TsClassElement elem : this.tsElements) { + if (elem.isCompatible(model)) { + return elem; + } + } + return null; + } + +} diff --git a/src/org/kar/archidata/externalRestApi/TsGenerateApi.java b/src/org/kar/archidata/externalRestApi/TsGenerateApi.java new file mode 100644 index 0000000..e66b930 --- /dev/null +++ b/src/org/kar/archidata/externalRestApi/TsGenerateApi.java @@ -0,0 +1,130 @@ +package org.kar.archidata.externalRestApi; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.kar.archidata.externalRestApi.model.ClassModel; + +public class TsGenerateApi { + + public static List getCompatibleModels( + final List requestedModel, + final List> search) { + final List out = new ArrayList<>(); + for (final ClassModel model : requestedModel) { + if (search.contains(model.getOriginClasses())) { + out.add(model); + } + } + if (out.isEmpty()) { + return null; + } + return out; + } + + public static void generateApi(final AnalyzeApi api, final String pathPackage) throws IOException { + final List localModel = generateApiModel(api); + final TsClassElementGroup tsGroup = new TsClassElementGroup(localModel); + // Generates all files + for (final TsClassElement element : localModel) { + element.generateFile(pathPackage, tsGroup); + } + } + + private static List generateApiModel(final AnalyzeApi api) { + // First step is to add all specific basic elements the wrap correctly the model + final List tsModels = new ArrayList<>(); + List models = getCompatibleModels(api.classModels, List.of(Void.class, void.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "void", "void", null, null, true)); + } + // Map is binded to any ==> can not determine this complex model for now + models = getCompatibleModels(api.classModels, List.of(Map.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "any", "any", null, null, true)); + } + models = getCompatibleModels(api.classModels, List.of(String.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "zod.string()", "string", null, "zod.string()", true)); + } + models = getCompatibleModels(api.classModels, List.of(InputStream.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "z.instanceof(File)", "File", null, "z.instanceof(File)", true)); + } + models = getCompatibleModels(api.classModels, List.of(Boolean.class, boolean.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "zod.boolean()", "boolean", null, "zod.boolean()", true)); + } + models = getCompatibleModels(api.classModels, List.of(UUID.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodUUID", "UUID", "isUUID", "zod.string().uuid()", false)); + } + models = getCompatibleModels(api.classModels, List.of(Long.class, long.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodLong", "Long", "isLong", "zod.number()", false)); + } + models = getCompatibleModels(api.classModels, List.of(Short.class, short.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodShort", "Short", "isShort", "zod.number().safe()", true)); + } + models = getCompatibleModels(api.classModels, List.of(Integer.class, int.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodInteger", "Integer", "isInteger", "zod.number().safe()", true)); + } + models = getCompatibleModels(api.classModels, List.of(Double.class, double.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodDouble", "Double", "isDouble", "zod.number()", true)); + } + models = getCompatibleModels(api.classModels, List.of(Float.class, float.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodFloat", "Float", "isFloat", "zod.number()", false)); + } + models = getCompatibleModels(api.classModels, List.of(Instant.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodInstant", "Instant", "isInstant", "zod.string()", false)); + } + models = getCompatibleModels(api.classModels, List.of(Date.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodDate", "Date", "isDate", + "zod.string().datetime({ precision: 3 })", false)); + } + models = getCompatibleModels(api.classModels, List.of(Timestamp.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodTimestamp", "Timestamp", "isTimestamp", + "zod.string().datetime({ precision: 3 })", false)); + } + models = getCompatibleModels(api.classModels, List.of(LocalDate.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodLocalDate", "LocalDate", "isLocalDate", "zod.string().date()", + false)); + } + models = getCompatibleModels(api.classModels, List.of(LocalTime.class)); + if (models != null) { + tsModels.add(new TsClassElement(models, "ZodLocalTime", "LocalTime", "isLocalTime", "zod.string().time()", + false)); + } + for (final ClassModel model : api.classModels) { + boolean alreadyExist = false; + for (final TsClassElement elem : tsModels) { + if (elem.isCompatible(model)) { + alreadyExist = true; + break; + } + } + if (alreadyExist) { + continue; + } + tsModels.add(new TsClassElement(model)); + } + return tsModels; + } +} diff --git a/src/org/kar/archidata/externalRestApi/model/ApiGroupModel.java b/src/org/kar/archidata/externalRestApi/model/ApiGroupModel.java index 512e2e5..b381323 100644 --- a/src/org/kar/archidata/externalRestApi/model/ApiGroupModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ApiGroupModel.java @@ -20,16 +20,28 @@ public class ApiGroupModel { // Name of the REST end-point name public String restEndPoint; // Name of the Class - String name; + public String name; // Origin class reference - Class originClass; + public Class originClass; // List of all API public List interfaces = new ArrayList<>(); + public ApiModel getInterfaceNamed(final String name) { + for (final ApiModel model : this.interfaces) { + if (name.equals(model.name)) { + return model; + } + } + return null; + } + public ApiGroupModel(final Class clazz, final ModelGroup previousModel) throws Exception { this.originClass = clazz; // the basic path has no specific elements... this.restEndPoint = ApiTool.apiAnnotationGetPath(clazz); + if (this.restEndPoint == null) { + this.restEndPoint = ""; + } this.name = clazz.getSimpleName(); final List consumes = ApiTool.apiAnnotationGetConsumes(clazz); diff --git a/src/org/kar/archidata/externalRestApi/model/ApiModel.java b/src/org/kar/archidata/externalRestApi/model/ApiModel.java index 7324de9..2c201ee 100644 --- a/src/org/kar/archidata/externalRestApi/model/ApiModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ApiModel.java @@ -3,7 +3,6 @@ package org.kar.archidata.externalRestApi.model; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; @@ -33,9 +32,13 @@ public class ApiModel { // Name of the API (function name) public String name; // list of all parameters (/{key}/... - public Map parameters = new HashMap<>(); + public final Map> parameters = new HashMap<>(); // list of all query (?key...) - public Map queries = new HashMap<>(); + public final Map> queries = new HashMap<>(); + // when request multi-part, need to separate it. + public final Map> multiPartParameters = new HashMap<>(); + // model of data available + public final List unnamedElement = new ArrayList<>(); // Possible input type of the REST API public List consumes = new ArrayList<>(); @@ -68,13 +71,17 @@ public class ApiModel { LOGGER.info("Get return Type RAW = {}", returnTypeModelRaw.getCanonicalName()); if (returnTypeModelRaw == Map.class) { LOGGER.warn("Model Map"); - final ParameterizedType listType = (ParameterizedType) method.getGenericReturnType(); - this.returnTypes.add(new ClassMapModel(listType, previousModel)); + final Type listType = method.getGenericReturnType(); + final ClassModel modelGenerated = ClassModel.getModel(listType, previousModel); + this.returnTypes.add(modelGenerated); + LOGGER.warn("Model Map ==> {}", modelGenerated); return; } else if (returnTypeModelRaw == List.class) { LOGGER.warn("Model List"); - final ParameterizedType listType = (ParameterizedType) method.getGenericReturnType(); - this.returnTypes.add(new ClassListModel(listType, previousModel)); + final Type listType = method.getGenericReturnType(); + final ClassModel modelGenerated = ClassModel.getModel(listType, previousModel); + this.returnTypes.add(modelGenerated); + LOGGER.warn("Model List ==> {}", modelGenerated); return; } else { LOGGER.warn("Model Object"); @@ -91,14 +98,18 @@ public class ApiModel { this.originClass = clazz; this.orignMethod = method; - final String methodPath = ApiTool.apiAnnotationGetPath(method); - final String methodType = ApiTool.apiAnnotationGetTypeRequest(method); - final String methodName = method.getName(); + String tmpPath = ApiTool.apiAnnotationGetPath(method); + if (tmpPath == null) { + tmpPath = ""; + } + this.restEndPoint = baseRestEndPoint + "/" + tmpPath; + this.restTypeRequest = ApiTool.apiAnnotationGetTypeRequest2(method); + this.name = method.getName(); this.description = ApiTool.apiAnnotationGetOperationDescription(method); this.consumes = ApiTool.apiAnnotationGetConsumes2(consume, method); this.produces = ApiTool.apiAnnotationProduces2(produce, method); - LOGGER.trace(" [{}] {} => {}/{}", methodType, methodName, baseRestEndPoint, methodPath); + LOGGER.trace(" [{}] {} => {}/{}", baseRestEndPoint, this.name, this.restEndPoint); this.needGenerateProgress = ApiTool.apiAnnotationTypeScriptProgress(method); updateReturnTypes(method, previousModel); @@ -107,10 +118,6 @@ public class ApiModel { LOGGER.trace(" - {}", elem); } - final Map> queryParams = new HashMap<>(); - final Map> pathParams = new HashMap<>(); - final Map> formDataParams = new HashMap<>(); - final List emptyElement = new ArrayList<>(); // LOGGER.info(" Parameters:"); for (final Parameter parameter : method.getParameters()) { // Security context are internal parameter (not available from API) @@ -126,26 +133,32 @@ public class ApiModel { } } else if (parameterType == List.class) { final Type parameterrizedType = parameter.getParameterizedType(); - parameterModel.add(ClassModel.getModelBase(parameterType, parameterrizedType, previousModel)); + final ClassModel modelGenerated = ClassModel.getModel(parameterrizedType, previousModel); + parameterModel.add(modelGenerated); } else if (parameterType == Map.class) { final Type parameterrizedType = parameter.getParameterizedType(); - parameterModel.add(ClassModel.getModelBase(parameterType, parameterrizedType, previousModel)); + final ClassModel modelGenerated = ClassModel.getModel(parameterrizedType, previousModel); + parameterModel.add(modelGenerated); } else { - parameterModel.add(ClassModel.getModel(parameterType, previousModel)); + parameterModel.add(previousModel.add(parameterType)); } final String pathParam = ApiTool.apiAnnotationGetPathParam(parameter); final String queryParam = ApiTool.apiAnnotationGetQueryParam(parameter); final String formDataParam = ApiTool.apiAnnotationGetFormDataParam(parameter); if (queryParam != null) { - queryParams.put(queryParam, parameterModel); + this.queries.put(queryParam, parameterModel); } else if (pathParam != null) { - pathParams.put(pathParam, parameterModel); + this.parameters.put(pathParam, parameterModel); } else if (formDataParam != null) { - formDataParams.put(formDataParam, parameterModel); + this.multiPartParameters.put(formDataParam, parameterModel); } else { - emptyElement.addAll(parameterModel); + this.unnamedElement.addAll(parameterModel); } } + if (this.unnamedElement.size() > 1) { + throw new IOException("Can not parse the API, enmpty element is more than 1 in " + this.name); + } + } } diff --git a/src/org/kar/archidata/externalRestApi/model/ClassEnumModel.java b/src/org/kar/archidata/externalRestApi/model/ClassEnumModel.java index 05da453..c15640f 100644 --- a/src/org/kar/archidata/externalRestApi/model/ClassEnumModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ClassEnumModel.java @@ -1,19 +1,43 @@ package org.kar.archidata.externalRestApi.model; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + public class ClassEnumModel extends ClassModel { protected ClassEnumModel(final Class clazz) { - this.originClasses.add(clazz); + this.originClasses = clazz; } @Override public String toString() { final StringBuilder out = new StringBuilder(); out.append("ClassEnumModel ["); - for (final Class elem : this.originClasses) { - out.append(elem.getCanonicalName()); - } + out.append(this.originClasses.getCanonicalName()); out.append("]"); return out.toString(); } + + final List listOfValues = new ArrayList<>(); + + @Override + public void analyze(final ModelGroup group) throws IOException { + // TODO: check if we really need to have multiple type for enums ??? + final Class clazz = this.originClasses; + final Object[] arr = clazz.getEnumConstants(); + for (final Object elem : arr) { + this.listOfValues.add(elem.toString()); + } + } + + public List getListOfValues() { + return this.listOfValues; + } + + @Override + public Set getAlls() { + return Set.of(this); + } } diff --git a/src/org/kar/archidata/externalRestApi/model/ClassListModel.java b/src/org/kar/archidata/externalRestApi/model/ClassListModel.java index 438114b..47991b7 100644 --- a/src/org/kar/archidata/externalRestApi/model/ClassListModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ClassListModel.java @@ -3,6 +3,7 @@ package org.kar.archidata.externalRestApi.model; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Set; public class ClassListModel extends ClassModel { public ClassModel valueModel; @@ -15,6 +16,10 @@ public class ClassListModel extends ClassModel { this.valueModel = getModel(clazz, previousModel); } + public ClassListModel(final Type model, final ModelGroup previousModel) throws IOException { + this.valueModel = getModel(model, previousModel); + } + public ClassListModel(final ParameterizedType listType, final ModelGroup previousModel) throws IOException { final Type model = listType.getActualTypeArguments()[0]; this.valueModel = getModel(model, previousModel); @@ -25,4 +30,13 @@ public class ClassListModel extends ClassModel { return "ClassListModel [valueModel=" + this.valueModel + "]"; } + @Override + public void analyze(final ModelGroup group) throws IOException { + throw new IOException("Analyze can not be done at this phase for List..."); + } + + @Override + public Set getAlls() { + return this.valueModel.getAlls(); + } } diff --git a/src/org/kar/archidata/externalRestApi/model/ClassMapModel.java b/src/org/kar/archidata/externalRestApi/model/ClassMapModel.java index 4b49f58..a6fe7a8 100644 --- a/src/org/kar/archidata/externalRestApi/model/ClassMapModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ClassMapModel.java @@ -2,6 +2,9 @@ package org.kar.archidata.externalRestApi.model; import java.io.IOException; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; public class ClassMapModel extends ClassModel { public ClassModel keyModel; @@ -12,6 +15,12 @@ public class ClassMapModel extends ClassModel { this.valueModel = valueModel; } + public ClassMapModel(final Type listTypeKey, final Type listTypeValue, final ModelGroup previousModel) + throws IOException { + this.keyModel = getModel(listTypeKey, previousModel); + this.valueModel = getModel(listTypeValue, previousModel); + } + public ClassMapModel(final ParameterizedType listType, final ModelGroup previousModel) throws IOException { this.keyModel = getModel(listType.getActualTypeArguments()[0], previousModel); this.valueModel = getModel(listType.getActualTypeArguments()[1], previousModel); @@ -22,4 +31,15 @@ public class ClassMapModel extends ClassModel { return "ClassMapModel [keyModel=" + this.keyModel + ", valueModel=" + this.valueModel + "]"; } + @Override + public void analyze(final ModelGroup group) throws IOException { + throw new IOException("Analyze can not be done at this phase for Map..."); + } + + @Override + public Set getAlls() { + final Set out = new HashSet<>(this.keyModel.getAlls()); + out.addAll(this.valueModel.getAlls()); + return out; + } } diff --git a/src/org/kar/archidata/externalRestApi/model/ClassModel.java b/src/org/kar/archidata/externalRestApi/model/ClassModel.java index 882c6c1..dbd621b 100644 --- a/src/org/kar/archidata/externalRestApi/model/ClassModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ClassModel.java @@ -6,28 +6,34 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; public abstract class ClassModel { - public List> originClasses = new ArrayList<>(); + protected Class originClasses = null; + protected List dependencyModels = new ArrayList<>(); + + public Class getOriginClasses() { + return this.originClasses; + } protected boolean isCompatible(final Class clazz) { - return this.originClasses.contains(clazz); + return this.originClasses == clazz; + } + + public List getDependencyModels() { + return this.dependencyModels; } public static ClassModel getModel(final Type type, final ModelGroup previousModel) throws IOException { - if (type == List.class) { - if (type instanceof final ParameterizedType parameterizedType) { - return new ClassListModel(parameterizedType, previousModel); - } else { - throw new IOException("Fail to manage parametrized type..."); + if (type instanceof final ParameterizedType paramType) { + final Type[] typeArguments = paramType.getActualTypeArguments(); + if (paramType.getRawType() == List.class) { + return new ClassListModel(typeArguments[0], previousModel); } - } - if (type == Map.class) { - if (type instanceof final ParameterizedType parameterizedType) { - return new ClassMapModel(parameterizedType, previousModel); - } else { - throw new IOException("Fail to manage parametrized type..."); + if (paramType.getRawType() == Map.class) { + return new ClassMapModel(typeArguments[0], typeArguments[1], previousModel); } + throw new IOException("Fail to manage parametrized type..."); } return previousModel.add((Class) type); } @@ -36,6 +42,7 @@ public abstract class ClassModel { final Class clazz, final Type parameterizedType, final ModelGroup previousModel) throws IOException { + /* if (clazz == List.class) { return new ClassListModel((ParameterizedType) parameterizedType, previousModel); } @@ -43,6 +50,8 @@ public abstract class ClassModel { return new ClassMapModel((ParameterizedType) parameterizedType, previousModel); } return previousModel.add(clazz); + */ + return getModel(parameterizedType, previousModel); } public static ClassModel getModel(final Class type, final ModelGroup previousModel) throws IOException { @@ -55,4 +64,8 @@ public abstract class ClassModel { return previousModel.add(type); } + public abstract void analyze(final ModelGroup group) throws Exception; + + public abstract Set getAlls(); + } diff --git a/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java b/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java index f40c4ba..b28520a 100644 --- a/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java +++ b/src/org/kar/archidata/externalRestApi/model/ClassObjectModel.java @@ -1,19 +1,161 @@ package org.kar.archidata.externalRestApi.model; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.kar.archidata.annotation.AnnotationTools; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class ClassObjectModel extends ClassModel { + static final Logger LOGGER = LoggerFactory.getLogger(ClassObjectModel.class); public ClassObjectModel(final Class clazz) { - this.originClasses.add(clazz); + this.originClasses = clazz; } @Override public String toString() { final StringBuilder out = new StringBuilder(); out.append("ClassObjectModel ["); - for (final Class elem : this.originClasses) { - out.append(elem.getCanonicalName()); - } + out.append(this.originClasses.getCanonicalName()); out.append("]"); return out.toString(); } + + private static boolean isFieldFromSuperClass(final Class model, final String filedName) { + final Class superClass = model.getSuperclass(); + if (superClass == null) { + return false; + } + for (final Field field : superClass.getFields()) { + String name; + try { + name = AnnotationTools.getFieldName(field); + if (filedName.equals(name)) { + return true; + } + } catch (final Exception e) { + // TODO Auto-generated catch block + LOGGER.trace("Catch error field name in parent create data table: {}", e.getMessage()); + } + } + return false; + } + + public record FieldProperty( + String name, + ClassModel model, + String comment, + int limitSize, + boolean readOnly) { + + public FieldProperty(final String name, final ClassModel model, final String comment, final int limitSize, + final boolean readOnly) { + this.name = name; + this.model = model; + this.comment = comment; + this.limitSize = limitSize; + this.readOnly = readOnly; + } + + public FieldProperty(final Field field, final ModelGroup previous) throws Exception { + this(field.getName(), // + ClassModel.getModel(field.getGenericType(), previous), // + AnnotationTools.getComment(field), // + AnnotationTools.getLimitSize(field), // + AnnotationTools.getSchemaReadOnly(field)); + } + + } + + String name = ""; + boolean isPrimitive = false; + String description = null; + String example = null; + ClassModel extendsClass = null; + List fields = new ArrayList<>(); + + public String getName() { + return this.name; + } + + public boolean isPrimitive() { + return this.isPrimitive; + } + + public String getDescription() { + return this.description; + } + + public String getExample() { + return this.example; + } + + public ClassModel getExtendsClass() { + return this.extendsClass; + } + + public List getFields() { + return this.fields; + } + + @Override + public void analyze(final ModelGroup previous) throws Exception { + final Class clazz = this.originClasses; + this.isPrimitive = clazz.isPrimitive(); + if (this.isPrimitive) { + return; + } + // Local generation of class: + LOGGER.trace("parse class: '{}'", clazz.getCanonicalName()); + final List alreadyAdded = new ArrayList<>(); + for (final Field elem : clazz.getFields()) { + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + final String dataName = elem.getName(); + if (isFieldFromSuperClass(clazz, dataName)) { + LOGGER.trace(" SKIP: '{}'", elem.getName()); + continue; + } + if (alreadyAdded.contains(dataName)) { + LOGGER.trace(" SKIP2: '{}'", elem.getName()); + continue; + } + alreadyAdded.add(dataName); + LOGGER.trace(" + '{}'", elem.getName()); + LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem), elem.getType()); + final FieldProperty porperty = new FieldProperty(elem, previous); + for (final ClassModel depModel : porperty.model().getAlls()) { + if (!this.dependencyModels.contains(depModel)) { + this.dependencyModels.add(depModel); + } + } + this.fields.add(new FieldProperty(elem, previous)); + } + this.name = clazz.getName(); + + final String[] elems = this.name.split("\\$"); + if (elems.length == 2) { + LOGGER.warn("Can have conflict in generation: {} (Remove class path) ==> {}", this.name, elems[1]); + this.name = elems[1]; + } + this.description = AnnotationTools.getSchemaDescription(clazz); + this.example = AnnotationTools.getSchemaExample(clazz); + final Class parentClass = clazz.getSuperclass(); + // manage heritage + if (parentClass != null && parentClass != Object.class && parentClass != Record.class) { + this.extendsClass = previous.add(parentClass); + this.dependencyModels.add(this.extendsClass); + } + } + + @Override + public Set getAlls() { + return Set.of(this); + } + } diff --git a/src/org/kar/archidata/externalRestApi/model/ModelGroup.java b/src/org/kar/archidata/externalRestApi/model/ModelGroup.java index f4eafaa..25d6c94 100644 --- a/src/org/kar/archidata/externalRestApi/model/ModelGroup.java +++ b/src/org/kar/archidata/externalRestApi/model/ModelGroup.java @@ -6,6 +6,8 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.core.Response; + public class ModelGroup { static final Logger LOGGER = LoggerFactory.getLogger(ModelGroup.class); public List previousModel = new ArrayList<>(); @@ -16,7 +18,10 @@ public class ModelGroup { this.previousModel = models; } - public ClassModel add(final Class clazz) { + public ClassModel add(Class clazz) { + if (clazz == Response.class) { + clazz = Object.class; + } //LOGGER.trace("Search element {}", clazz.getCanonicalName()); for (final ClassModel value : this.previousModel) { if (value.isCompatible(clazz)) { diff --git a/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiName.java b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiName.java new file mode 100644 index 0000000..d8fc840 --- /dev/null +++ b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiName.java @@ -0,0 +1,47 @@ +package test.kar.archidata.externalRestApi; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.kar.archidata.externalRestApi.AnalyzeApi; +import org.kar.archidata.externalRestApi.model.ApiModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.GET; + +public class TestAnalyzeApiName { + final static private Logger LOGGER = LoggerFactory.getLogger(TestAnalyzeApiName.class); + + public class ApiName { + @GET + public void firstName() { + + } + + @GET + public void SecondName() { + + } + } + + @Test + public void testNames() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ApiName.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals("ApiName", api.apiModels.get(0).name); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("firstName"); + Assertions.assertNotNull(model); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("SecondName"); + Assertions.assertNotNull(model); + } + } + +} diff --git a/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiParameterType.java b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiParameterType.java new file mode 100644 index 0000000..bf759ac --- /dev/null +++ b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiParameterType.java @@ -0,0 +1,143 @@ +package test.kar.archidata.externalRestApi; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.kar.archidata.externalRestApi.AnalyzeApi; +import org.kar.archidata.externalRestApi.model.ApiModel; +import org.kar.archidata.externalRestApi.model.ClassEnumModel; +import org.kar.archidata.externalRestApi.model.ClassListModel; +import org.kar.archidata.externalRestApi.model.ClassMapModel; +import org.kar.archidata.externalRestApi.model.ClassObjectModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.GET; + +public class TestAnalyzeApiParameterType { + final static private Logger LOGGER = LoggerFactory.getLogger(TestAnalyzeApiParameterType.class); + + public enum TestEnum { + PLOP, PLIP + } + + public class TestObject { + public int value; + } + + public class BasicParameter { + @GET + public void setInteger1(final int parameter) {} + + @GET + public void setInteger2(final Integer parameter) {} + + @GET + public void setString(final String parameter) {} + + @GET + public void setObject(final TestObject parameter) {} + + @GET + public void setEnum(final TestEnum parameter) {} + } + + @Test + public void testBasicParameter() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(BasicParameter.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(5, api.apiModels.get(0).interfaces.size()); + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setInteger1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.unnamedElement.get(0)); + Assertions.assertEquals(int.class, classModel.getOriginClasses()); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setInteger2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.unnamedElement.get(0)); + Assertions.assertEquals(Integer.class, classModel.getOriginClasses()); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setString"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.unnamedElement.get(0)); + Assertions.assertEquals(String.class, classModel.getOriginClasses()); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setObject"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.unnamedElement.get(0)); + Assertions.assertEquals(TestObject.class, classModel.getOriginClasses()); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setEnum"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassEnumModel classModel = Assertions.assertInstanceOf(ClassEnumModel.class, + model.unnamedElement.get(0)); + Assertions.assertEquals(TestEnum.class, classModel.getOriginClasses()); + } + + } + + public class ListParameter { + @GET + public void setList(final List parameter) {} + } + + @Test + public void testListParameter() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ListParameter.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(1, api.apiModels.get(0).interfaces.size()); + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setList"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassListModel classModel = Assertions.assertInstanceOf(ClassListModel.class, + model.unnamedElement.get(0)); + final ClassObjectModel classModelValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classModel.valueModel); + Assertions.assertEquals(Integer.class, classModelValue.getOriginClasses()); + + } + + public class MapParameter { + @GET + public void setMap(final Map parameter) {} + } + + @Test + public void testMapParameter() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(MapParameter.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(1, api.apiModels.get(0).interfaces.size()); + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("setMap"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.unnamedElement.size()); + final ClassMapModel classModel = Assertions.assertInstanceOf(ClassMapModel.class, model.unnamedElement.get(0)); + final ClassObjectModel classModelKey = Assertions.assertInstanceOf(ClassObjectModel.class, classModel.keyModel); + Assertions.assertEquals(String.class, classModelKey.getOriginClasses()); + final ClassObjectModel classModelValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classModel.valueModel); + Assertions.assertEquals(Integer.class, classModelValue.getOriginClasses()); + + } +} diff --git a/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiPath.java b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiPath.java new file mode 100644 index 0000000..7b931ce --- /dev/null +++ b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiPath.java @@ -0,0 +1,107 @@ +package test.kar.archidata.externalRestApi; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.kar.archidata.externalRestApi.AnalyzeApi; +import org.kar.archidata.externalRestApi.model.ApiModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +public class TestAnalyzeApiPath { + final static private Logger LOGGER = LoggerFactory.getLogger(TestAnalyzeApiPath.class); + + public class NoPath { + @GET + public void noPath() { + + } + + @GET + @Path("plop") + public void withPath() { + + } + + @GET + @Path("/plop") + public void withPath2() { + + } + } + + @Test + public void testNoPath() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(NoPath.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals("", api.apiModels.get(0).restEndPoint); + Assertions.assertEquals(3, api.apiModels.get(0).interfaces.size()); + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("noPath"); + Assertions.assertNotNull(model); + Assertions.assertEquals("/", model.restEndPoint); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("withPath"); + Assertions.assertNotNull(model); + Assertions.assertEquals("/plop", model.restEndPoint); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("withPath2"); + Assertions.assertNotNull(model); + Assertions.assertEquals("//plop", model.restEndPoint); + } + } + + @Path("/kaboom") + public class WithPath { + @GET + public void noPath() { + + } + + @GET + @Path("plop") + public void withPath() { + + } + + @GET + @Path("/plop") + public void withPath2() { + + } + } + + @Test + public void testWithPath() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(WithPath.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals("/kaboom", api.apiModels.get(0).restEndPoint); + Assertions.assertEquals(3, api.apiModels.get(0).interfaces.size()); + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("noPath"); + Assertions.assertNotNull(model); + Assertions.assertEquals("/kaboom/", model.restEndPoint); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("withPath"); + Assertions.assertNotNull(model); + Assertions.assertEquals("/kaboom/plop", model.restEndPoint); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("withPath2"); + Assertions.assertNotNull(model); + Assertions.assertEquals("/kaboom//plop", model.restEndPoint); + } + } + +} diff --git a/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiReturn.java b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiReturn.java new file mode 100644 index 0000000..38cad58 --- /dev/null +++ b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeApiReturn.java @@ -0,0 +1,605 @@ +package test.kar.archidata.externalRestApi; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.kar.archidata.externalRestApi.AnalyzeApi; +import org.kar.archidata.externalRestApi.model.ApiModel; +import org.kar.archidata.externalRestApi.model.ClassEnumModel; +import org.kar.archidata.externalRestApi.model.ClassListModel; +import org.kar.archidata.externalRestApi.model.ClassMapModel; +import org.kar.archidata.externalRestApi.model.ClassObjectModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.core.Response; + +public class TestAnalyzeApiReturn { + final static private Logger LOGGER = LoggerFactory.getLogger(TestAnalyzeApiReturn.class); + + public enum TestEnum { + PLOP, PLIP + } + + public class TestObject { + public int value; + } + + public class ReturnValueVoid { + @GET + public void getVoid1() {} + + @GET + public Void getVoid2() { + return null; + } + } + + @Test + public void testReturnVoid() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueVoid.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getVoid1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(void.class, classModel.getOriginClasses()); + } + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getVoid2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Void.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueInteger { + @GET + public int getInteger1() { + return 0; + } + + @GET + public Integer getInteger2() { + return 0; + } + + } + + @Test + public void testReturnInteger() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueInteger.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + // Check int + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getInteger1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(int.class, classModel.getOriginClasses()); + } + // Check Integer + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getInteger2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Integer.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueShort { + @GET + public short getShort1() { + return 0; + } + + @GET + public Short getShort2() { + return 0; + } + + } + + @Test + public void testReturnShort() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueShort.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + // Check short + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getShort1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(short.class, classModel.getOriginClasses()); + } + // Check Short + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getShort2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Short.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueLong { + @GET + public long getLong1() { + return 0; + } + + @GET + public Long getLong2() { + return 0L; + } + + } + + @Test + public void testReturnLong() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueLong.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + // Check long + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getLong1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(long.class, classModel.getOriginClasses()); + } + // Check Long + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getLong2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + Assertions.assertInstanceOf(ClassObjectModel.class, model.returnTypes.get(0)); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Long.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueFloat { + @GET + public float getFloat1() { + return 0; + } + + @GET + public Float getFloat2() { + return 0.0f; + } + + } + + @Test + public void testReturnFloat() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueFloat.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + // Check float + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getFloat1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(float.class, classModel.getOriginClasses()); + } + // Check Float + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getFloat2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Float.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueDouble { + @GET + public double getDouble1() { + return 0; + } + + @GET + public Double getDouble2() { + return 0.0; + } + + } + + @Test + public void testReturnDouble() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueDouble.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + // Check double + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getDouble1"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(double.class, classModel.getOriginClasses()); + } + // Check Double + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getDouble2"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Double.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueString { + @GET + public String getString() { + return "0"; + } + + } + + @Test + public void testReturnString() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueString.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(1, api.apiModels.get(0).interfaces.size()); + // Check String + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getString"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(String.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueAny { + @GET + public Response getResponse() { + return null; + } + + @GET + public Object getObject() { + return null; + } + } + + @Test + public void testReturnAny() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueAny.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(2, api.apiModels.get(0).interfaces.size()); + // Check Response ==> represent a Any value then it wrapped as Object + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getResponse"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Object.class, classModel.getOriginClasses()); + } + // Check Object + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getObject"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(Object.class, classModel.getOriginClasses()); + } + + } + + public class ReturnValueEnum { + @GET + public TestEnum getEnum() { + return TestEnum.PLIP; + } + + } + + @Test + public void testReturnEnum() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueEnum.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(1, api.apiModels.get(0).interfaces.size()); + // Check Enum + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getEnum"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + final ClassEnumModel classModel = Assertions.assertInstanceOf(ClassEnumModel.class, + model.returnTypes.get(0)); + Assertions.assertEquals(TestEnum.class, classModel.getOriginClasses()); + } + } + + public class ReturnValueList { + @GET + public List getListInteger() { + return null; + } + + @GET + public List getListEnum() { + return null; + } + + @GET + public List getListObject() { + return null; + } + + @GET + public List> getListListInteger() { + return null; + } + + @GET + public List> getListMapInteger() { + return null; + } + + } + + @Test + public void testReturnList() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueList.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(5, api.apiModels.get(0).interfaces.size()); + // Check List + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getListInteger"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassListModel classListModel = Assertions.assertInstanceOf(ClassListModel.class, + model.returnTypes.get(0)); + // Level 1 + final ClassObjectModel classModelOfValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classListModel.valueModel); + Assertions.assertEquals(Integer.class, classModelOfValue.getOriginClasses()); + } + // Check List + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getListEnum"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassListModel classListModel = Assertions.assertInstanceOf(ClassListModel.class, + model.returnTypes.get(0)); + // Level 1 + final ClassEnumModel classModelOfValue = Assertions.assertInstanceOf(ClassEnumModel.class, + classListModel.valueModel); + Assertions.assertEquals(TestEnum.class, classModelOfValue.getOriginClasses()); + } + // Check List + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getListObject"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassListModel classListModel = Assertions.assertInstanceOf(ClassListModel.class, + model.returnTypes.get(0)); + // Level 1 + final ClassObjectModel classModelOfValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classListModel.valueModel); + Assertions.assertEquals(Integer.class, classModelOfValue.getOriginClasses()); + } + // Check List> + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getListListInteger"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassListModel classListModel = Assertions.assertInstanceOf(ClassListModel.class, + model.returnTypes.get(0)); + // Level 1 + final ClassListModel classList2Model = Assertions.assertInstanceOf(ClassListModel.class, + classListModel.valueModel); + // Level 2 + final ClassObjectModel classModelOfValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classList2Model.valueModel); + Assertions.assertEquals(Integer.class, classModelOfValue.getOriginClasses()); + } + // Check List> + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getListMapInteger"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassListModel classListModel = Assertions.assertInstanceOf(ClassListModel.class, + model.returnTypes.get(0)); + // Level 1 + final ClassMapModel classMapModel = Assertions.assertInstanceOf(ClassMapModel.class, + classListModel.valueModel); + // Level 2 + final ClassObjectModel classModelOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.keyModel); + Assertions.assertEquals(String.class, classModelOfKey.getOriginClasses()); + final ClassObjectModel classModelOfValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.valueModel); + Assertions.assertEquals(Integer.class, classModelOfValue.getOriginClasses()); + } + + } + + // does not test other than key string, but in theory it works. + public class ReturnValueMap { + @GET + public Map getMapInteger() { + return null; + } + + @GET + public Map getMapEnum() { + return null; + } + + @GET + public Map getMapObject() { + return null; + } + + @GET + public Map> getMapMap() { + return null; + } + + @GET + public Map> getMapList() { + return null; + } + + } + + @Test + public void testReturnMap() throws Exception { + final AnalyzeApi api = new AnalyzeApi(); + api.createApi(List.of(ReturnValueMap.class)); + + Assertions.assertEquals(1, api.apiModels.size()); + Assertions.assertEquals(5, api.apiModels.get(0).interfaces.size()); + // Check Map + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getMapInteger"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassMapModel classMapModel = Assertions.assertInstanceOf(ClassMapModel.class, + model.returnTypes.get(0)); + final ClassObjectModel classModelOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.keyModel); + Assertions.assertEquals(String.class, classModelOfKey.getOriginClasses()); + // Level 1 + final ClassObjectModel classModelOfValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.valueModel); + Assertions.assertEquals(Integer.class, classModelOfValue.getOriginClasses()); + } + // Check Map + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getMapEnum"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassMapModel classMapModel = Assertions.assertInstanceOf(ClassMapModel.class, + model.returnTypes.get(0)); + final ClassObjectModel classModelOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.keyModel); + Assertions.assertEquals(String.class, classModelOfKey.getOriginClasses()); + // Level 1 + final ClassEnumModel classModelOfValue = Assertions.assertInstanceOf(ClassEnumModel.class, + classMapModel.valueModel); + Assertions.assertEquals(TestEnum.class, classModelOfValue.getOriginClasses()); + } + // Check Map + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getMapObject"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassMapModel classMapModel = Assertions.assertInstanceOf(ClassMapModel.class, + model.returnTypes.get(0)); + final ClassObjectModel classModelOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.keyModel); + Assertions.assertEquals(String.class, classModelOfKey.getOriginClasses()); + // Level 1 + final ClassObjectModel classModelOfValue = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.valueModel); + Assertions.assertEquals(TestObject.class, classModelOfValue.getOriginClasses()); + } + // Check Map> + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getMapMap"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassMapModel classMapModel = Assertions.assertInstanceOf(ClassMapModel.class, + model.returnTypes.get(0)); + final ClassObjectModel classModelOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.keyModel); + Assertions.assertEquals(String.class, classModelOfKey.getOriginClasses()); + // Level 1 + final ClassMapModel classModelOfValue = Assertions.assertInstanceOf(ClassMapModel.class, + classMapModel.valueModel); + final ClassObjectModel classModelOfValueOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classModelOfValue.keyModel); + Assertions.assertEquals(String.class, classModelOfValueOfKey.getOriginClasses()); + + final ClassObjectModel classSubModel = Assertions.assertInstanceOf(ClassObjectModel.class, + classModelOfValue.valueModel); + Assertions.assertEquals(Integer.class, classSubModel.getOriginClasses()); + } + // Check Map> + { + final ApiModel model = api.apiModels.get(0).getInterfaceNamed("getMapList"); + Assertions.assertNotNull(model); + Assertions.assertEquals(1, model.returnTypes.size()); + // Level 0 + final ClassMapModel classMapModel = Assertions.assertInstanceOf(ClassMapModel.class, + model.returnTypes.get(0)); + final ClassObjectModel classModelOfKey = Assertions.assertInstanceOf(ClassObjectModel.class, + classMapModel.keyModel); + Assertions.assertEquals(String.class, classModelOfKey.getOriginClasses()); + // Level 1 + final ClassListModel classModelOfValue = Assertions.assertInstanceOf(ClassListModel.class, + classMapModel.valueModel); + final ClassObjectModel classSubModel = Assertions.assertInstanceOf(ClassObjectModel.class, + classModelOfValue.valueModel); + Assertions.assertEquals(Integer.class, classSubModel.getOriginClasses()); + } + + } + +} diff --git a/test/src/test/kar/archidata/externalRestApi/TestAnalyzeModel.java b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeModel.java new file mode 100644 index 0000000..77203d1 --- /dev/null +++ b/test/src/test/kar/archidata/externalRestApi/TestAnalyzeModel.java @@ -0,0 +1,43 @@ +package test.kar.archidata.externalRestApi; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.kar.archidata.externalRestApi.AnalyzeModel; +import org.kar.archidata.externalRestApi.model.ClassModel; +import org.kar.archidata.externalRestApi.model.ClassObjectModel; +import org.kar.archidata.externalRestApi.model.ClassObjectModel.FieldProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestAnalyzeModel { + final static private Logger LOGGER = LoggerFactory.getLogger(TestAnalyzeModel.class); + + public class TestObject { + public Integer value; + } + + @Test + public void testNames() throws Exception { + final ClassObjectModel model = new ClassObjectModel(TestObject.class); + final List models = new ArrayList<>(); + models.add(model); + AnalyzeModel.fillModel(models); + + Assertions.assertEquals("TestObject", model.getName()); + Assertions.assertEquals(false, model.isPrimitive()); + Assertions.assertNull(model.getDescription()); + Assertions.assertNull(model.getExample()); + Assertions.assertNull(model.getExtendsClass()); + Assertions.assertEquals(1, model.getFields().size()); + final FieldProperty fieldProperty = model.getFields().get(0); + Assertions.assertEquals("value", fieldProperty.name()); + + final ClassObjectModel classModel = Assertions.assertInstanceOf(ClassObjectModel.class, fieldProperty.model()); + Assertions.assertEquals(Integer.class, classModel.getOriginClasses()); + + } + +}