package org.simpleflatmapper.reflect.meta; import org.simpleflatmapper.reflect.instantiator.ExecutableInstantiatorDefinition; import org.simpleflatmapper.reflect.Getter; import org.simpleflatmapper.reflect.InstantiatorDefinition; import org.simpleflatmapper.reflect.ReflectionService; import org.simpleflatmapper.reflect.ScoredGetter; import org.simpleflatmapper.reflect.ScoredSetter; import org.simpleflatmapper.reflect.Setter; import org.simpleflatmapper.reflect.getter.GetterHelper; import org.simpleflatmapper.util.Consumer; import org.simpleflatmapper.util.ErrorHelper; import org.simpleflatmapper.util.Predicate; import org.simpleflatmapper.util.TypeHelper; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class FastTupleClassMeta<T> implements ClassMeta<T> { private final ClassMeta<T> delegate; private final List<InstantiatorDefinition> instantiatorDefinitions; public FastTupleClassMeta(Type target, ReflectionService reflectionService) { try { Class<T> clazz = TypeHelper.toClass(target); instantiatorDefinitions = new ArrayList<InstantiatorDefinition>(); instantiatorDefinitions.add(new ExecutableInstantiatorDefinition(clazz.getConstructor())); final List<PropertyMeta<T, ?>> properties = getPropertyMetas(target, reflectionService); this.delegate = new ObjectClassMeta<T>( target, instantiatorDefinitions, Collections.<ConstructorPropertyMeta<T, ?>>emptyList(), Collections.<String, String>emptyMap(), properties, reflectionService); } catch (NoSuchMethodException e) { ErrorHelper.rethrow(e); throw new IllegalStateException(); } } private static <T> ArrayList<PropertyMeta<T, ?>> getPropertyMetas(Type ownerType, ReflectionService reflectionService) throws NoSuchMethodException { final ArrayList<PropertyMeta<T, ?>> propertyMetas = new ArrayList<PropertyMeta<T, ?>>(); Class<?> clazz = TypeHelper.toClass(ownerType); if (isDirect(clazz)) { for(Method m : clazz.getDeclaredMethods()) { if (m.getParameterTypes().length == 0 && GetterHelper.isPublicMember(m.getModifiers())) { String field = m.getName(); Method setter = clazz.getDeclaredMethod(field, m.getReturnType()); ObjectPropertyMeta<T, ?> propertyMeta = newPropertyMethod(field, m, setter, reflectionService, ownerType); propertyMetas.add(propertyMeta); } } } else { for (Field f : clazz.getDeclaredFields()) { String field = f.getName(); try { Method getter = clazz.getDeclaredMethod(field); Method setter = clazz.getDeclaredMethod(field, f.getType()); ObjectPropertyMeta<T, ?> propertyMeta = newPropertyMethod(field, getter, setter, reflectionService, ownerType); propertyMetas.add(propertyMeta); } catch (NoSuchMethodException e) { // field has no getter/setter ignore. } } } return propertyMetas; } private static boolean isDirect(Class<?> clazz) { try { Field unsafe = clazz.getDeclaredField("unsafe"); int m = unsafe.getModifiers(); return Modifier.isStatic(m); } catch (NoSuchFieldException e) { return false; } } private static <T, P> ObjectPropertyMeta<T, P> newPropertyMethod(String field, Method getter, Method setter, ReflectionService reflectionService, Type ownerType) { Getter<T, P> methodGetter = reflectionService.getObjectGetterFactory().getMethodGetter(getter); Setter<T, P> methodSetter = reflectionService.getObjectSetterFactory().getMethodSetter(setter); return new ObjectPropertyMeta<T, P>(field, ownerType, reflectionService, getter.getGenericReturnType(), ScoredGetter.of(methodGetter, 1), ScoredSetter.of(methodSetter, 1), null); } @Override public ReflectionService getReflectionService() { return delegate.getReflectionService(); } @Override public PropertyFinder<T> newPropertyFinder(Predicate<PropertyMeta<?, ?>> propertyFilter) { return delegate.newPropertyFinder(propertyFilter); } @Override public Type getType() { return delegate.getType(); } @Override public List<InstantiatorDefinition> getInstantiatorDefinitions() { return instantiatorDefinitions; } @Override public void forEachProperties(Consumer<? super PropertyMeta<T, ?>> consumer) { delegate.forEachProperties(consumer); } }