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

org.sfm.reflect.InstantiatorFactory 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: 1.10.3
Show newest version
package org.sfm.reflect;

import org.sfm.map.ColumnDefinition;
import org.sfm.map.impl.CalculateMaxIndex;
import org.sfm.map.FieldKey;
import org.sfm.map.impl.PropertyMapping;
import org.sfm.map.impl.PropertyMappingsBuilder;
import org.sfm.reflect.asm.AsmFactory;
import org.sfm.reflect.impl.InjectConstructorInstantiator;
import org.sfm.reflect.impl.StaticConstructorInstantiator;
import org.sfm.utils.ForEachCallBack;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class InstantiatorFactory {
	private static final Object[] EMPTY_ARGS = new Object[]{};

	private final AsmFactory asmFactory;
	
	public InstantiatorFactory(final AsmFactory asmFactory) {
		this.asmFactory = asmFactory;
	}


	public , D extends ColumnDefinition> Instantiator getInstantiator(Type source, Type target, PropertyMappingsBuilder propertyMappingsBuilder, Map> constructorParameterGetterMap, org.sfm.map.GetterFactory getterFactory) throws NoSuchMethodException {
		return  getInstantiator(source, target, propertyMappingsBuilder, constructorParameterGetterMap, getterFactory, true);
	}

	@SuppressWarnings("unchecked")
    public , D extends ColumnDefinition> Instantiator getInstantiator(Type source, Type target, PropertyMappingsBuilder propertyMappingsBuilder, Map> constructorParameterGetterMap, final org.sfm.map.GetterFactory getterFactory,  boolean useAsmIfEnabled) throws NoSuchMethodException {

        if (propertyMappingsBuilder.isDirectProperty()) {
            Getter getter = propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() {
                public Getter getter;
                @Override
                public void handle(PropertyMapping propertyMapping) {
                    getter = getterFactory.newGetter(propertyMapping.getPropertyMeta().getType(), propertyMapping.getColumnKey());
                }
            }).getter;

            return new GetterInstantiator(getter);

        }

		if (TypeHelper.isArray(target)) {
			return getArrayInstantiator(TypeHelper.toClass(TypeHelper.getComponentType(target)), propertyMappingsBuilder.forEachProperties(new CalculateMaxIndex()).maxIndex + 1);
		} else {
			return getInstantiator(target, TypeHelper.toClass(source), propertyMappingsBuilder.getPropertyFinder().getEligibleConstructorDefinitions(), constructorParameterGetterMap,useAsmIfEnabled);
		}
	}

	public  Instantiator getInstantiator(Type target, final Class source, List> constructors, Map> injections, boolean useAsmIfEnabled) throws SecurityException {
		final ConstructorDefinition constructorDefinition = getSmallerConstructor(constructors);

		if (constructorDefinition == null) {
			throw new IllegalArgumentException("No constructor available for " + target);
		}
		Constructor constructor = constructorDefinition.getConstructor();
		
		if (asmFactory != null && Modifier.isPublic(constructor.getModifiers()) && useAsmIfEnabled) {
			try {
				return asmFactory.createInstantiator(source, constructorDefinition, injections);
			} catch (Exception e) {
				// fall back on reflection
			}
		}
		
		constructor.setAccessible(true);
		
		if (constructor.getParameterTypes().length == 0) {
			return new StaticConstructorInstantiator(constructor, EMPTY_ARGS); 
		} else {
			return new InjectConstructorInstantiator(constructorDefinition, injections);
		}
	}

	private  ConstructorDefinition getSmallerConstructor(final List> constructors) {
        if (constructors == null) {
            return null;
        }

		ConstructorDefinition selectedConstructor = null;
		
		for(ConstructorDefinition c : constructors) {
			if (selectedConstructor == null || (c.getParameters().length < selectedConstructor.getParameters().length)) {
				selectedConstructor = c;
			}
		}
		
		return selectedConstructor;
	}

	public  Instantiator getArrayInstantiator(final Class elementType, final int length) {
		return new ArrayInstantiator(elementType, length);
	}



	private static final class ArrayInstantiator implements Instantiator {
		private final Class elementType;
		private final int length;

		public ArrayInstantiator(Class elementType, int length) {
			this.elementType = elementType;
			this.length = length;
		}

		@SuppressWarnings("unchecked")
        @Override
        public T newInstance(S s) throws Exception {
            return (T) Array.newInstance(elementType, length);
        }
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy