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

org.simpleflatmapper.reflect.meta.ObjectClassMeta Maven / Gradle / Ivy

Go to download

Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.

There is a newer version: 9.0.2
Show newest version
package org.simpleflatmapper.reflect.meta;

import org.simpleflatmapper.reflect.getter.GetterHelper;
import org.simpleflatmapper.reflect.getter.NullGetter;
import org.simpleflatmapper.reflect.impl.ParamNameDeductor;
import org.simpleflatmapper.reflect.*;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.reflect.setter.SetterHelper;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.util.Consumer;
import org.simpleflatmapper.util.ErrorHelper;
import org.simpleflatmapper.util.ListCollector;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.TypeHelper;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

public final class ObjectClassMeta implements ClassMeta {

	private final List> properties;
	private final List> constructorProperties;
	private final List instantiatorDefinitions;


	private final ReflectionService reflectService;
	private final Type target;

	private final Map fieldAliases;
	private final boolean needTransformer;

	public ObjectClassMeta(Type target, ReflectionService reflectService) {
		this(target, null, reflectService);
	}

	public ObjectClassMeta(Type target, Member builderInstantiator, ReflectionService reflectService) {
		try {
			this.target = target;
			this.needTransformer = TypeHelper.toClass(target).isAnnotationPresent(ModifyInjectedParams.class);
			this.reflectService = reflectService;
			this.instantiatorDefinitions = reflectService.extractInstantiator(target, builderInstantiator);
			this.constructorProperties = listConstructorProperties(instantiatorDefinitions, reflectService.builderIgnoresNullValues());
			this.fieldAliases = Collections.unmodifiableMap(aliases(reflectService, TypeHelper.toClass(target)));
			this.properties = Collections.unmodifiableList(listProperties(reflectService, target));
		} catch(Exception e) {
			ErrorHelper.rethrow(e);
			throw new IllegalStateException();
		}
	}

    public ObjectClassMeta(Type target,
                           List instantiatorDefinitions,
                           List> constructorProperties,
						   Map fieldAliases,
                           List> properties,
                           ReflectionService reflectService, 
						   boolean needTransformer) {
        this.target = target;
		this.reflectService = reflectService;
		this.instantiatorDefinitions = instantiatorDefinitions;
		this.constructorProperties = constructorProperties;
		this.fieldAliases = fieldAliases;
		this.properties = properties;
		this.needTransformer = needTransformer;
	}

	@Override
	public ClassMeta withReflectionService(ReflectionService reflectionService) {
		
		return new ObjectClassMeta(target, 
				instantiatorDefinitions, 
				withReflectionServiceConstructor(constructorProperties, reflectionService), 
				fieldAliases,
				withReflectionService(properties, reflectionService),
				reflectionService,
				needTransformer
		);
	}


	private Map aliases(final ReflectionService reflectService, Class target) {
		final Map map = new HashMap();

		ClassVisitor.visit(target, new FieldAndMethodCallBack() {
			@Override
			public void method(Method method) {
				String alias = reflectService.getColumnName(method);
				if (alias != null && !alias.isEmpty()) {
					final String name;
					if (SetterHelper.isSetter(method)) {
						name = SetterHelper.getPropertyNameFromMethodName(method.getName());
					} else if (GetterHelper.isGetter(method)) {
						name = GetterHelper.getPropertyNameFromMethodName(method.getName());
					} else {
						throw new IllegalArgumentException("Annotation on non accessor method " + method);
					}
					map.put(name, alias);
				}
			}

			@Override
			public void field(Field field) {
				String alias = reflectService.getColumnName(field);
				if (alias != null && !alias.isEmpty()) {
					map.put(field.getName(), alias);
				}
			}
		});

		return map;
	}

	private List> listConstructorProperties(List instantiatorDefinitions, boolean builderIgnoresNullValues) {
		if (instantiatorDefinitions == null) return null;

		List> constructorProperties = new ArrayList>();

		ParamNameDeductor paramNameDeductor = null;
		for(InstantiatorDefinition cd : instantiatorDefinitions) {
			for(org.simpleflatmapper.reflect.Parameter param : cd.getParameters()) {
				String paramName = param.getName();

				if (paramName == null) {
					if (paramNameDeductor == null) {
						paramNameDeductor = new ParamNameDeductor(TypeHelper.toClass(target));
					}
					paramName = paramNameDeductor.findParamName(cd, param, builderIgnoresNullValues);
				}
				constructorProperties.add(constructorMeta(param, paramName, cd));
			}
		}
		return constructorProperties;
	}

    private 

ConstructorPropertyMeta constructorMeta(org.simpleflatmapper.reflect.Parameter param, String paramName, InstantiatorDefinition instantiatorDefinition) { return new ConstructorPropertyMeta(paramName, target, reflectService, param, instantiatorDefinition, null); } private List> listProperties(final ReflectionService reflectService, final Type targetType) { final Class target = TypeHelper.toClass(targetType); final List> properties = new ArrayList>(); final Map, Type> typeVariableTypeMap = TypeHelper.getTypesMap(targetType); ClassVisitor.visit(target, new FieldAndMethodCallBack() { @Override public void method(Method method) { final String name = method.getName(); if (SetterHelper.isSetter(method)) { final String propertyName = SetterHelper.getPropertyNameFromMethodName(name); Setter methodSetter = reflectService.getObjectSetterFactory().getMethodSetter(method); register(propertyName, method.getGenericParameterTypes()[0], ScoredGetter.nullGetter(), ScoredSetter.ofMethod(method, methodSetter), getDefineProperties(method)); } else if (GetterHelper.isGetter(method)) { final String propertyName = GetterHelper.getPropertyNameFromMethodName(name); Getter methodGetter = reflectService.getObjectGetterFactory().getMethodGetter(method); register(propertyName, method.getGenericReturnType(), ScoredGetter.ofMethod(method, methodGetter), ScoredSetter.nullSetter(), getDefineProperties(method)); if ((method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)) && name.startsWith("is") ) { // is there a constructor on the name if (findProperty(constructorProperties, name, method.getReturnType()) != -1) { register(name, method.getGenericReturnType(), ScoredGetter.ofMethod(method, methodGetter), ScoredSetter.nullSetter(), getDefineProperties(method)); }; } } } @SuppressWarnings("unchecked") private

void register(String propertyName, Type type, ScoredGetter getter, ScoredSetter setter, Object[] defineProperties) { if (type instanceof TypeVariable) { Type mappedType = typeVariableTypeMap.get(type); if (mappedType != null) { type = mappedType; } } int indexOfProperty = findProperty(constructorProperties, propertyName, type); if (indexOfProperty != -1) { ConstructorPropertyMeta constructorPropertyMeta = (ConstructorPropertyMeta) constructorProperties.get(indexOfProperty); if (defineProperties != null && defineProperties.length > 0) { constructorPropertyMeta = constructorPropertyMeta.defineProperties(defineProperties); constructorProperties.set(indexOfProperty, constructorPropertyMeta); } if (getter != null && GetterHelper.isCompatible(constructorPropertyMeta.getPropertyType(), type)) { constructorPropertyMeta = constructorPropertyMeta.getter(getter); constructorProperties.set(indexOfProperty, constructorPropertyMeta); } if (setter != null && SetterHelper.isCompatible(constructorPropertyMeta.getPropertyType(), type)) { constructorPropertyMeta = constructorPropertyMeta.setter(setter); constructorProperties.set(indexOfProperty, constructorPropertyMeta); } } else { indexOfProperty = findProperty(properties, propertyName, type); if (indexOfProperty == -1) { properties.add(new ObjectPropertyMeta(propertyName, targetType, reflectService, type, getter, setter, defineProperties)); } else { ObjectPropertyMeta meta = (ObjectPropertyMeta) properties.get(indexOfProperty); ScoredGetter compatibleGetter = GetterHelper.isCompatible(meta.getPropertyType(), type) ? getter : ScoredGetter.nullGetter(); ScoredSetter compatibleSetter = SetterHelper.isCompatible(meta.getPropertyType(), type) ? setter : ScoredSetter.nullSetter(); properties.set(indexOfProperty, meta.getterSetter(compatibleGetter, compatibleSetter, defineProperties)); } } } @Override public void field(Field field) { final String name = field.getName(); if (!Modifier.isStatic(field.getModifiers())) { if (Modifier.isPublic(field.getModifiers())) { ScoredGetter getter = ScoredGetter.ofField(field, reflectService.getObjectGetterFactory().getFieldGetter(field)); ScoredSetter setter; if (!Modifier.isFinal(field.getModifiers())) { setter = ScoredSetter.ofField(field, reflectService.getObjectSetterFactory().getFieldSetter(field)); } else { setter = ScoredSetter.nullSetter(); } register(name, field.getGenericType(), getter, setter, getDefineProperties(field)); } else { register(name, field.getGenericType(), ScoredGetter.nullGetter(), ScoredSetter.nullSetter(), getDefineProperties(field)); } } } private int findProperty(List> properties, String name, Type type) { for(int i = 0; i < properties.size(); i++) { PropertyMeta propertyMeta = properties.get(i); String propertyMetaName = propertyMeta.getName(); if (propertyMetaName != null && propertyMetaName.equals(name) && TypeHelper.isAssignable(propertyMeta.getPropertyType(), type)) { return i; } } return -1; } }); // filter out private field only; for(Iterator> it = properties.iterator(); it.hasNext();) { PropertyMeta propertyMeta = it.next(); if (NullSetter.isNull(propertyMeta.getSetter()) && NullGetter.isNull(propertyMeta.getGetter())) { it.remove(); } } return properties; } private Object[] getDefineProperties(AnnotatedElement annotatedElement) { ListCollector properties = new ListCollector(); AnnotationToPropertyService annotationToPropertyService = AnnotationToPropertyUtil.getAnnotationToPropertyService(); for(Annotation annotation : annotatedElement.getAnnotations()) { annotationToPropertyService.generateProperty(annotation, properties); } return properties.getList().toArray(); } protected String getAlias(String propertyName) { String columnName = this.fieldAliases.get(propertyName); if (columnName == null) { columnName = propertyName; } return columnName; } @Override public List getInstantiatorDefinitions() { return instantiatorDefinitions; } @Override public void forEachProperties(Consumer> consumer) { for(ConstructorPropertyMeta prop : constructorProperties) { consumer.accept(prop); } for(PropertyMeta prop : properties) { consumer.accept(prop); } } List> getProperties() { return properties; } List> getConstructorProperties() { return constructorProperties; } @Override public ReflectionService getReflectionService() { return reflectService; } @Override public PropertyFinder newPropertyFinder() { return new ObjectPropertyFinder(this, reflectService.selfScoreFullName()); } @Override public Type getType() { return target; } public int getNumberOfProperties() { return constructorProperties.size() + properties.size(); } @Override public boolean needTransformer() { return needTransformer; } public PropertyMeta getFirstProperty() { if (!constructorProperties.isEmpty()) { return constructorProperties.get(0); } if (!properties.isEmpty()) { return properties.get(0); } return null; } public static List> withReflectionService(List> props, ReflectionService reflectionService) { ArrayList> list = new ArrayList>(); for(PropertyMeta p : props) { list.add(p.withReflectionService(reflectionService)); } return list; } public static List> withReflectionServiceConstructor(List> props, ReflectionService reflectionService) { ArrayList> list = new ArrayList>(); for(ConstructorPropertyMeta p : props) { list.add(p.withReflectionService(reflectionService)); } return list; } }