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

com.crabshue.commons.aggregator.Analysed Maven / Gradle / Ivy

The newest version!
package com.crabshue.commons.aggregator;

import com.crabshue.commons.aggregator.model.Collect;
import com.crabshue.commons.aggregator.model.Execute;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

@Data
@Slf4j
class Analysed {
    private CLASS_TYPE classType;
    private String classContext;
    private List classCollects;
    private Map> collects;
    private Map> executes;
    private Map variables;
    private List otherFields;

    @Override
    public String toString() {
        return "Analysed{" +
            "classType=" + classType +
            ", classContext='" + classContext + '\'' +
            ", classCollects=" + classCollects +
            ", collects=" + collects +
            ", executes=" + executes +
            ", variables=" + variables +
            ", otherFields=" + otherFields +
            '}';
    }

    Analysed(Class objectClass, IgnorableClassDetector ignorableClassDetector) {
        Context cx = (Context) objectClass.getDeclaredAnnotation(Context.class);
        classContext = cx == null ? null : cx.value();
        classCollects = analyse(null,
            (com.crabshue.commons.aggregator.Collect[]) objectClass.getDeclaredAnnotationsByType(
                com.crabshue.commons.aggregator.Collect.class));
        if (classCollects.size() == 0)
            classCollects = null;
        if (objectClass.isArray()) {
            classType = CLASS_TYPE.ARRAY;
        } else if (List.class.isAssignableFrom(objectClass)) {
            classType = CLASS_TYPE.LIST;
        } else if (Map.class.isAssignableFrom(objectClass)) {
            classType = CLASS_TYPE.MAP;
        } else if (Iterable.class.isAssignableFrom(objectClass)) {
            classType = CLASS_TYPE.ITERABLE;
        } else if (objectClass.isPrimitive()) {
            classType = CLASS_TYPE.IGNORABLE;
        } else if (!isProcessable(objectClass)) {
            classType = CLASS_TYPE.IGNORABLE;
        } else if (ignorableClassDetector.canIgnore(objectClass)) {
            classType = CLASS_TYPE.IGNORABLE;
        } else {
            classType = CLASS_TYPE.PROCESSABLE;
            variables = new HashMap<>();
            executes = new HashMap<>();
            collects = new HashMap<>();
            otherFields = new ArrayList<>();
            for (Field f : getFields(objectClass)) {

                Variable variable = f.getDeclaredAnnotation(Variable.class);
                if (variable != null) {
                    variables.put(f.getName(), variable.value());
                }
                com.crabshue.commons.aggregator.Execute[] executors = f.getDeclaredAnnotationsByType(
                    com.crabshue.commons.aggregator.Execute.class);
                com.crabshue.commons.aggregator.Collect[] collectors = f.getDeclaredAnnotationsByType(
                    com.crabshue.commons.aggregator.Collect.class);
                String fieldName = sanitizeFieldName(f.getName());
                if (!isProcessable(objectClass, f, fieldName)) {
                    continue;
                }
                boolean executorsExist = executors != null && executors.length > 0;
                boolean collectorsExist = collectors != null && collectors.length > 0;
                if (executorsExist) {
                    executes.put(fieldName, analyse(fieldName, executors));
                }
                if (collectorsExist) {
                    collects.put(fieldName, analyse(fieldName, collectors));
                }
                if (!executorsExist && !collectorsExist) {
                    otherFields.add(fieldName);
                }
            }
        }
    }

    public static boolean isProcessable(Class objectClass) {
        if (!Modifier.isPublic(objectClass.getModifiers())) {
            logger.warn("Ignoring non public class:'{}', as it will likely fail any evaluation", objectClass.getName());
            return false;
        }
        return true;
    }

    public static boolean isProcessable(Class clazz, Field f, String fieldName) {
        if (!Modifier.isPublic(f.getModifiers()) && !hasPublicAccessor(clazz, fieldName)) {
            logger.warn("Ignoring non public field:'{}' of class:'{}', as it will likely fail any evaluation", fieldName, clazz.getName());
            return false;
        }
        return true;
    }

    private static boolean hasPublicAccessor(Class clazz, String fieldName) {
        String accessorName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
        try {
            return Modifier.isPublic(clazz.getMethod(accessorName).getModifiers());
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    Analysed() {
        classCollects = new ArrayList<>();
        otherFields = new ArrayList<>();
        collects = new HashMap<>();
        executes = new HashMap<>();
        variables = new HashMap<>();
    }

    private static List getFields(Class baseClass) {
        ArrayList ret = new ArrayList<>();
        while (baseClass != null && baseClass != Object.class) {
            Collections.addAll(ret, baseClass.getDeclaredFields());
            baseClass = baseClass.getSuperclass();
        }
        return ret;
    }

    private List analyse(String field, com.crabshue.commons.aggregator.Execute[] executes) {
        List executeList = new ArrayList<>();
        for (com.crabshue.commons.aggregator.Execute execute : executes) {
            executeList.add(new Execute(field, execute.value(), execute.when()));
        }
        return executeList;
    }

    private List analyse(String field, com.crabshue.commons.aggregator.Collect[] collects) {
        List ret = new ArrayList<>();
        for (com.crabshue.commons.aggregator.Collect collect : collects) {
            ret.add(new Collect(field, collect.what(), collect.value(), collect.when()));
        }
        return ret;
    }

    private String sanitizeFieldName(String name) {
        //TODO: also do for or and eq ne lt gt le ge div mod not null true false new var return
        if ("size".equals(name)) {
            return "'" + name + "'";
        }
        return name;
    }

    void addExecute(String field, String jexl, String when) {
        Execute ex = new Execute(field, jexl, when);
        field = sanitizeFieldName(field);
        if (!executes.containsKey(field)) {
            executes.put(field, new ArrayList<>());
        }
        executes.get(field).add(ex);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        Analysed analysed = (Analysed) o;

        if (classType != analysed.classType)
            return false;
        if (classContext != null ? !classContext.equals(analysed.classContext) : analysed.classContext != null)
            return false;
        if (classCollects != null ? !classCollects.equals(analysed.classCollects) : analysed.classCollects != null)
            return false;
        if (collects != null ? !collects.equals(analysed.collects) : analysed.collects != null)
            return false;
        if (executes != null ? !executes.equals(analysed.executes) : analysed.executes != null)
            return false;
        if (variables != null ? !variables.equals(analysed.variables) : analysed.variables != null)
            return false;
        return otherFields != null ? otherFields.equals(analysed.otherFields) : analysed.otherFields == null;
    }

    @Override
    public int hashCode() {
        return Objects.hash(classType, classContext, classCollects, collects, executes, variables, otherFields);
    }

    void addCollectField(String field, String to, String when) {
        field = sanitizeFieldName(field);
        Collect collect = new Collect(field, null, to, when);
        if (!collects.containsKey(field)) {
            collects.put(field, new ArrayList<>());
        }
        collects.get(field).add(collect);
    }

    void addCollectClass(String what, String to, String when) {
        classCollects.add(new Collect(null, what, to, when));
    }

    void addVariable(String field, String variable) {
        field = sanitizeFieldName(field);
        variables.put(field, variable);
    }

    void addOtherFields(Class clazz) {
        for (Field f : getFields(clazz)) {
            String fieldName = sanitizeFieldName(f.getName());
            //check static
            if (!executes.containsKey(fieldName) && !collects.containsKey(fieldName) && isProcessable(clazz, f, fieldName))
                otherFields.add(fieldName);
        }
    }

    void prune() {
        if (classCollects.isEmpty())
            classCollects = null;
    }

    public enum CLASS_TYPE {ARRAY, LIST, MAP, ITERABLE, IGNORABLE, PROCESSABLE}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy