Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.knightsoftnet.gwtp.spring.annotation.processor.AbstractBackofficeCreator Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package de.knightsoftnet.gwtp.spring.annotation.processor;
import de.knightsoftnet.validators.annotation.processor.TypeUtils;
import de.knightsoftnet.validators.shared.data.FieldTypeEnum;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.FilerException;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
/**
* Create class or interface.
*/
public abstract class AbstractBackofficeCreator {
protected static final String JAVAX_VALIDATION_PATH = "javax.validation.constraints.";
protected static final String JAKARTA_VALIDATION_PATH = "jakarta.validation.constraints.";
protected static final String MT_VALIDATION_PATH = "de.knightsoftnet.validators.shared.";
protected static final String WIDGET_PATH = "de.knightsoftnet.mtwidgets.client.ui.widget.";
protected static final String CLASS_SUFFIX_VIEW = "View";
private final List imports;
protected final String suffix;
protected AbstractBackofficeCreator(final String suffix) {
super();
imports = new ArrayList<>();
this.suffix = suffix;
}
public String getSuffix() {
return suffix;
}
/**
* write class or interface.
*
* @param element the element which represents the entity
* @param annotationInterface annotation interface
* @param processingEnv processing environment
*/
public void writeClassOrInterface(final Element element, final T annotationInterface,
final ProcessingEnvironment processingEnv) {
try {
final String serverPackage = detectPackage(element, processingEnv);
final String entityType = getEntityNameOfElement(element);
final JavaFileObject builderFile =
processingEnv.getFiler().createSourceFile(serverPackage + "." + entityType + suffix);
try (PrintWriter out = new PrintWriter(builderFile.openWriter())) {
out.print("package ");
out.print(serverPackage);
out.println(";");
out.println();
addAdditionalImports(serverPackage, element, annotationInterface, processingEnv);
writeImports(imports, out, serverPackage);
out.println();
writeBody(out, serverPackage, element, annotationInterface, processingEnv);
}
} catch (final FilerException e) {
// happens when trying to recreate an existing interface
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, e.getMessage());
} catch (final IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
e.printStackTrace();
}
}
protected String getPackageOfElement(final Element element) {
final String entityName = element.asType().toString();
final int packagePos = entityName.lastIndexOf('.');
return entityName.substring(0, packagePos);
}
protected String getEntityNameOfElement(final Element element) {
final String entityName = element.asType().toString();
final int packagePos = entityName.lastIndexOf('.');
return entityName.substring(packagePos + 1);
}
protected String getEntityNameOfElementLower(final Element element) {
final String entityName = element.asType().toString();
final int packagePos = entityName.lastIndexOf('.');
return entityName.substring(packagePos + 1, packagePos + 2).toLowerCase()
+ entityName.substring(packagePos + 2);
}
protected DeclaredType getDeclaredTypeOfFirstTypeElement(final DeclaredType type) {
return (DeclaredType) type.getTypeArguments().get(0);
}
protected DeclaredType getDeclaredTypeOfFirstTypeElement(final Element element) {
return getDeclaredTypeOfFirstTypeElement((DeclaredType) element.asType());
}
protected String getEntityNameOfFirstTypeElement(final Element element) {
final String entityName = getDeclaredTypeOfFirstTypeElement(element).toString();
final int packagePos = entityName.lastIndexOf('.');
return entityName.substring(packagePos + 1);
}
protected String getEntityNameOfFirstTypeElementLower(final Element element) {
final String entityName = getDeclaredTypeOfFirstTypeElement(element).toString();
final int packagePos = entityName.lastIndexOf('.');
return entityName.substring(packagePos + 1, packagePos + 2).toLowerCase()
+ entityName.substring(packagePos + 2);
}
/**
* add import line.
*
* @param classWithPaths class including pass to import
*/
protected void addImports(final String... classWithPaths) {
Stream.of(classWithPaths).forEach(this::addImport);
}
/**
* add import line.
*
* @param typeMirrors class including pass to import
*/
protected void addImports(final TypeMirror... typeMirrors) {
Stream.of(typeMirrors).forEach(this::addImport);
}
/**
* add import line.
*
* @param classWithPath class including pass to import
*/
protected void addImport(final String classWithPath) {
imports.add(classWithPath);
}
/**
* add import line.
*
* @param typeMirror type mirror of the class to add
*/
protected void addImport(final TypeMirror typeMirror) {
addImport(typeMirror.toString());
}
/**
* write import lines.
*
* @param imports list of imports
* @param out print writer
* @param classPath path of the class (or interface) to crate
*/
protected void writeImports(final List imports, final PrintWriter out,
final String classPath) {
String lastPrefix = firstTwoPartsOfPath(classPath);
String lastImport = StringUtils.EMPTY;
imports.sort(new ImportComparator(lastPrefix));
for (final String importValue : imports) {
if (!StringUtils.equals(importValue, lastImport)) {
lastImport = importValue;
if (!importValue.startsWith(lastPrefix)) {
out.println();
lastPrefix = firstPartOfPath(importValue);
}
out.print("import ");
out.print(importValue);
out.println(";");
}
}
}
protected String firstPartOfPath(final String classPath) {
final int pos1 = classPath.indexOf('.');
return classPath.substring(0, pos1);
}
protected String firstTwoPartsOfPath(final String classPath) {
final int pos1 = classPath.indexOf('.');
final int pos2 = classPath.indexOf('.', pos1 + 1);
return classPath.substring(0, pos2);
}
protected List getFields(final Element element) {
return TypeUtils.getFields(element.asType()).stream().sorted((o1, o2) -> {
// sort id on top, keep the rest unchanged
if ("id".equals(o1.getSimpleName().toString())) {
return "id".equals(o2.getSimpleName().toString()) ? 0 : -1;
}
return 0;
}).collect(Collectors.toList());
}
protected boolean hasEnum(final Element element) {
return getFields(element).stream().map(Element::asType).anyMatch(this::isEnum);
}
protected boolean isEnum(final TypeMirror typeMirror) {
return StringUtils.isNoneEmpty(getEnumName(typeMirror));
}
protected String getEnumName(final TypeMirror typeMirror) {
if ("java.lang.Enum".equals(TypeUtils.getClassName(typeMirror))) {
return TypeUtils.getClassName(getDeclaredTypeOfFirstTypeElement((DeclaredType) typeMirror));
}
if (typeMirror.getKind() == TypeKind.DECLARED) {
final TypeMirror superclass =
((TypeElement) ((DeclaredType) typeMirror).asElement()).getSuperclass();
if (superclass != null) {
return getEnumName(superclass);
}
}
return null;
}
protected String getEnumNameWithoutPackage(final TypeMirror typeMirror) {
final String[] splittedName = StringUtils.split(getEnumName(typeMirror), '.');
return splittedName[splittedName.length - 1];
}
/**
* read all values of a enumeration.
*
* @param enumTypeElement type element of the enumeration
* @return list of values
*/
protected List getEnumValues(final TypeElement enumTypeElement) {
return enumTypeElement.getEnclosedElements().stream()
.filter(element -> element.getKind().equals(ElementKind.ENUM_CONSTANT))
.map(Object::toString).collect(Collectors.toList());
}
/**
* map given field to FieldTypeEnum.
*
* @param field the field to detect
* @param elementType declared type of the structure
* @param processingEnv progressing environment
* @return the detected field type enum
*/
protected FieldTypeEnum mapElementToSearchType(final Element field,
final DeclaredType elementType, final ProcessingEnvironment processingEnv) {
return detectBackofficeWidgetOfField("", null, field, elementType, processingEnv, true)
.getFieldType();
}
private boolean isEmbedded(final TypeMirror fieldType) {
if (fieldType.getKind() == TypeKind.DECLARED) {
return ((DeclaredType) fieldType).asElement().getAnnotationMirrors().stream()
.anyMatch(annotation -> StringUtils.equals(annotation.getAnnotationType().toString(),
"jakarta.persistence.Embeddable")
|| StringUtils.equals(annotation.getAnnotationType().toString(),
"javax.persistence.Embeddable"));
}
return false;
}
/**
* detect the matching widgets for given element as flat list.
*
* @param element the element to detect field widgets from
* @param processingEnv progressing environment
* @return List of BackofficeWidgets
*/
protected List detectBackofficeWidgetsOfElementFlat(final Element element,
final ProcessingEnvironment processingEnv) {
return detectBackofficeWidgetsOfElement("", null, element, processingEnv, true).stream()
.flatMap(BackofficeWidget::streamFlatBackofficeWidget).filter(
entry -> !entry.isIgnore() && !StringUtils.endsWith(entry.getName(), ".id")
).collect(Collectors.toList());
}
/**
* detect the matching widgets for given element.
*
* @param prefix field prefix
* @param parentWidget parent widget or null
* @param element the element to detect field widgets from
* @param processingEnv progressing environment
* @param writeDebugId write debug id for widget
* @return List of BackofficeWidgets
*/
protected List detectBackofficeWidgetsOfElement(final String prefix,
final BackofficeWidget parentWidget, final Element element,
final ProcessingEnvironment processingEnv, final boolean writeDebugId) {
if (element.asType().getKind() == TypeKind.DECLARED) {
return getFields(element).stream().filter(
field -> !field.getModifiers().contains(Modifier.STATIC)
).map(field -> detectBackofficeWidgetOfField(prefix, parentWidget, field,
(DeclaredType) element.asType(), processingEnv, writeDebugId))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
/**
* detect the matching widget for given field.
*
* @param prefix field prefix
* @param parentWidget parent widget or null
* @param field the field to detect
* @param elementType declared type of the structure
* @param processingEnv progressing environment
* @param writeDebugId write debug id for widget
* @return BackofficeWidget
*/
protected BackofficeWidget detectBackofficeWidgetOfField(final String prefix,
final BackofficeWidget parentWidget, final Element field, final DeclaredType elementType,
final ProcessingEnvironment processingEnv, final boolean writeDebugId) {
final String fieldName = field.getSimpleName().toString();
final List imports = new ArrayList<>();
final String widgetName;
final List widgetParameter = new ArrayList<>();
final FieldTypeEnum fieldTypeEnum;
final List childWidgets = new ArrayList<>();
boolean provided = false;
String providedConstructor = StringUtils.EMPTY;
final TypeMirror fieldType = processingEnv.getTypeUtils().asMemberOf(elementType, field);
final List extends AnnotationMirror> annotations = field.getAnnotationMirrors();
final List annotationNames = annotations.stream()
.map(annotationMirror -> annotationMirror.getAnnotationType().toString())
.collect(Collectors.toList());
final boolean ignore = annotationNames.contains("com.fasterxml.jackson.annotation.JsonIgnore");
final Map additional = new HashMap<>();
if ("id".equals(fieldName)) {
widgetParameter.add(BackofficeWidgetParameter.of("enabled", "false", true));
}
switch (TypeUtils.getClassName(fieldType)) {
case "double":
case "java.lang.Double":
widgetName = "DecimalDoubleBox";
imports.add(WIDGET_PATH + widgetName);
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.NUMERIC;
break;
case "java.math.BigDecimal":
widgetName = "DecimalBigDecimalBox";
imports.add(WIDGET_PATH + widgetName);
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.NUMERIC;
break;
case "long":
case "java.lang.Long":
widgetName = "LongBox";
imports.add(WIDGET_PATH + widgetName);
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.NUMERIC;
break;
case "boolean":
case "java.lang.Boolean":
widgetName = "CheckBox";
imports.add(WIDGET_PATH + widgetName);
fieldTypeEnum = FieldTypeEnum.BOOLEAN;
break;
case "java.time.LocalDate":
widgetName = "DateBoxLocalDate";
imports.add(WIDGET_PATH + widgetName);
futurePastMinMaxCheck(imports, widgetParameter, annotationNames, "java.time.LocalDate",
"LocalDate", "minusDays(1L)", "plusDays(1L)");
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.DATE;
break;
case "java.util.Date":
widgetName = "DateTimeLocalBox";
imports.add(WIDGET_PATH + widgetName);
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.DATETIME;
break;
case "java.time.LocalDateTime":
widgetName = "DateTimeLocalBoxLocalDateTime";
imports.add(WIDGET_PATH + widgetName);
futurePastMinMaxCheck(imports, widgetParameter, annotationNames, "java.time.LocalDateTime",
"LocalDateTime", "minusMinutes(1L)", "plusMinutes(1L)");
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.DATETIME;
break;
case "java.time.LocalTime":
widgetName = "TimeBoxLocalTime";
imports.add(WIDGET_PATH + widgetName);
notNullRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.TIME;
break;
case "de.knightsoftnet.validators.shared.data.CountryEnum":
widgetName = "CountryListBox";
imports.add(WIDGET_PATH + widgetName);
notNullRequiredCheck(widgetParameter, annotationNames);
widgetParameter.add(BackofficeWidgetParameter.of("sort", "NAME_ASC", true));
fieldTypeEnum = FieldTypeEnum.ENUM_FIXED;
break;
case "de.knightsoftnet.gwtp.spring.shared.db.LocalizedEntity":
widgetName = "MultiLanguageTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.STRING_LOCALIZED;
break;
default:
final List extends AnnotationMirror> elementAnnotations =
elementType.asElement().getAnnotationMirrors();
if (isEnum(processingEnv.getTypeUtils().asMemberOf(elementType, field))) {
final List enumValues = getEnumValues((TypeElement) ((DeclaredType) processingEnv
.getTypeUtils().asMemberOf(elementType, field)).asElement());
if (enumValues.size() < 4 && writeDebugId) {
widgetName =
"SortableIdAndNameRadioButton<" + getEnumNameWithoutPackage(field.asType()) + ">";
imports.add(WIDGET_PATH + "SortableIdAndNameRadioButton");
providedConstructor = "new SortableIdAndNameRadioButton<"
+ getEnumNameWithoutPackage(field.asType()) + ">(\"" + fieldName + "\",\n" //
+ " Stream.of(" + getEnumNameWithoutPackage(field.asType()) + ".values())\n"
+ " .map(entry -> new IdAndNameBean<"
+ getEnumNameWithoutPackage(field.asType()) + ">(entry, " + "messages."
+ fieldNameToCamelCase(prefix + fieldName) + "(entry)))\n" //
+ " .collect(Collectors.toList()));";
} else {
widgetName = "IdAndNameListBox<" + getEnumNameWithoutPackage(field.asType()) + ">";
imports.add(WIDGET_PATH + "IdAndNameListBox");
providedConstructor =
"new IdAndNameListBox<" + getEnumNameWithoutPackage(field.asType()) + ">(Stream.of("
+ getEnumNameWithoutPackage(field.asType()) + ".values())\n" //
+ " .map(entry -> new IdAndNameBean<"
+ getEnumNameWithoutPackage(field.asType()) + ">(entry, " + "messages."
+ fieldNameToCamelCase(prefix + fieldName) + "(entry)))\n" //
+ " .collect(Collectors.toList()));";
}
provided = true;
imports.add(WIDGET_PATH + "helper.IdAndNameBean");
imports.add("java.util.stream.Collectors");
imports.add("java.util.stream.Stream");
imports.add(getEnumName(field.asType()));
fieldTypeEnum = FieldTypeEnum.ENUM_FIXED;
} else if (annotationNames.contains(MT_VALIDATION_PATH + "Email")
|| annotationNames.contains(JAVAX_VALIDATION_PATH + "Email")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "Email")) {
widgetName = "EmailTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (annotationNames.contains(MT_VALIDATION_PATH + "Bic")
|| annotationNames.contains(MT_VALIDATION_PATH + "BicValue")) {
widgetName = "BicSuggestBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (annotationNames.contains(MT_VALIDATION_PATH + "Iban")
|| annotationNames.contains(MT_VALIDATION_PATH + "IbanFormated")) {
widgetName = "IbanTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
if (matchesBankCountryIbanAnnotation(fieldName, elementAnnotations).isPresent()) {
widgetParameterBicReference(
matchesBankCountryIbanAnnotation(fieldName, elementAnnotations).get(),
widgetParameter);
}
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (annotationNames.contains(MT_VALIDATION_PATH + "PhoneNumber")) {
widgetName = detectPhoneWidget(annotations);
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (matchesPostalCodeAnnotation(fieldName, elementAnnotations).isPresent()) {
widgetName = "PostalCodeTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
widgetParameterCountryCodeReference(
matchesPostalCodeAnnotation(fieldName, elementAnnotations).get(), widgetParameter);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (matchesTaxNumberAnnotation(fieldName, elementAnnotations).isPresent()) {
widgetName = "TaxNumberTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
widgetParameterCountryCodeReference(
matchesTaxNumberAnnotation(fieldName, elementAnnotations).get(), widgetParameter);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (matchesTinAnnotation(fieldName, elementAnnotations).isPresent()) {
widgetName = "TinTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
widgetParameterCountryCodeReference(
matchesTinAnnotation(fieldName, elementAnnotations).get(), widgetParameter);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (matchesVatIdAnnotation(fieldName, elementAnnotations).isPresent()) {
widgetName = "VatIdTextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
widgetParameterCountryCodeReference(
matchesVatIdAnnotation(fieldName, elementAnnotations).get(), widgetParameter);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (matchesPhoneNumberValueAnnotation(fieldName, elementAnnotations).isPresent()) {
final AnnotationMirror annotationMirror =
matchesPhoneNumberValueAnnotation(fieldName, elementAnnotations).get();
if (BooleanUtils.isTrue(
getValueFromAnnotationMirror(annotationMirror, "allowDin5008", Boolean.TRUE))) {
widgetName = "PhoneNumberDin5008InterSuggestBox";
} else if (BooleanUtils
.isTrue(getValueFromAnnotationMirror(annotationMirror, "allowE123", Boolean.TRUE))) {
widgetName = "PhoneNumberE123InterSuggestBox";
} else if (BooleanUtils
.isTrue(getValueFromAnnotationMirror(annotationMirror, "allowUri", Boolean.TRUE))) {
widgetName = "PhoneNumberUriSuggestBox";
} else if (BooleanUtils
.isTrue(getValueFromAnnotationMirror(annotationMirror, "allowMs", Boolean.TRUE))) {
widgetName = "PhoneNumberMsSuggestBox";
} else {
widgetName = "PhoneNumberCommonInterSuggestBox";
}
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
widgetParameterCountryCodeReference(annotationMirror, widgetParameter);
fieldTypeEnum = FieldTypeEnum.STRING;
} else if (annotationNames.contains("jakarta.persistence.OneToMany")
|| annotationNames.contains("javax.persistence.OneToMany")) {
final DeclaredType oneToManyType = getDeclaredTypeOfFirstTypeElement(field);
imports.add(TypeUtils.getClassName(oneToManyType));
imports.add("com.google.gwt.uibinder.client.UiHandler");
imports.add("com.google.gwt.event.dom.client.ClickEvent");
widgetName = TypeUtils.getClassNameWithoutPath(elementType)
+ TypeUtils.getClassNameWithoutPath(oneToManyType) + "Editor";
childWidgets.addAll(detectBackofficeWidgetsOfElement(prefix + fieldName + ".", null,
oneToManyType.asElement(), processingEnv, false));
final Optional extends AnnotationMirror> annotationMirror = annotations.stream()
.filter(amirror -> "jakarta.persistence.OneToMany"
.equals(amirror.getAnnotationType().toString())
|| "javax.persistence.OneToMany".equals(amirror.getAnnotationType().toString()))
.findFirst();
if (annotationMirror.isPresent()) {
additional.putAll(getValuesAnnotationMirror(annotationMirror.get()));
}
fieldTypeEnum = FieldTypeEnum.ONE_TO_MANY;
} else {
if (isEmbedded(fieldType)) {
widgetName = TypeUtils.getClassNameWithoutPath(elementType)
+ TypeUtils.getClassNameWithoutPath(fieldType) + CLASS_SUFFIX_VIEW;
childWidgets.addAll(detectBackofficeWidgetsOfElement(prefix + fieldName + ".", null,
field, processingEnv, writeDebugId));
fieldTypeEnum = FieldTypeEnum.EMBEDED;
} else {
widgetName = "TextBox";
imports.add(WIDGET_PATH + widgetName);
notNullNotBlankNotEmptyRequiredCheck(widgetParameter, annotationNames);
sizeMaxLengthCheck(widgetParameter, annotations, annotationNames);
fieldTypeEnum = FieldTypeEnum.STRING;
}
}
}
final BackofficeWidget result = BackofficeWidget.of(elementType, field, fieldName, imports,
widgetName, widgetParameter, provided, providedConstructor, fieldTypeEnum, parentWidget,
ignore, writeDebugId, additional);
if (!childWidgets.isEmpty()) {
result.setChildWidgets(childWidgets);
}
return result;
}
private Optional extends AnnotationMirror> matchesPostalCodeAnnotation(final String fieldName,
final List extends AnnotationMirror> elementAnnotations) {
return matchesGivenAnnotation(fieldName, elementAnnotations, "PostalCode", "fieldPostalCode");
}
private Optional extends AnnotationMirror> matchesTaxNumberAnnotation(final String fieldName,
final List extends AnnotationMirror> elementAnnotations) {
return matchesGivenAnnotation(fieldName, elementAnnotations, "TaxNumber", "fieldTaxNumber");
}
private Optional extends AnnotationMirror> matchesTinAnnotation(final String fieldName,
final List extends AnnotationMirror> elementAnnotations) {
return matchesGivenAnnotation(fieldName, elementAnnotations, "Tin", "fieldTin");
}
private Optional extends AnnotationMirror> matchesVatIdAnnotation(final String fieldName,
final List extends AnnotationMirror> elementAnnotations) {
return matchesGivenAnnotation(fieldName, elementAnnotations, "VatId", "fieldVatId");
}
private Optional extends AnnotationMirror> matchesPhoneNumberValueAnnotation(
final String fieldName, final List extends AnnotationMirror> elementAnnotations) {
return matchesGivenAnnotation(fieldName, elementAnnotations, "PhoneNumberValue",
"fieldPhoneNumber");
}
private Optional extends AnnotationMirror> matchesBankCountryIbanAnnotation(
final String fieldName, final List extends AnnotationMirror> elementAnnotations) {
return matchesGivenAnnotation(fieldName, elementAnnotations, "BankCountry", "fieldIban");
}
private Optional extends AnnotationMirror> matchesGivenAnnotation(final String fieldName,
final List extends AnnotationMirror> elementAnnotations, final String validationName,
final String validationFieldName) {
return elementAnnotations.stream()
.filter(annotationMirror -> (MT_VALIDATION_PATH + validationName)
.equals(annotationMirror.getAnnotationType().toString()))
.filter(annotationMirror -> annotationMirror.getElementValues().entrySet().stream()
.anyMatch(elementValue -> StringUtils.equals(validationFieldName,
elementValue.getKey().getSimpleName())
&& StringUtils.equals(fieldName,
Objects.toString(elementValue.getValue().getValue(), null))))
.findFirst();
}
private void widgetParameterCountryCodeReference(final AnnotationMirror annotationMirror,
final List widgetParameter) {
widgetParameter.add(BackofficeWidgetParameter.of("countryCodeReference",
getValueFromAnnotationMirror(annotationMirror, "fieldCountryCode", "countryCode"), false));
}
private void widgetParameterBicReference(final AnnotationMirror annotationMirror,
final List widgetParameter) {
widgetParameter.add(BackofficeWidgetParameter.of("bicInput",
getValueFromAnnotationMirror(annotationMirror, "fieldBic", "bic"), false));
}
@SuppressWarnings("unchecked")
private static R getValueFromAnnotationMirror(final AnnotationMirror annotationMirror,
final String fieldName, final R defaultValue) {
return annotationMirror.getElementValues().entrySet().stream()
.filter(
elementValue -> StringUtils.equals(fieldName, elementValue.getKey().getSimpleName()))
.map(elementValue -> (R) elementValue.getValue().getValue()).findFirst()
.orElse(defaultValue);
}
private String detectPhoneWidget(final List extends AnnotationMirror> annotations) {
final Optional extends AnnotationMirror> phoneNumberValidator =
annotations.stream().filter(annotationMirror -> (MT_VALIDATION_PATH + "PhoneNumber")
.equals(annotationMirror.getAnnotationType().toString())).findFirst();
if (phoneNumberValidator.isPresent()) {
if (BooleanUtils.isTrue(getValueFromAnnotationMirror(phoneNumberValidator.get(),
"allowDin5008", Boolean.FALSE))) {
return "PhoneNumberDin5008InterSuggestBox";
}
if (BooleanUtils.isTrue(
getValueFromAnnotationMirror(phoneNumberValidator.get(), "allowE123", Boolean.FALSE))) {
return "PhoneNumberE123InterSuggestBox";
}
if (BooleanUtils.isTrue(
getValueFromAnnotationMirror(phoneNumberValidator.get(), "allowUri", Boolean.FALSE))) {
return "PhoneNumberUriSuggestBox";
}
if (BooleanUtils.isTrue(
getValueFromAnnotationMirror(phoneNumberValidator.get(), "allowCommon", Boolean.FALSE))) {
return "PhoneNumberCommonInterSuggestBox";
}
}
return "PhoneNumberMsSuggestBox";
}
private void futurePastMinMaxCheck(final List imports,
final List widgetParameter, final List annotationNames,
final String importString, final String classString, final String minusMethodString,
final String plusMethodString) {
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "PastOrPresent")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "PastOrPresent")) {
imports.add(importString);
widgetParameter.add(BackofficeWidgetParameter.of("max", classString + ".now()", false));
}
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "Past")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "Past")) {
imports.add(importString);
widgetParameter.add(
BackofficeWidgetParameter.of("max", classString + ".now()." + minusMethodString, false));
}
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "FutureOrPresent")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "FutureOrPresent")) {
imports.add(importString);
widgetParameter.add(BackofficeWidgetParameter.of("min", classString + ".now()", false));
}
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "Future")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "Future")) {
imports.add(importString);
widgetParameter.add(
BackofficeWidgetParameter.of("min", classString + ".now()." + plusMethodString, false));
}
}
private static Map getValuesAnnotationMirror(
final AnnotationMirror annotationMirror) {
return annotationMirror.getElementValues().entrySet().stream()
.collect(Collectors.toMap(elementValue -> elementValue.getKey().getSimpleName().toString(),
elementValue -> elementValue.getValue().getValue()));
}
private void sizeMaxLengthCheck(final List widgetParameter,
final List extends AnnotationMirror> annotations, final List annotationNames) {
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "Size")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "Size")) {
final Optional extends AnnotationMirror> sizeValidator = annotations.stream()
.filter(annotationMirror -> StringUtils.equals(JAKARTA_VALIDATION_PATH + "Size",
annotationMirror.getAnnotationType().toString())
|| StringUtils.equals(JAVAX_VALIDATION_PATH + "Size",
annotationMirror.getAnnotationType().toString()))
.findFirst();
if (sizeValidator.isPresent()) {
final Optional maxSize = sizeValidator.get().getElementValues().entrySet().stream()
.filter(elementValue -> "max".contentEquals(elementValue.getKey().getSimpleName()))
.map(elementValue -> Objects.toString(elementValue.getValue().getValue(), null))
.findAny();
if (maxSize.isPresent()) {
widgetParameter.add(BackofficeWidgetParameter.of("maxLength", maxSize.get(), true));
}
}
}
}
private void notNullNotBlankNotEmptyRequiredCheck(
final List widgetParameter, final List annotationNames) {
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "NotNull")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "NotNull")
|| annotationNames.contains(JAVAX_VALIDATION_PATH + "NotBlank")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "NotBlank")
|| annotationNames.contains(JAVAX_VALIDATION_PATH + "NotEmpty")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "NotEmpty")) {
widgetParameter.add(BackofficeWidgetParameter.of("required", "true", true));
}
}
private void notNullRequiredCheck(final List widgetParameter,
final List annotationNames) {
if (annotationNames.contains(JAVAX_VALIDATION_PATH + "NotNull")
|| annotationNames.contains(JAKARTA_VALIDATION_PATH + "NotNull")) {
widgetParameter.add(BackofficeWidgetParameter.of("required", "true", true));
}
}
protected boolean fieldNameIsConcatenated(final String fieldName) {
return StringUtils.contains(fieldName, '.');
}
protected String fieldNameToCamelCase(final String fieldName) {
final StringBuilder fieldNameCamelCase = new StringBuilder(StringUtils.length(fieldName));
boolean nextUpper = false;
for (final char a : fieldName.toCharArray()) {
if (a == '.') {
nextUpper = true;
} else if (nextUpper) {
fieldNameCamelCase.append(Character.toUpperCase(a));
nextUpper = false;
} else {
fieldNameCamelCase.append(a);
}
}
return fieldNameCamelCase.toString();
}
/**
* detect package for given element.
*
* @param element element to get package from
* @param processingEnv processing environment
* @return the package of the element
*/
protected String detectPackage(final Element element, final ProcessingEnvironment processingEnv) {
return processingEnv.getElementUtils().getPackageOf(element.getEnclosingElement())
.getQualifiedName().toString();
}
/**
* write additional imports.
*
* @param element the element which represents the entity
*/
protected abstract void addAdditionalImports(final String serverPackage, final Element element,
final T annotationInterface, final ProcessingEnvironment processingEnv);
/**
* write class or interface body.
*
* @param out print writer
* @param serverPackage package to generate stuff in
* @param element the element which represents the entity
* @param annotationInterface annotation interface
* @param processingEnv processing environment
*/
protected abstract void writeBody(final PrintWriter out, final String serverPackage,
final Element element, final T annotationInterface, ProcessingEnvironment processingEnv);
}