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

org.simpleflatmapper.reflect.impl.ParamNameDeductor Maven / Gradle / Ivy

package org.simpleflatmapper.reflect.impl;

import org.simpleflatmapper.reflect.getter.GetterHelper;
import org.simpleflatmapper.reflect.Getter;
import org.simpleflatmapper.reflect.Instantiator;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.reflect.InstantiatorFactory;
import org.simpleflatmapper.reflect.ObjectGetterFactory;
import org.simpleflatmapper.reflect.Parameter;
import org.simpleflatmapper.reflect.ReflectionInstantiatorDefinitionFactory;
import org.simpleflatmapper.reflect.meta.ClassVisitor;
import org.simpleflatmapper.util.TypeHelper;
import org.simpleflatmapper.reflect.getter.ConstantGetter;
import org.simpleflatmapper.reflect.meta.FieldAndMethodCallBack;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ParamNameDeductor {

    private static final Map, Object> primitivesMarkValue = new HashMap, Object>();
    static {
        primitivesMarkValue.put(byte.class, (byte) 1);
        primitivesMarkValue.put(char.class, (char) 1);
        primitivesMarkValue.put(short.class, (short) 1);
        primitivesMarkValue.put(int.class, (int) 1);
        primitivesMarkValue.put(long.class, (long) 1);
        primitivesMarkValue.put(float.class, (float) 1);
        primitivesMarkValue.put(double.class, (double) 1);
    }
    private static final Map, Object> primitivesNeutralValue = new HashMap, Object>();
    static {
        primitivesNeutralValue.put(byte.class, (byte) 0);
        primitivesNeutralValue.put(char.class, (char) 0);
        primitivesNeutralValue.put(short.class, (short) 0);
        primitivesNeutralValue.put(int.class, (int) 0);
        primitivesNeutralValue.put(long.class, (long) 0);
        primitivesNeutralValue.put(float.class, (float) 0);
        primitivesNeutralValue.put(double.class, (double) 0);
    }
    
    private final Class target;

    private List> accessors;
    private final InstantiatorFactory instantiatorFactory = new InstantiatorFactory(null);

    public ParamNameDeductor(Class  target) {
        this.target = target;
    }


    public String findParamName(InstantiatorDefinition instantiatorDefinition, Parameter param, boolean builderIgnoresNullValues) {
        if (accessors == null) {
            accessors = listAccessors();
        }
        try {
            T value;

            Map> parameters = parametersWithExpectedValue(instantiatorDefinition, param, true, builderIgnoresNullValues);
            Instantiator instantiator = instantiatorFactory.getInstantiator(instantiatorDefinition, Object.class, parameters, false, builderIgnoresNullValues);

            try {
                // try with null values
                value = instantiator.newInstance(null);
            } catch(NullPointerException e) {
                // try with non null explicit values
                parameters = parametersWithExpectedValue(instantiatorDefinition, param, false, builderIgnoresNullValues);
                instantiator = instantiatorFactory.getInstantiator(instantiatorDefinition, Object.class, parameters, false, builderIgnoresNullValues);
                value = instantiator.newInstance(null);
            }

            if (value != null) {
                Object expectedPropertyValue = parameters.get(param).get(null);
                // iterate through all the accessor to find one that returns a matching value
                for (Accessor accessor : accessors) {
                    try {
                        final Object propertyValue = accessor.getter.get(value);
                        if (expectedPropertyValue.equals(propertyValue)) {
                            return accessor.name;
                        }
                    } catch (Exception e) {
                        // IGNORE
                    }
                }
            }

        } catch(Exception e) {
            // IGNORE
        }
        return null;
    }

    private Map> parametersWithExpectedValue(InstantiatorDefinition instantiatorDefinition, Parameter param, boolean allowNull, boolean builderIgnoresNullValues) throws Exception {
        Map> parameterGetterMap = parameters(instantiatorDefinition, allowNull, builderIgnoresNullValues);
        parameterGetterMap.put(param, new ConstantGetter(markValue(param.getGenericType(), builderIgnoresNullValues)));
        return parameterGetterMap;
    }

    private Map> parameters(InstantiatorDefinition instantiatorDefinition, boolean allowNull, boolean builderIgnoresNullValues) throws Exception {
        Map> parameterGetterMap = new HashMap>();
        for(Parameter parameter : instantiatorDefinition.getParameters()) {
            Object value = neutralValue(parameter.getGenericType(), allowNull, builderIgnoresNullValues);
            parameterGetterMap.put(parameter, new ConstantGetter(value));
        }
        return parameterGetterMap;
    }

    @SuppressWarnings("unchecked")
    private  V markValue(Type type, boolean builderIgnoresNullValues) throws Exception {
        if (TypeHelper.isPrimitive(type)) {
            return (V) primitivesMarkValue.get(type);
        }
        else if (TypeHelper.areEquals(type, String.class)) {
            return (V) "1";
        } else if (TypeHelper.isAssignable(Enum.class, type)) {
            Enum[] values = TypeHelper.toClass(type).getEnumConstants();
            return (V) (values.length > 1 ? values[1] : values[0]);
        } else {
            return createValueFromInstantiator(type, builderIgnoresNullValues);
        }
    }

    @SuppressWarnings("unchecked")
    private  V neutralValue(Type type, boolean allowNull, boolean builderIgnoresNullValues) throws Exception {
        if (TypeHelper.isPrimitive(type)) {
            return (V) primitivesNeutralValue.get(type);
        }
        if (allowNull)  return null;

        if (TypeHelper.areEquals(type, String.class)) {
            return (V) "0";
        } else if (TypeHelper.isAssignable(Enum.class, type)) {
            Enum[] values = TypeHelper.toClass(type).getEnumConstants();
            return (V) values[0];
        } else {
            return createValueFromInstantiator(type, builderIgnoresNullValues);
        }
    }

    private  V createValueFromInstantiator(Type type, boolean builderIgnoresNullValues) throws Exception {
        InstantiatorDefinition instantiatorDefinition = InstantiatorFactory.getSmallerConstructor(ReflectionInstantiatorDefinitionFactory.extractDefinitions(type), Collections.emptySet());

        Instantiator instantiator = instantiatorFactory.getInstantiator(instantiatorDefinition, Object.class, parameters(instantiatorDefinition, true, builderIgnoresNullValues), false, builderIgnoresNullValues);
        try {
            return instantiator.newInstance(null);
        } catch (NullPointerException e) {
            instantiator = instantiatorFactory.getInstantiator(instantiatorDefinition, Object.class, parameters(instantiatorDefinition, false, builderIgnoresNullValues), false, builderIgnoresNullValues);
            return instantiator.newInstance(null);
        }
    }

    private List> listAccessors() {
        final List> list = new ArrayList>();
        ClassVisitor.visit(target, new FieldAndMethodCallBack() {
            ObjectGetterFactory objectGetterFactory = new ObjectGetterFactory(null);
            @Override
            public void method(Method method) {
                if (GetterHelper.isGetter(method)) {
                    Getter methodGetter = objectGetterFactory.getMethodGetter(method);
                    list.add(new Accessor(GetterHelper.getPropertyNameFromMethodName(method.getName()), methodGetter));
                }
            }

            @Override
            public void field(Field field) {
                Getter fieldGetter = objectGetterFactory.getFieldGetter(field);
                list.add(new Accessor(field.getName(), fieldGetter));
            }
        });
        return list;
    }

    private static class Accessor {
        private final Getter getter;
        private final String name;

        private Accessor(String name, Getter getter) {
            this.getter = getter;
            this.name = name;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy