[FEAT] add link of List<UUID> that is decorate with @ManyToOne, or @ManyToMany or @OneToMany

This commit is contained in:
Edouard DUPIN 2024-06-20 00:09:37 +02:00
parent 7e81bfef28
commit cdb4581799
6 changed files with 206 additions and 172 deletions

View File

@ -17,7 +17,9 @@ import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@ -136,18 +138,30 @@ public class AnnotationTools {
return ((DefaultValue) annotation[0]).value();
}
public static ManyToOne getManyToOne(final Field element) throws DataAccessException {
public static ManyToOne getManyToOne(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToOne.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @ManyToOne on " + element.getClass().getCanonicalName());
}
return (ManyToOne) annotation[0];
}
public static ManyToMany getManyToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToMany.class);
if (annotation.length == 0) {
return null;
}
return (ManyToMany) annotation[0];
}
public static OneToMany getOneToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(OneToMany.class);
if (annotation.length == 0) {
return null;
}
return (OneToMany) annotation[0];
}
public static DataJson getDataJson(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataJson.class);
if (annotation.length == 0) {

View File

@ -23,7 +23,7 @@ import org.kar.archidata.externalRestApi.model.ApiGroupModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
public class DotGenerateApi {
public static void generateApi(final AnalyzeApi api, final String pathDotFile) throws Exception {
final List<DotClassElement> localModel = generateApiModel(api);
final DotClassElementGroup dotGroup = new DotClassElementGroup(localModel);
@ -64,18 +64,20 @@ public class DotGenerateApi {
myWriter.write("\n");
}
// create an invisible link to force all element to be link together:
String previous = null;
for (final ApiGroupModel element : api.apiModels) {
if (previous == null) {
if (false) {
String previous = null;
for (final ApiGroupModel element : api.apiModels) {
if (previous == null) {
previous = element.name;
continue;
}
myWriter.write("\t{ ");
myWriter.write(previous);
myWriter.write(":s -> ");
previous = element.name;
continue;
myWriter.write(previous);
myWriter.write(":n [style=invis]}\n");
}
myWriter.write("\t{ ");
myWriter.write(previous);
myWriter.write(":s -> ");
previous = element.name;
myWriter.write(previous);
myWriter.write(":n [style=invis]}\n");
}
/*
myWriter.write("""
@ -105,7 +107,7 @@ public class DotGenerateApi {
""");
}
}
private static List<DotClassElement> generateApiModel(final AnalyzeApi api) throws Exception {
// First step is to add all specific basic elements the wrap correctly the model
final List<DotClassElement> dotModels = new ArrayList<>();
@ -224,7 +226,7 @@ public class DotGenerateApi {
dotModels.add(new DotClassElement(model));
}
return dotModels;
}
}

View File

@ -1,6 +1,7 @@
package org.kar.archidata.externalRestApi.dot;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
@ -19,7 +20,7 @@ import org.slf4j.LoggerFactory;
public class DotApiGeneration {
static final Logger LOGGER = LoggerFactory.getLogger(DotApiGeneration.class);
public static String generateClassEnumModelTypescript(
final ClassEnumModel model,
final DotClassElementGroup dotGroup,
@ -28,7 +29,7 @@ public class DotApiGeneration {
final DotClassElement dotModel = dotGroup.find(model);
return dotModel.dotTypeName;
}
public static String generateClassObjectModelTypescript(
final ClassObjectModel model,
final DotClassElementGroup dotGroup,
@ -42,7 +43,7 @@ public class DotApiGeneration {
}
return dotModel.dotTypeName;
}
public static String generateClassMapModelTypescript(
final ClassMapModel model,
final DotClassElementGroup dotGroup,
@ -55,7 +56,7 @@ public class DotApiGeneration {
out.append("&gt;");
return out.toString();
}
public static String generateClassListModelTypescript(
final ClassListModel model,
final DotClassElementGroup dotGroup,
@ -66,7 +67,7 @@ public class DotApiGeneration {
out.append("&gt;");
return out.toString();
}
public static String generateClassModelTypescript(
final ClassModel model,
final DotClassElementGroup dotGroup,
@ -85,88 +86,61 @@ public class DotApiGeneration {
}
throw new IOException("Impossible model:" + model);
}
public static String generateClassModelsTypescript(
final List<ClassModel> models,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 0) {
return "void";
}
final StringBuilder out = new StringBuilder();
if (models.size() > 1) {
out.append("Union&lt;");
}
boolean isFirst = true;
for (final ClassModel model : models) {
if (isFirst) {
isFirst = false;
} else {
out.append(" | ");
out.append(", ");
}
final String data = generateClassModelTypescript(model, dotGroup, imports);
final String data = DotClassElement.generateClassModelTypescript(model, dotGroup);
out.append(data);
}
if (models.size() > 1) {
out.append("&gt;");
}
return out.toString();
}
public static List<String> generateClassModelsLinks(
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
// a ce point ca fait les union et tout et tou, mais il vas faloir fusionner avec les class ...
ICI CA PLANTE !!!
if (models.size() == 0) {
return null;
}
final StringBuilder out = new StringBuilder();
boolean isFirst = true;
final List<String> out = new ArrayList<>();
final boolean isFirst = true;
for (final ClassModel model : models) {
if (isFirst) {
isFirst = false;
} else {
out.append(" | ");
final String data = DotClassElement.generateClassModelTypescriptLink(model, dotGroup);
if (data != null) {
out.add(data);
}
final String data = generateClassModelTypescript(model, dotGroup, imports);
out.append(data);
}
return out.toString();
return out;
}
public static String capitalizeFirstLetter(final String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
public static String generateApiFile(final ApiGroupModel element, final DotClassElementGroup dotGroup)
throws IOException {
final StringBuilder data = new StringBuilder();
final String polkop = """
API_REST_PLOP [
shape=plain
label=<<table color="#FF3333" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td><b>MY_CLASS_NAME</b><br/>(REST)</td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
<tr>
<td align="left" port="PROPERTY_1_REF" >
+ plop(xxx: Kaboom) : KataPloof<br/>
&nbsp;&nbsp;&nbsp;&nbsp;/qsdqds/{id}/
</td>
</tr>
<tr>
<td align="left" port="PROPERTY_2_REF" >
+ plop(xxx: Kaboom) : KataPloof<br/>
&nbsp;&nbsp;&nbsp;&nbsp;/qsdqds/{id}/
</td>
</tr>
</table>
</td>
</tr>
</table>>
]
""";
final StringBuilder outLinks = new StringBuilder();
data.append("""
%s [
shape=plain
@ -195,7 +169,9 @@ public class DotApiGeneration {
}
}
*/
data.append("\t\t\t\t\t<tr><td align=\"left\"><b> + ");
data.append("\t\t\t\t\t<tr><td align=\"left\" port=\"");
data.append(interfaceElement.name);
data.append("\"><b> + ");
data.append(interfaceElement.name);
data.append("(");
boolean hasParam = false;
@ -248,7 +224,7 @@ public class DotApiGeneration {
hasParam2 = true;
data.append(pathEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(pathEntry.getValue(), dotGroup, writeImports));
data.append(generateClassModelsTypescript(pathEntry.getValue(), dotGroup));
}
data.append("}");
}
@ -263,26 +239,18 @@ public class DotApiGeneration {
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
*/
/*if (returnComplexModel != null) {
data.append(returnModelNameIfComplex);
} else*/ {
if (interfaceElement.returnTypes instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(interfaceElement.returnTypes);
data.append(dotFieldModel.dotTypeName);
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(dotFieldModel.dotTypeName);
outLinks.append(":NAME:w\n");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, dotGroup,
imports);
data.append(returnType);
}
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, dotGroup);
data.append(returnType);
final List<String> returnLinks = generateClassModelsLinks(interfaceElement.returnTypes, dotGroup);
for (final String link : returnLinks) {
outLinks.append("\t");
outLinks.append(element.name);
outLinks.append(":");
outLinks.append(interfaceElement.name);
outLinks.append(":e -> ");
outLinks.append(link);
outLinks.append(":NAME:w\n");
}
data.append("</b>");
//data.append("<br align=\"left\"/>&nbsp;&nbsp;&nbsp;&nbsp;");
data.append("</td></tr>\n\t\t\t\t\t\t\t<tr><td align=\"left\"> ");
@ -367,9 +335,9 @@ public class DotApiGeneration {
}
/*
data.append("\n}\n");
final StringBuilder out = new StringBuilder();
final List<String> toolImportsList = new ArrayList<>(toolImports);
Collections.sort(toolImportsList);
if (toolImportsList.size() != 0) {
@ -381,13 +349,13 @@ public class DotApiGeneration {
}
out.append("\n} from \"../rest-tools\";\n\n");
}
if (zodImports.size() != 0) {
out.append("import { z as zod } from \"zod\"\n");
}
final Set<String> finalImportSet = new TreeSet<>();
for (final ClassModel model : imports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
@ -418,7 +386,7 @@ public class DotApiGeneration {
}
finalImportSet.add(dotModel.dotTypeName + "Write");
}
if (finalImportSet.size() != 0) {
out.append("import {");
for (final String elem : finalImportSet) {
@ -428,10 +396,10 @@ public class DotApiGeneration {
}
out.append("\n} from \"../model\";\n\n");
}
out.append(data.toString());
*/
data.append("""
</table>
</td>
@ -439,7 +407,8 @@ public class DotApiGeneration {
</table>>
]
""");
data.append(outLinks.toString());
return data.toString();
}
}

View File

@ -15,13 +15,13 @@ import org.slf4j.LoggerFactory;
public class DotClassElement {
static final Logger LOGGER = LoggerFactory.getLogger(DotClassElement.class);
public enum DefinedPosition {
NATIVE, // Native element of dot language.
BASIC, // basic wrapping for JAVA type.
NORMAL // Normal Object to interpret.
}
public List<ClassModel> models;
public String zodName;
public String dotTypeName;
@ -30,11 +30,11 @@ public class DotClassElement {
public String fileName = null;
public String comment = null;
public DefinedPosition nativeType = DefinedPosition.NORMAL;
public static String determineFileName(final String className) {
return className.replaceAll("([a-z])([A-Z])", "$1-$2").replaceAll("([A-Z])([A-Z][a-z])", "$1-$2").toLowerCase();
}
public DotClassElement(final List<ClassModel> model, final String zodName, final String dotTypeName,
final String dotCheckType, final String declaration, final DefinedPosition nativeType) {
this.models = model;
@ -43,17 +43,17 @@ public class DotClassElement {
this.declaration = declaration;
this.nativeType = nativeType;
}
public DotClassElement(final ClassModel model) {
this.models = List.of(model);
this.dotTypeName = model.getOriginClasses().getSimpleName();
this.declaration = null;
}
public boolean isCompatible(final ClassModel model) {
return this.models.contains(model);
}
public String generateEnum(final ClassEnumModel model, final DotClassElementGroup dotGroup) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("""
@ -106,7 +106,7 @@ public class DotClassElement {
}
return out.toString();
}
private Object generateComment(final ClassObjectModel model) {
final StringBuilder out = new StringBuilder();
if (model.getDescription() != null || model.getExample() != null) {
@ -132,7 +132,7 @@ public class DotClassElement {
}
return out.toString();
}
public String optionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (field.nullable()) {
@ -150,7 +150,7 @@ public class DotClassElement {
}
return ".optional()";
}
public String maxSizeZod(final FieldProperty field) {
final StringBuilder builder = new StringBuilder();
final Class<?> clazz = field.model().getOriginClasses();
@ -182,23 +182,63 @@ public class DotClassElement {
}
return builder.toString();
}
public String readOnlyZod(final FieldProperty field) {
if (field.readOnly()) {
return ".readonly()";
}
return "";
}
public String generateBaseObject() {
final StringBuilder out = new StringBuilder();
return out.toString();
}
public String convertHtml(final String data) {
return data.replace("<", "&lt;").replace(">", "&gt;");
}
public static String generateClassModelTypescript(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof final ClassListModel fieldListModel) {
return generateDotList(fieldListModel, dotGroup);
} else if (model instanceof final ClassMapModel fieldMapModel) {
return generateDotMap(fieldMapModel, dotGroup);
}
throw new IOException("Impossible model:" + model);
}
public static String generateClassModelTypescriptLink(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
if (dotFieldModel.nativeType == DefinedPosition.NORMAL) {
return dotFieldModel.dotTypeName;
}
} else if (model instanceof final ClassListModel fieldListModel) {
final String className = generateDotListClassName(fieldListModel, dotGroup);
if (className != null) {
return className;
}
} else if (model instanceof final ClassMapModel fieldMapModel) {
final String className = generateDotMapClassName(fieldMapModel, dotGroup);
if (className != null) {
return className;
}
}
return null;
}
public String generateObject(final ClassObjectModel model, final DotClassElementGroup dotGroup) throws IOException {
final StringBuilder out = new StringBuilder();
final StringBuilder outLinks = new StringBuilder();
@ -235,58 +275,29 @@ public class DotClassElement {
out.append("\"><b> + ");
out.append(field.name());
out.append("</b>: ");
if (fieldModel instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(fieldModel);
out.append(dotFieldModel.dotTypeName);
out.append(generateClassModelTypescript(fieldModel, dotGroup));
final String remoteType = generateClassModelTypescriptLink(fieldModel, dotGroup);
if (remoteType != null) {
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(dotFieldModel.dotTypeName);
outLinks.append(remoteType);
outLinks.append(":NAME:w\n");
} else if (fieldModel instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(fieldModel);
out.append(dotFieldModel.dotTypeName);
if (dotFieldModel.nativeType == DefinedPosition.NORMAL) {
} else if (field.linkClass() != null) {
final String remoteLinkType = generateClassModelTypescriptLink(field.linkClass(), dotGroup);
if (remoteLinkType != null) {
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(dotFieldModel.dotTypeName);
outLinks.append(remoteLinkType);
outLinks.append(":NAME:w\n");
}
} else if (fieldModel instanceof final ClassListModel fieldListModel) {
final String data = generateDotList(fieldListModel, dotGroup);
out.append(data);
final String className = generateDotListClassName(fieldListModel, dotGroup);
if (className != null) {
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(className);
outLinks.append(":NAME:w\n");
}
} else if (fieldModel instanceof final ClassMapModel fieldMapModel) {
final String data = generateDotMap(fieldMapModel, dotGroup);
out.append(data);
final String className = generateDotMapClassName(fieldMapModel, dotGroup);
if (className != null) {
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(className);
outLinks.append(":NAME:w\n");
}
} /*
out.append(maxSizeZod(field));
out.append(readOnlyZod(field));
out.append(optionalTypeZod(field));
out.append(",\n");
*/
}
out.append("</td></tr>\n");
}
out.append("""
@ -310,10 +321,10 @@ public class DotClassElement {
out.append("\tedge [dir=back arrowtail=diamond arrowsize=2]\n");
//out.append("\tedge [arrowhead=diamond arrowsize=2]\n");
out.append(outLinks.toString());
}
return out.toString();
}
private static String generateDotMap(final ClassMapModel model, final DotClassElementGroup dotGroup) {
@ -349,12 +360,12 @@ public class DotClassElement {
out.append("&gt;");
return out.toString();
}
private static String generateDotEnum(final ClassEnumModel model, final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
return dotParentModel.dotTypeName;
}
private static String generateDotObject(final ClassObjectModel model, final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
return dotParentModel.dotTypeName;
@ -369,7 +380,7 @@ public class DotClassElement {
}
return null;
}
private static String generateDotListClassName(final ClassListModel model, final DotClassElementGroup dotGroup) {
if (model.valueModel instanceof final ClassListModel fieldListModel) {
return generateDotListClassName(fieldListModel, dotGroup);
@ -380,7 +391,7 @@ public class DotClassElement {
}
return null;
}
private static String generateDotMapClassName(final ClassMapModel model, final DotClassElementGroup dotGroup) {
if (model.valueModel instanceof final ClassListModel fieldListModel) {
return generateDotListClassName(fieldListModel, dotGroup);
@ -410,7 +421,7 @@ public class DotClassElement {
out.append("&gt;");
return out.toString();
}
public String generateFile(final DotClassElementGroup dotGroup) throws IOException {
if (this.nativeType == DefinedPosition.NATIVE) {
return "";
@ -426,7 +437,7 @@ public class DotClassElement {
}
return data;
}
private static String generateLocalModelBase(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
@ -443,7 +454,7 @@ public class DotClassElement {
}
return "";
}
public static String generateLocalModel(
final String ModelName,
final List<ClassModel> models,
@ -470,5 +481,5 @@ public class DotClassElement {
}
return out.toString();
}
}

View File

@ -6,15 +6,15 @@ import org.kar.archidata.externalRestApi.model.ClassModel;
public class DotClassElementGroup {
private final List<DotClassElement> dotElements;
public List<DotClassElement> getDotElements() {
return this.dotElements;
}
public DotClassElementGroup(final List<DotClassElement> tsElements) {
this.dotElements = tsElements;
}
public DotClassElement find(final ClassModel model) {
for (final DotClassElement elem : this.dotElements) {
if (elem.isCompatible(model)) {
@ -23,5 +23,5 @@ public class DotClassElementGroup {
}
return null;
}
}

View File

@ -15,6 +15,9 @@ import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.validation.constraints.Size;
public class ClassObjectModel extends ClassModel {
@ -56,6 +59,7 @@ public class ClassObjectModel extends ClassModel {
public record FieldProperty(
String name,
ClassModel model,
ClassModel linkClass, // link class when use remote ID (ex: list<UUID>)
String comment,
int sizeMin, // String SizeMin
int sizeMax, // String SizeMax
@ -66,11 +70,12 @@ public class ClassObjectModel extends ClassModel {
Boolean columnNotNull,
Boolean nullable) {
public FieldProperty(final String name, final ClassModel model, final String comment, final int sizeMin,
final int sizeMax, final Long min, final Long max, final Boolean readOnly, final Boolean notNull,
final Boolean columnNotNull, final Boolean nullable) {
public FieldProperty(final String name, final ClassModel model, final ClassModel linkClass,
final String comment, final int sizeMin, final int sizeMax, final Long min, final Long max,
final Boolean readOnly, final Boolean notNull, final Boolean columnNotNull, final Boolean nullable) {
this.name = name;
this.model = model;
this.linkClass = linkClass;
this.comment = comment;
this.sizeMin = sizeMin;
this.sizeMax = sizeMax;
@ -85,7 +90,6 @@ public class ClassObjectModel extends ClassModel {
private static int getStringMinSize(final Field field) throws DataAccessException {
final Size size = AnnotationTools.getConstraintsSize(field);
final int colomnLimitSize = AnnotationTools.getLimitSize(field);
return size != null ? size.min() : 0;
}
@ -95,9 +99,43 @@ public class ClassObjectModel extends ClassModel {
return size == null ? colomnLimitSize : colomnLimitSize < size.max() ? colomnLimitSize : size.max();
}
private static Class<?> getSubModelIfExist2(final Field field) {
final ManyToOne manyToOne = AnnotationTools.getManyToOne(field);
if (manyToOne != null) {
if (manyToOne.targetEntity() != null && manyToOne.targetEntity() != void.class) {
return manyToOne.targetEntity();
}
return null;
}
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
if (manyToMany != null) {
if (manyToMany.targetEntity() != null && manyToMany.targetEntity() != void.class) {
return manyToMany.targetEntity();
}
return null;
}
final OneToMany oneToMany = AnnotationTools.getOneToMany(field);
if (oneToMany != null) {
if (oneToMany.targetEntity() != null && oneToMany.targetEntity() != void.class) {
return oneToMany.targetEntity();
}
return null;
}
return null;
}
private static ClassModel getSubModelIfExist(final Field field, final ModelGroup previous) throws IOException {
final Class<?> tmp = getSubModelIfExist2(field);
if (tmp == null) {
return null;
}
return ClassModel.getModel(tmp, previous);
}
public FieldProperty(final Field field, final ModelGroup previous) throws DataAccessException, IOException {
this(field.getName(), //
ClassModel.getModel(field.getGenericType(), previous), //
getSubModelIfExist(field, previous), //
AnnotationTools.getComment(field), //
getStringMinSize(field), //
getStringMaxSize(field), //