package org.simpleflatmapper.reflect;
import org.simpleflatmapper.reflect.asm.AsmFactory;
import org.simpleflatmapper.reflect.getter.FieldGetter;
import org.simpleflatmapper.reflect.getter.MethodGetter;
import org.simpleflatmapper.reflect.getter.GetterHelper;
import org.simpleflatmapper.reflect.primitive.BooleanGetter;
import org.simpleflatmapper.reflect.primitive.BoxedBooleanGetter;
import org.simpleflatmapper.reflect.primitive.BoxedByteGetter;
import org.simpleflatmapper.reflect.primitive.BoxedCharacterGetter;
import org.simpleflatmapper.reflect.primitive.BoxedDoubleGetter;
import org.simpleflatmapper.reflect.primitive.BoxedFloatGetter;
import org.simpleflatmapper.reflect.primitive.BoxedIntGetter;
import org.simpleflatmapper.reflect.primitive.BoxedLongGetter;
import org.simpleflatmapper.reflect.primitive.BoxedShortGetter;
import org.simpleflatmapper.reflect.primitive.ByteGetter;
import org.simpleflatmapper.reflect.primitive.CharacterGetter;
import org.simpleflatmapper.reflect.primitive.DoubleGetter;
import org.simpleflatmapper.reflect.primitive.FloatGetter;
import org.simpleflatmapper.reflect.primitive.IntGetter;
import org.simpleflatmapper.reflect.primitive.LongGetter;
import org.simpleflatmapper.reflect.primitive.ShortGetter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
*
*/
public final class ObjectGetterFactory {
private final AsmFactory asmFactory;
public ObjectGetterFactory(AsmFactory asmFactory) {
this.asmFactory = asmFactory;
}
public <T, P> Getter<T, P> getGetter(final Class<? super T> target, final String property) {
// first look for method
final Method method = lookForMethod(target, property);
final Getter<T, P> getter;
if (method == null) {
getter = getFieldGetter(target, property);
} else {
getter = getMethodGetter(method);
}
return getter;
}
public <T, P> Getter<T, P> getMethodGetter(final Method method) {
boolean accessible = Modifier.isPublic(method.getModifiers()) && Modifier.isPublic(method.getDeclaringClass().getModifiers());
if (asmFactory != null && accessible) {
try {
return asmFactory.createGetter(method);
} catch(Throwable e) {
// ignore
}
}
if (!accessible) {
method.setAccessible(true);
}
return new MethodGetter<T, P>(method);
}
public <T, P> Getter<T, P> getFieldGetter(final Class<?> target, final String property) {
// look for field
final Field field = lookForField(target, property);
if (field != null) {
return getFieldGetter(field);
} else {
return null;
}
}
public <T, P> Getter<T, P> getFieldGetter(Field field) {
boolean accessible = Modifier.isPublic(field.getModifiers()) && Modifier.isPublic(field.getDeclaringClass().getModifiers());
if (asmFactory != null && accessible) {
try {
return asmFactory.createGetter(field);
} catch(Throwable e) {}
}
if (!accessible) {
field.setAccessible(true);
}
return new FieldGetter<T, P>(field);
}
private Method lookForMethod(final Class<?> target, final String property) {
if (target == null) return null;
for(Method m : target.getDeclaredMethods()) {
if(GetterHelper.isPublicMember(m.getModifiers())
&& GetterHelper.methodNameMatchesProperty(m.getName(), property)) {
return m;
}
}
if (!Object.class.equals(target)) {
return lookForMethod(target.getSuperclass(), property);
}
return null;
}
private Field lookForField(final Class<?> target, final String property) {
if (target == null) return null;
for(Field field : target.getDeclaredFields()) {
if(GetterHelper.fieldModifiersMatches(field.getModifiers())
&& GetterHelper.fieldNameMatchesProperty(field.getName(), property)) {
return field;
}
}
return lookForField(target.getSuperclass(), property);
}
@SuppressWarnings("unchecked")
public static <T> BooleanGetter<T> toBooleanGetter(final Getter<T, ? extends Boolean> getter) {
if (getter instanceof BooleanGetter) {
return (BooleanGetter<T>) getter;
} else {
return new BoxedBooleanGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> IntGetter<T> toIntGetter(Getter<T, ? extends Integer> getter) {
if (getter instanceof IntGetter) {
return (IntGetter<T>) getter;
} else {
return new BoxedIntGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> LongGetter<T> toLongGetter(Getter<T, ? extends Long> getter) {
if (getter instanceof LongGetter) {
return (LongGetter<T>) getter;
} else {
return new BoxedLongGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> FloatGetter<T> toFloatGetter(Getter<T, ? extends Float> getter) {
if (getter instanceof FloatGetter) {
return (FloatGetter<T>) getter;
} else {
return new BoxedFloatGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> DoubleGetter<T> toDoubleGetter(Getter<T, ? extends Double> getter) {
if (getter instanceof DoubleGetter) {
return (DoubleGetter<T>) getter;
} else {
return new BoxedDoubleGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> ByteGetter<T> toByteGetter(Getter<T, ? extends Byte> getter) {
if (getter instanceof ByteGetter) {
return (ByteGetter<T>) getter;
} else {
return new BoxedByteGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> ShortGetter<T> toShortGetter(Getter<T, ? extends Short> getter) {
if (getter instanceof ShortGetter) {
return (ShortGetter<T>) getter;
} else {
return new BoxedShortGetter<T>(getter);
}
}
@SuppressWarnings("unchecked")
public static <T> CharacterGetter<T> toCharGetter(Getter<T, ? extends Character> getter) {
if (getter instanceof CharacterGetter) {
return (CharacterGetter<T>) getter;
} else {
return new BoxedCharacterGetter<T>(getter);
}
}
}