All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.knightsoftnet.gwtp.spring.annotation.processor.AbstractBackofficeCreator Maven / Gradle / Ivy

There is a newer version: 2.2.2
Show newest version
/*
 * 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 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 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 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 matchesPostalCodeAnnotation(final String fieldName,
      final List elementAnnotations) {

    return matchesGivenAnnotation(fieldName, elementAnnotations, "PostalCode", "fieldPostalCode");
  }

  private Optional matchesTaxNumberAnnotation(final String fieldName,
      final List elementAnnotations) {

    return matchesGivenAnnotation(fieldName, elementAnnotations, "TaxNumber", "fieldTaxNumber");
  }

  private Optional matchesTinAnnotation(final String fieldName,
      final List elementAnnotations) {

    return matchesGivenAnnotation(fieldName, elementAnnotations, "Tin", "fieldTin");
  }

  private Optional matchesVatIdAnnotation(final String fieldName,
      final List elementAnnotations) {

    return matchesGivenAnnotation(fieldName, elementAnnotations, "VatId", "fieldVatId");
  }

  private Optional matchesPhoneNumberValueAnnotation(
      final String fieldName, final List elementAnnotations) {

    return matchesGivenAnnotation(fieldName, elementAnnotations, "PhoneNumberValue",
        "fieldPhoneNumber");
  }

  private Optional matchesBankCountryIbanAnnotation(
      final String fieldName, final List elementAnnotations) {

    return matchesGivenAnnotation(fieldName, elementAnnotations, "BankCountry", "fieldIban");
  }

  private Optional matchesGivenAnnotation(final String fieldName,
      final List 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 annotations) {
    final Optional 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 annotations, final List annotationNames) {
    if (annotationNames.contains(JAVAX_VALIDATION_PATH + "Size")
        || annotationNames.contains(JAKARTA_VALIDATION_PATH + "Size")) {
      final Optional 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);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy