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.EmptyStaticMethodInstantiator;
import org.sfm.reflect.impl.InjectConstructorInstantiator;
import org.sfm.reflect.impl.EmptyConstructorInstantiator;
import org.sfm.reflect.impl.InjectStaticMethodInstantiator;
import org.sfm.utils.ForEachCallBack;

import java.lang.reflect.*;
import java.util.HashMap;
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(), propertyMapping.getColumnDefinition());
                }
            }).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().getEligibleInstantiatorDefinitions(), constructorParameterGetterMap,useAsmIfEnabled);
		}
	}

	@SuppressWarnings("unchecked")
	public  Instantiator getInstantiator(Type target, final Class source, List constructors, Map> injections, boolean useAsmIfEnabled) throws SecurityException {
		final InstantiatorDefinition instantiatorDefinition = getSmallerConstructor(constructors);

		if (instantiatorDefinition == null) {
			throw new IllegalArgumentException("No constructor available for " + target);
		}
		return newInstantiator(source, injections, useAsmIfEnabled, instantiatorDefinition);


	}

	@SuppressWarnings("unchecked")
	private  Instantiator newInstantiator(Class source, Map> injections, boolean useAsmIfEnabled, InstantiatorDefinition instantiatorDefinition) {
		Member executable = instantiatorDefinition.getExecutable();

		if (asmFactory != null && Modifier.isPublic(executable.getModifiers()) && useAsmIfEnabled) {
			try {
				return asmFactory.createInstantiator(source, instantiatorDefinition, injections);
			} catch (Exception e) {
				// fall back on reflection
			}
		}

		if (executable instanceof Constructor) {
			Constructor c = (Constructor) executable;
			if (c.getParameterTypes().length == 0) {
				return new EmptyConstructorInstantiator(c);
			} else {
				return new InjectConstructorInstantiator(instantiatorDefinition, injections);
			}
		} else if (executable instanceof Method){
			Method m = (Method) executable;
			if (m.getParameterTypes().length == 0) {
				return new EmptyStaticMethodInstantiator(m);
			} else {
				return new InjectStaticMethodInstantiator(instantiatorDefinition, injections);
			}

		} else {
			throw new IllegalArgumentException("Unsupported executable type " + executable);
		}
	}

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

		InstantiatorDefinition selectedConstructor = null;
		
		for(InstantiatorDefinition c : constructors) {
			if (selectedConstructor == null || c.compareTo(selectedConstructor) < 0) {
				selectedConstructor = c;
			}
		}
		
		return selectedConstructor;
	}

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

	@SuppressWarnings("unchecked")
	public  Instantiator getOneArgIdentityInstantiator(InstantiatorDefinition id) {
		Map> injections = new HashMap>();
		injections.put(id.getParameters()[0], new IdentityGetter());
		return newInstantiator(id.getParameters()[0].getType(), injections, true, id);
	}


	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