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

io.toolisticon.aptk.tools.BeanUtils Maven / Gradle / Ivy

package io.toolisticon.aptk.tools;

import com.sun.source.tree.StatementTree;
import io.toolisticon.aptk.tools.command.impl.GetAttributesCommand;
import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers;
import io.toolisticon.aptk.tools.fluentfilter.FluentElementFilter;
import io.toolisticon.aptk.tools.fluentvalidator.FluentElementValidator;

import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Utility class to handle bean related tasks.
 */
public final class BeanUtils {

    final static String[] GETTER_PREFIXES = {"get", "is", "has"};
    final static String[] SETTER_PREFIXES = {"set"};

    /**
     * Class to store attribute related data.
     */
    public static class AttributeResult {

        private VariableElement field;


        private String setterMethodName;
        private String getterMethodName;


        public VariableElement getField() {
            return field;
        }

        public void setField(VariableElement field) {
            this.field = field;
        }

        public boolean hasGetter() {
            return getterMethodName != null;
        }

        public boolean hasSetter() {
            return setterMethodName != null;
        }

        public String getSetterMethodName() {
            return setterMethodName;
        }

        public void setSetterMethodName(String setterMethodName) {
            this.setterMethodName = setterMethodName;
        }

        public String getGetterMethodName() {
            return getterMethodName;
        }

        public void setGetterMethodName(String getterMethodName) {
            this.getterMethodName = getterMethodName;
        }

        public String getFieldName() {
            return field.getSimpleName().toString();
        }

        public TypeMirror getFieldTypeMirror() {
            return field.asType();
        }

        public TypeElement getFieldTypeElement() {
            return TypeUtils.TypeRetrieval.getTypeElement(getFieldTypeMirror());
        }

        public boolean isValidAttribute() {
            return this.hasGetter() && this.hasSetter();
        }

    }


    /**
     * Hidden constructor
     */
    private BeanUtils() {

    }

    /**
     * Checks if typeElement has a sole default no-args constructor.
     * 

* Internally calls isDefaultNoargConstructor. * See that method description for detailed overview of checked criteria. * * @param typeElement the type element * @return true */ public static boolean hasDefaultNoargsConstructor(TypeElement typeElement) { List constructors = FluentElementFilter.createFluentElementFilter(typeElement.getEnclosedElements()) .applyFilter(AptkCoreMatchers.IS_CONSTRUCTOR) .getResult(); // check for number of constructors if (constructors.size() != 1) { return false; } return isDefaultNoargConstructor(constructors.get(0)); } /** * Checks whether an ExecutableElement is a default noargs constructor. *

* Checks if *

    *
  • executable element is public constructor without parameters
  • *
  • constructor is sole constructor
  • *
  • constructor contains just a super(); statement in body
  • *
  • constructor has no thrown types declarations
  • *
  • constructor has same visibility modifier like it's type
  • *
* * @param element The executable element to check * @return true if passes executable element is constructor, otherwise false */ public static boolean isDefaultNoargConstructor(ExecutableElement element) { // first check element if (!FluentElementValidator.createFluentElementValidator(element) .applyValidator(AptkCoreMatchers.BY_ELEMENT_KIND).hasOneOf(ElementKind.CONSTRUCTOR) .applyValidator(AptkCoreMatchers.BY_MODIFIER).hasAllOf(Modifier.PUBLIC) .applyValidator(AptkCoreMatchers.HAS_NO_PARAMETERS) .applyValidator(AptkCoreMatchers.HAS_NO_THROWN_TYPES) .justValidate()) { return false; } TypeElement typeElementFilter = ElementUtils.AccessEnclosingElements.getFirstEnclosingElementOfKind(element, ElementKind.CLASS); // check for number of constructors if (!FluentElementFilter.createFluentElementFilter(typeElementFilter.getEnclosedElements()) .applyFilter(AptkCoreMatchers.IS_CONSTRUCTOR).hasSingleElement()) { return false; } // must have same visibility like class if (ElementUtils.CheckModifierOfElement.getVisibilityModifier(typeElementFilter) != ElementUtils.CheckModifierOfElement.getVisibilityModifier(element)) { return false; } // now check statements of constructor List statements = ProcessingEnvironmentUtils.getTrees().getTree(element).getBody().getStatements(); if (statements.size() != 1) { return false; } return Pattern.compile("^\\s*super\\(\\)[;]{0,1}\\s*$").matcher(statements.get(0).toString()).matches(); } public static boolean isAttribute(VariableElement field) { return checkHasSetter(field) && checkHasGetter(field); } public static AttributeResult[] getAttributesWithInheritance(TypeElement typeElement) { List resultList = new ArrayList(); resultList.addAll(Arrays.asList(GetAttributesCommand.INSTANCE.execute(typeElement))); // process super types for (TypeElement superTypeElement : ElementUtils.AccessTypeHierarchy.getSuperTypeElementsOfKindType(typeElement)) { resultList.addAll(Arrays.asList(GetAttributesCommand.INSTANCE.execute(superTypeElement))); } return resultList.toArray(new AttributeResult[resultList.size()]); } public static AttributeResult[] getAttributes(TypeElement typeElement) { if (typeElement == null) { return new AttributeResult[0]; } List fields = FluentElementFilter.createFluentElementFilter(typeElement.getEnclosedElements()) .applyFilter(AptkCoreMatchers.IS_FIELD) .applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByNoneOf(Modifier.STATIC) .getResult(); List result = new ArrayList<>(); for (VariableElement field : fields) { AttributeResult attributeResult = new AttributeResult(); attributeResult.setField(field); String getterMethodName = BeanUtils.getGetterMethodName(field); attributeResult.setGetterMethodName(BeanUtils.getGetterMethodName(field)); attributeResult.setSetterMethodName(BeanUtils.getSetterMethodName(field)); // just add those fields with both getters and setters if (attributeResult.hasGetter() && attributeResult.hasSetter()) { result.add(attributeResult); } } return result.toArray(new AttributeResult[result.size()]); } /** * Checks if passed field has getter method. * If getter method cannot be found it will check if there are lombok annotations which will triger generation of it. * * @param field the VariableElement of a field * @return true if getter method is present or to be generated by lombok */ public static boolean checkHasGetter(VariableElement field) { if (field == null || field.getKind() != ElementKind.FIELD || AptkCoreMatchers.BY_MODIFIER.getMatcher().checkForMatchingCharacteristic(field, Modifier.STATIC)) { return false; } TypeElement typeElement = ElementUtils.AccessEnclosingElements.getFirstEnclosingElementOfKind(field, ElementKind.CLASS); return checkLombokDataAnnotation(typeElement) || checkLombokGetterAnnotationOnType(typeElement) || checkLombokGetterAnnotationOnField(field) || checkHasGetterMethod(field, typeElement) ; } /** * Checks if passed field has setter method. * If setter method cannot be found it will check if there are lombok annotations which will triger generation of it. * * @param field the VariableElement of a field * @return true if getter method is present or to be generated by lombok */ public static boolean checkHasSetter(VariableElement field) { if (field == null || field.getKind() != ElementKind.FIELD) { return false; } TypeElement typeElement = ElementUtils.AccessEnclosingElements.getFirstEnclosingElementOfKind(field, ElementKind.CLASS); return checkLombokDataAnnotation(typeElement) || checkLombokSetterAnnotationOnType(typeElement) || checkLombokSetterAnnotationOnField(field) || checkHasSetterMethod(field, typeElement) ; } /** * Checks if lombok.Data annotation is present on passed TypeElement. * * @param typeElement the TypeElement to check * @return true if Data annotation can be found on passed typeElement otherwise false */ public static boolean checkLombokDataAnnotation(TypeElement typeElement) { return AnnotationUtils.getAnnotationMirror(typeElement, "lombok.Data") != null; } /** * Checks if lombok.Getter annotation is present on passed TypeElement. * * @param typeElement the TypeElement to check * @return true if Getter annotation can be found on passed TypeElement otherwise false */ public static boolean checkLombokGetterAnnotationOnType(TypeElement typeElement) { return AnnotationUtils.getAnnotationMirror(typeElement, "lombok.Getter") != null; } /** * Checks if lombok.Getter annotation is present on passed TypeElement. * * @param variableElement the VariableElement to check * @return true if Getter annotation can be found on passed VariableElement otherwise false */ public static boolean checkLombokGetterAnnotationOnField(VariableElement variableElement) { return AnnotationUtils.getAnnotationMirror(variableElement, "lombok.Getter") != null; } /** * Get the getters method name. * * @param field The field * @return the getters method name or null if field has no getter */ public static String getGetterMethodName(VariableElement field) { if (field == null || field.getKind() != ElementKind.FIELD) { return null; } TypeElement typeElement = (TypeElement) ElementUtils.AccessEnclosingElements.getFirstEnclosingElementOfKind(field, ElementKind.CLASS); ExecutableElement getterMethod = getGetterMethod(field, typeElement); if (getterMethod != null) { return getterMethod.getSimpleName().toString(); } if (checkLombokDataAnnotation(typeElement) || checkLombokGetterAnnotationOnType(typeElement) || checkLombokGetterAnnotationOnField(field)) { return TypeUtils.TypeComparison.isTypeEqual(field.asType(), TypeUtils.TypeRetrieval.getTypeMirror(boolean.class)) ? getPrefixedName("is", field.getSimpleName().toString()) : getPrefixedName("get", field.getSimpleName().toString()); } return null; } /** * Get setter name for a field. * * @param field the fields VariableElement * @return the name of the setter method */ public static String getSetterMethodName(VariableElement field) { if (field == null || field.getKind() != ElementKind.FIELD) { return null; } return checkHasSetter(field) ? getPrefixedName("set", field.getSimpleName().toString()) : null; } /** * Checks if a field has a setter method or if it will be created by lombok * * @param field the fields VariableElement * @param typeElement the TypeElement * @return true if field has a getter method, otherwise false */ protected static boolean checkHasGetterMethod(VariableElement field, TypeElement typeElement) { return getGetterMethod(field, ElementUtils.AccessEnclosingElements.getFirstEnclosingElementOfKind(field, ElementKind.CLASS)) != null; } protected static ExecutableElement getGetterMethod(VariableElement field, TypeElement typeElement) { List result = FluentElementFilter.createFluentElementFilter(typeElement.getEnclosedElements()) .applyFilter(AptkCoreMatchers.IS_METHOD) .applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByAllOf(Modifier.PUBLIC) .applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByNoneOf(Modifier.ABSTRACT, Modifier.STATIC) .applyFilter(AptkCoreMatchers.BY_NAME).filterByOneOf(getPossibleGetterOrSetterNames(field, GETTER_PREFIXES)) .applyFilter(AptkCoreMatchers.HAS_NO_PARAMETERS) .applyFilter(AptkCoreMatchers.BY_RETURN_TYPE_MIRROR).filterByOneOf(field.asType()) .getResult(); return result.size() >= 1 ? result.get(0) : null; } protected static boolean checkHasSetterMethod(VariableElement field, TypeElement typeElement) { return getSetterMethod(field, typeElement) != null; } protected static ExecutableElement getSetterMethod(VariableElement field, TypeElement typeElement) { TypeMirror[] parameters = {field.asType()}; List result = FluentElementFilter.createFluentElementFilter(typeElement.getEnclosedElements()) .applyFilter(AptkCoreMatchers.IS_METHOD) .applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByAllOf(Modifier.PUBLIC) .applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByNoneOf(Modifier.ABSTRACT, Modifier.STATIC) .applyFilter(AptkCoreMatchers.BY_NAME).filterByOneOf(getPossibleGetterOrSetterNames(field, SETTER_PREFIXES)) .applyFilter(AptkCoreMatchers.HAS_VOID_RETURN_TYPE) .applyFilter(AptkCoreMatchers.BY_PARAMETER_TYPE_MIRROR).filterByOneOf(parameters) .getResult(); return result.size() >= 1 ? result.get(0) : null; } protected static String[] getPossibleGetterOrSetterNames(VariableElement field, String[] prefixes) { String[] result = new String[prefixes.length]; for (int i = 0; i < prefixes.length; i++) { result[i] = getPrefixedName(prefixes[i], field.getSimpleName().toString()); } return result; } /** * Method to create a prefixed camel cased String * * @param name the name to be prefixed * @param prefix the prefix * @return the camel cased string */ public static String getPrefixedName(String prefix, String name) { return prefix + name.substring(0, 1).toUpperCase() + name.substring(1); } public static boolean checkLombokSetterAnnotationOnType(TypeElement typeElement) { return AnnotationUtils.getAnnotationMirror(typeElement, "lombok.Setter") != null; } public static boolean checkLombokSetterAnnotationOnField(VariableElement variableElement) { return AnnotationUtils.getAnnotationMirror(variableElement, "lombok.Setter") != null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy