fr.ird.observe.toolkit.eugene.templates.dto.DtoDefinitionTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eugene-templates Show documentation
Show all versions of eugene-templates Show documentation
ObServe Eugene templates module
The newest version!
/*-
* #%L
* ObServe Toolkit :: Eugene Templates
* %%
* Copyright (C) 2008 - 2017 IRD, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
package fr.ird.observe.toolkit.eugene.templates.dto;
import fr.ird.observe.binder.DtoReferenceBinder;
import fr.ird.observe.binder.data.DataDtoReferenceBinder;
import fr.ird.observe.binder.referential.ReferentialDtoReferenceBinder;
import fr.ird.observe.dto.IdHelper;
import fr.ird.observe.dto.form.FormDefinition;
import fr.ird.observe.dto.reference.DataDtoReferenceDefinition;
import fr.ird.observe.dto.reference.ReferentialDtoReferenceDefinition;
import fr.ird.observe.spi.dto.DataDtoDefinition;
import fr.ird.observe.spi.dto.DataDtoWithNoReferenceDefinition;
import fr.ird.observe.spi.dto.DtoModuleHelper;
import fr.ird.observe.spi.dto.ReferentialDtoDefinition;
import fr.ird.observe.toolkit.eugene.templates.DtoHelper;
import fr.ird.observe.toolkit.eugene.templates.DtoModel;
import fr.ird.observe.toolkit.eugene.templates.DtoTransformerContext;
import fr.ird.observe.toolkit.eugene.templates.ToolkitTagValues;
import org.nuiton.eugene.EugeneCoreTagValues;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.java.BeanTransformerTagValues;
import org.nuiton.eugene.java.EugeneJavaTagValues;
import org.nuiton.eugene.java.JavaGeneratorUtil;
import org.nuiton.eugene.java.ObjectModelTransformerToJava;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelClassifier;
import org.nuiton.eugene.models.object.ObjectModelJavaModifier;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.eugene.models.object.ObjectModelPackage;
import org.nuiton.i18n.spi.GetterFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author Tony Chemit - [email protected]
* @plexus.component role="org.nuiton.eugene.Template" role-hint="fr.ird.observe.toolkit.eugene.templates.dto.DtoDefinitionTransformer"
* @since 3.0
*/
public class DtoDefinitionTransformer extends ObjectModelTransformerToJava {
private DtoModel dtoModel;
private GetterFile i18nGetterFile;
@Override
public void transformFromModel(ObjectModel model) {
super.transformFromModel(model);
i18nGetterFile = getConfiguration().getProperty(PROP_I18N_GETTER_FILE, GetterFile.class);
dtoModel = new DtoModel(
new EugeneCoreTagValues(),
new EugeneJavaTagValues(),
new BeanTransformerTagValues(),
new ToolkitTagValues(),
getLog(),
model,
getDefaultPackageName());
DtoTransformerContext context = dtoModel.context;
context.report();
List referentialDefinitionClasses = new LinkedList<>();
List dataDefinitionClasses = new LinkedList<>();
List dataWithoutReferenceDefinitionClasses = new LinkedList<>();
for (ObjectModelClass input : context.selectedClasses) {
ObjectModelPackage aPackage = getPackage(input);
if (EugeneCoreTagValues.isSkip(input, aPackage) || input.isAbstract()) {
continue;
}
if (IdHelper.isReferentialFromPackageName(input.getPackageName())) {
referentialDefinitionClasses.add(input);
} else {
String referencesTagValue = dtoModel.toolkitTagValues.getReferencesTagValue(input);
boolean withoutReference = referencesTagValue == null;
if (withoutReference) {
dataWithoutReferenceDefinitionClasses.add(input);
} else {
dataDefinitionClasses.add(input);
}
}
}
getLog().info(String.format("Found %d referential dto.", referentialDefinitionClasses.size()));
for (ObjectModelClass input : referentialDefinitionClasses) {
generateReferentialDtoDefinitionClass(context, input);
}
getLog().info(String.format("Found %d data dto.", dataDefinitionClasses.size()));
for (ObjectModelClass input : dataDefinitionClasses) {
generateDataDtoDefinitionClass(context, input);
}
getLog().info(String.format("Found %d data (without reference) dto.", dataWithoutReferenceDefinitionClasses.size()));
for (ObjectModelClass input : dataWithoutReferenceDefinitionClasses) {
generateDataDtoWithoutReferenceDefinitionClass(context, input);
}
Function function = i -> i.getQualifiedName() + "DtoDefinition";
storeServiceLoaderFile(DataDtoDefinition.class, dataDefinitionClasses, function);
storeServiceLoaderFile(DataDtoWithNoReferenceDefinition.class, dataWithoutReferenceDefinitionClasses, function);
storeServiceLoaderFile(ReferentialDtoDefinition.class, referentialDefinitionClasses, function);
}
private void generateDataDtoDefinitionClass(DtoTransformerContext context, ObjectModelClass input) {
String prefix = getConstantPrefix(input);
setConstantPrefix(prefix);
String dtoType = input.getPackageName() + "." + input.getName() + "Dto";
String dtoTypeSimpleName = GeneratorUtil.getSimpleName(dtoType);
i18nGetterFile.addKey("observe.common." + dtoTypeSimpleName + ".type");
i18nGetterFile.addKey("observe.common." + dtoTypeSimpleName + ".types");
String referenceType = dtoType.replace("Dto", "Reference");
String referenceTypeSimpleName = GeneratorUtil.getSimpleName(referenceType);
List properties = getAllProperties(input);
String referencesTagValue = dtoModel.toolkitTagValues.getReferencesTagValue(input);
String superClass = String.format("%s<%s, %s>", DataDtoDefinition.class.getName(), dtoType, referenceType);
String className = input.getName() + "DtoDefinition";
ObjectModelClass output = createClass(className, input.getPackageName());
setSuperClass(output, superClass);
getLog().debug("will generate " + output.getQualifiedName());
addInstance(output, DataDtoDefinition.class.getSimpleName(), dtoTypeSimpleName, "fromDataDto");
int selectedPriority = dtoModel.toolkitTagValues.getSelectedTagValue(input);
int openPriority = dtoModel.toolkitTagValues.getOpenTagValue(input);
String parentDtoType;
if (selectedPriority > 0) {
String selectedParentTagValue = dtoModel.toolkitTagValues.getSelectedParentTagValue(input);
Objects.requireNonNull(selectedParentTagValue, "Can't find a parent for a selected data " + input.getQualifiedName());
parentDtoType = JavaGeneratorUtil.getSimpleName(selectedParentTagValue) + ".class";
addImport(output, selectedParentTagValue);
} else {
parentDtoType = "null";
}
ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PUBLIC);
String referenceParam = referenceTypeSimpleName + ".class";
setOperationBody(constructor, ""+"\n"
+" super("+parentDtoType+", "+dtoTypeSimpleName+".class, "+referenceParam+", "+selectedPriority+", "+openPriority+");\n"
+" ");
addComputeDtoGettersMethod(output, dtoTypeSimpleName, properties);
addComputeDtoSettersMethod(output, dtoTypeSimpleName, properties);
Set availableReferenceProperties = new LinkedHashSet<>(Arrays.asList(referencesTagValue.split(",")));
Set referenceProperties = DtoHelper.getReferenceProperties(context, input, availableReferenceProperties);
addComputeReferenceGettersMethod(output, referenceTypeSimpleName, referenceProperties);
addComputeReferenceBinder(output, dtoType, referenceType, false);
addComputeReferenceDefinition(output, dtoType, referenceTypeSimpleName, referenceProperties, false);
addComputeFormDefinition(input, output, dtoTypeSimpleName, referenceTypeSimpleName, false);
}
private void generateDataDtoWithoutReferenceDefinitionClass(DtoTransformerContext context, ObjectModelClass input) {
String prefix = getConstantPrefix(input);
setConstantPrefix(prefix);
String dtoType = input.getPackageName() + "." + input.getName() + "Dto";
String dtoTypeSimpleName = GeneratorUtil.getSimpleName(dtoType);
String referenceType = dtoType.replace("Dto", "Reference");
String referenceTypeSimpleName = GeneratorUtil.getSimpleName(referenceType);
List properties = getAllProperties(input);
String superClass = String.format("%s<%s>", DataDtoWithNoReferenceDefinition.class.getName(), dtoType);
String className = input.getName() + "DtoDefinition";
ObjectModelClass output = createClass(className, input.getPackageName());
setSuperClass(output, superClass);
addImport(output, DtoModuleHelper.class);
getLog().debug("will generate " + output.getQualifiedName());
addInstance(output, DataDtoWithNoReferenceDefinition.class.getSimpleName(), dtoTypeSimpleName, "fromDataDtoWithoutReference");
ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PUBLIC);
setOperationBody(constructor, ""+"\n"
+" super("+dtoTypeSimpleName+".class);\n"
+" ");
addComputeDtoGettersMethod(output, dtoTypeSimpleName, properties);
addComputeDtoSettersMethod(output, dtoTypeSimpleName, properties);
addComputeFormDefinition(input, output, dtoTypeSimpleName, referenceTypeSimpleName, false);
}
private void generateReferentialDtoDefinitionClass(DtoTransformerContext context, ObjectModelClass input) {
String prefix = getConstantPrefix(input);
setConstantPrefix(prefix);
String dtoType = input.getPackageName() + "." + input.getName() + "Dto";
String dtoTypeSimpleName = GeneratorUtil.getSimpleName(dtoType);
i18nGetterFile.addKey("observe.common." + dtoTypeSimpleName + ".type");
i18nGetterFile.addKey("observe.common." + dtoTypeSimpleName + ".types");
String referenceType = dtoType.replace("Dto", "Reference");
String referenceTypeSimpleName = GeneratorUtil.getSimpleName(referenceType);
List properties = getAllProperties(input);
String referencesTagValue = dtoModel.toolkitTagValues.getReferencesTagValue(input);
if (referencesTagValue == null) {
referencesTagValue = "code,label";
}
String superClass = String.format("%s<%s, %s>", ReferentialDtoDefinition.class.getName(), dtoType, referenceType);
String className = input.getName() + "DtoDefinition";
ObjectModelClass output = createClass(className, input.getPackageName());
setSuperClass(output, superClass);
getLog().debug("will generate " + output.getQualifiedName());
addInstance(output, ReferentialDtoDefinition.class.getSimpleName(), dtoTypeSimpleName, "fromReferentialDto");
int selectedPriority = dtoModel.toolkitTagValues.getSelectedTagValue(input);
int openPriority = dtoModel.toolkitTagValues.getOpenTagValue(input);
ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PUBLIC);
String referenceParam = referenceTypeSimpleName + ".class";
setOperationBody(constructor, ""+"\n"
+" super(null, "+dtoTypeSimpleName+".class, "+referenceParam+", "+selectedPriority+", "+openPriority+");\n"
+" ");
addComputeDtoGettersMethod(output, dtoTypeSimpleName, properties);
addComputeDtoSettersMethod(output, dtoTypeSimpleName, properties);
Set referenceProperties;
Set availableReferenceProperties = new LinkedHashSet<>(Arrays.asList(referencesTagValue.split(",")));
referenceProperties = DtoHelper.getReferenceProperties(context, input, availableReferenceProperties);
addComputeReferenceGettersMethod(output, referenceTypeSimpleName, referenceProperties);
addComputeReferenceBinder(output, dtoType, referenceType, true);
addComputeReferenceDefinition(output, dtoType, referenceTypeSimpleName, referenceProperties, true);
addComputeFormDefinition(input, output, dtoTypeSimpleName, referenceTypeSimpleName, true);
}
private void addInstance(ObjectModelClass output, String type, String dtoTypeSimpleName, String method) {
addImport(output, DtoModuleHelper.class);
addAttribute(output, "INSTANCE", output.getName(), null, ObjectModelJavaModifier.PRIVATE, ObjectModelJavaModifier.STATIC);
ObjectModelOperation get = addOperation(output, "get", output.getName(), ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC, ObjectModelJavaModifier.FINAL);
setOperationBody(get, ""+"\n"
+" if (INSTANCE == null) {\n"
+" "+type+" context = DtoModuleHelper."+method+"("+dtoTypeSimpleName+".class);\n"
+" INSTANCE = ("+output.getName()+") context;\n"
+" }\n"
+" return INSTANCE;\n"
+" ");
}
private void addComputeDtoGettersMethod(ObjectModelClass output, String dtoType, List properties) {
ObjectModelOperation computeDtoGetters = addOperation(output, "computeDtoGetters", getGettersMapType(dtoType), ObjectModelJavaModifier.PROTECTED, ObjectModelJavaModifier.FINAL);
addAnnotation(output, computeDtoGetters, Override.class);
String dtoGettersMapCode = generateGettersMap(output, dtoType, properties);
setOperationBody(computeDtoGetters, ""+"\n"
+" return "+dtoGettersMapCode+";\n"
+" ");
}
private void addComputeDtoSettersMethod(ObjectModelClass output, String dtoType, List properties) {
ObjectModelOperation computeDtoSetters = addOperation(output, "computeDtoSetters", getSettersMapType(dtoType), ObjectModelJavaModifier.PROTECTED, ObjectModelJavaModifier.FINAL);
addAnnotation(output, computeDtoSetters, Override.class);
String dtoSettersMapCode = generateSettersMap(output, dtoType, properties, e -> getPropertyType(output, e));
setOperationBody(computeDtoSetters, ""+"\n"
+" return "+dtoSettersMapCode+";\n"
+" ");
}
private void addComputeFormDefinition(ObjectModelClass input, ObjectModelClass output, String dtoType, String referenceType, boolean referential) {
String formTagValue = null;
boolean withForm = dtoModel.formContext.selectedClasses.contains(input);
if (withForm) {
formTagValue = dtoModel.toolkitTagValues.getFormTagValue(input, getPackage(input.getPackageName())).trim();
}
StringBuilder bodyBuilder = new StringBuilder();
if (formTagValue != null) {
Map properties;
boolean mainForm = formTagValue.equals("self");
boolean withProperties;
if (referential || mainForm) {
properties = DtoHelper.getFormProperties(input);
getLog().debug(String.format("form: %s, found %d properties.", dtoType, properties.size()));
withProperties = !properties.isEmpty();
if (referential || withProperties) {
if (referential) {
bodyBuilder.append(""+"\n"
+" return () -> FormDefinition.referentialBuilder("+dtoType+".class, "+referenceType+".class)");
} else {
bodyBuilder.append(""+"\n"
+" return () -> FormDefinition.builder("+dtoType+".class)");
i18nGetterFile.addKey("observe.common." + dtoType + ".title");
}
for (Map.Entry entry : properties.entrySet()) {
String propertyName = entry.getKey();
String type = entry.getValue();
propertyName = JavaGeneratorUtil.convertVariableNameToConstantName("property" + JavaGeneratorUtil.capitalizeJavaBeanPropertyName(propertyName));
bodyBuilder.append(""+"\n"
+" .addProperty("+dtoType+"."+propertyName+", "+type+".class)");
}
bodyBuilder.append(""+"\n"
+" .build();\n"
+" ");
}
}
}
if (bodyBuilder.length() == 0) {
bodyBuilder.append(""+"\n"
+" return () -> null;\n"
+" ");
}
String methodType = "Supplier>";
addImport(output, Supplier.class);
addImport(output, FormDefinition.class);
ObjectModelOperation computeFormDefinition = addOperation(output, "computeFormDefinition", methodType, ObjectModelJavaModifier.PROTECTED, ObjectModelJavaModifier.FINAL);
addAnnotation(output, computeFormDefinition, Override.class);
setOperationBody(computeFormDefinition, bodyBuilder.toString());
}
private void addComputeReferenceBinder(ObjectModelClass output, String dtoType, String referenceType, boolean referential) {
String binderPackageName = DtoReferenceBinder.class.getPackage().getName();
String binderFieldType = referenceType == null ? (referential ? ReferentialDtoReferenceBinder.class.getName() : DataDtoReferenceBinder.class.getName()) : DtoHelper.generateBinderName(dtoModel.context.defaultPackage.getName().length(), binderPackageName, dtoType, GeneratorUtil.getSimpleName(dtoType) + "Reference", referential);
addImport(output, binderFieldType);
binderFieldType = JavaGeneratorUtil.getSimpleName(binderFieldType);
ObjectModelOperation computeReferenceBinder = addOperation(output, "computeReferenceBinder", binderFieldType, ObjectModelJavaModifier.PROTECTED, ObjectModelJavaModifier.FINAL);
addAnnotation(output, computeReferenceBinder, Override.class);
String binderInstance = referenceType == null ? "null" : "new " + binderFieldType + "()";
setOperationBody(computeReferenceBinder, ""+"\n"
+" return "+binderInstance+";\n"
+" ");
if (referenceType != null) {
ObjectModelOperation getReferenceBinder = addOperation(output, "toReferenceBinder", binderFieldType, ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.FINAL);
addAnnotation(output, getReferenceBinder, Override.class);
setOperationBody(getReferenceBinder, ""+"\n"
+" return ("+binderFieldType+") super.toReferenceBinder();\n"
+" ");
}
}
private void addComputeReferenceDefinition(ObjectModelClass output, String dtoType, String referenceType, Set referenceProperties, boolean referential) {
Class builderMethodName = referential ? ReferentialDtoReferenceDefinition.class : DataDtoReferenceDefinition.class;
addImport(output, builderMethodName);
StringBuilder definition;
if (referenceType == null) {
definition = new StringBuilder("" +"\n"
+" return null;\n"
+" "
);
} else {
definition = new StringBuilder("" +"\n"
+" return "+builderMethodName.getSimpleName()+"\n"
+" .builder("+dtoType+".class, "+referenceType+".class)"
);
for (ObjectModelAttribute attr : referenceProperties) {
addImport(output, attr.getType());
String type = JavaGeneratorUtil.getSimpleName(attr.getType());
String name = attr.getName();
String getterName;
boolean booleanProperty = JavaGeneratorUtil.isBooleanPrimitive(attr);
if (booleanProperty) {
getterName = JavaGeneratorUtil.OPERATION_GETTER_BOOLEAN_PREFIX;
} else {
getterName = JavaGeneratorUtil.OPERATION_GETTER_DEFAULT_PREFIX;
}
getterName += JavaGeneratorUtil.capitalizeJavaBeanPropertyName(name);
name = JavaGeneratorUtil.convertVariableNameToConstantName("property" + JavaGeneratorUtil.capitalizeJavaBeanPropertyName(name));
definition.append("" +"\n"
+" .addProperty("+type+".class, "+referenceType+"."+name+", "+referenceType+"::"+getterName+")"
);
}
definition.append(""+"\n"
+" .build();"
);
}
String definitionType = builderMethodName.getName();
if (referenceType != null) {
definitionType = String.format("%s<%s, %s>", definitionType, dtoType, referenceType);
}
ObjectModelOperation computeReferenceDefinition = addOperation(output, "computeReferenceDefinition", definitionType, ObjectModelJavaModifier.FINAL, ObjectModelJavaModifier.PROTECTED);
addAnnotation(output, computeReferenceDefinition, Override.class);
setOperationBody(computeReferenceDefinition, definition.toString());
}
private void addComputeReferenceGettersMethod(ObjectModelClass output, String referenceType, Set referenceProperties) {
String methodType = referenceType == null ? "ImmutableMap>" : getGettersMapType(referenceType);
ObjectModelOperation computeReferenceGetters = addOperation(output, "computeReferenceGetters", methodType, ObjectModelJavaModifier.PROTECTED, ObjectModelJavaModifier.FINAL);
addAnnotation(output, computeReferenceGetters, Override.class);
String referenceGettersMapCode = referenceType == null ? "null" : generateGettersMap(output, referenceType, referenceProperties);
setOperationBody(computeReferenceGetters, ""+"\n"
+" return "+referenceGettersMapCode+";\n"
+" ");
}
private List getAllProperties(ObjectModelClass input) {
List attributes =
(List) input.getAllOtherAttributes();
List result = new ArrayList<>();
for (ObjectModelAttribute attr : attributes) {
if (attr.isNavigable()) {
// only keep navigable attributes
result.add(attr);
}
}
result.addAll(getProperties(input));
return result;
}
private String getAttributeTypeWithGeneric(ObjectModelAttribute attr) {
String attrType = dtoModel.context.getAttributeType(attr);
String generic = eugeneTagValues.getAttributeGenericTagValue(attr);
if (generic != null) {
attrType += String.format("<%s>", dtoModel.context.getAttributeType(generic));
}
return attrType;
}
private List getProperties(ObjectModelClass input) {
List attributes =
(List) input.getAttributes();
List attrs =
new ArrayList<>();
for (ObjectModelAttribute attr : attributes) {
if (attr.isNavigable()) {
// only keep navigable attributes
attrs.add(attr);
}
}
return attrs;
}
private String getPropertyType(ObjectModelClass output, ObjectModelAttribute attr) {
boolean multiple = JavaGeneratorUtil.isNMultiplicity(attr);
String attrType = getAttributeTypeWithGeneric(attr);
if (multiple) {
attrType = JavaGeneratorUtil.getAttributeInterfaceType(attr, getAttributeTypeWithGeneric(attr), true);
}
addImport(output, attrType);
return JavaGeneratorUtil.getSimpleName(attrType);
}
}