package org.simpleflatmapper.reflect;
import org.simpleflatmapper.reflect.asm.AsmFactory;
import org.simpleflatmapper.reflect.getter.FieldSetter;
import org.simpleflatmapper.reflect.setter.MethodSetter;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.reflect.setter.SetterHelper;
import org.simpleflatmapper.reflect.primitive.BooleanFieldSetter;
import org.simpleflatmapper.reflect.primitive.BooleanMethodSetter;
import org.simpleflatmapper.reflect.primitive.BooleanSetter;
import org.simpleflatmapper.reflect.primitive.ByteFieldSetter;
import org.simpleflatmapper.reflect.primitive.ByteMethodSetter;
import org.simpleflatmapper.reflect.primitive.ByteSetter;
import org.simpleflatmapper.reflect.primitive.CharacterFieldSetter;
import org.simpleflatmapper.reflect.primitive.CharacterMethodSetter;
import org.simpleflatmapper.reflect.primitive.CharacterSetter;
import org.simpleflatmapper.reflect.primitive.DoubleFieldSetter;
import org.simpleflatmapper.reflect.primitive.DoubleMethodSetter;
import org.simpleflatmapper.reflect.primitive.DoubleSetter;
import org.simpleflatmapper.reflect.primitive.FloatFieldSetter;
import org.simpleflatmapper.reflect.primitive.FloatMethodSetter;
import org.simpleflatmapper.reflect.primitive.FloatSetter;
import org.simpleflatmapper.reflect.primitive.IntFieldSetter;
import org.simpleflatmapper.reflect.primitive.IntMethodSetter;
import org.simpleflatmapper.reflect.primitive.IntSetter;
import org.simpleflatmapper.reflect.primitive.LongFieldSetter;
import org.simpleflatmapper.reflect.primitive.LongMethodSetter;
import org.simpleflatmapper.reflect.primitive.LongSetter;
import org.simpleflatmapper.reflect.primitive.ShortFieldSetter;
import org.simpleflatmapper.reflect.primitive.ShortMethodSetter;
import org.simpleflatmapper.reflect.primitive.ShortSetter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
*
*/
public final class ObjectSetterFactory {
private final AsmFactory asmFactory;
public ObjectSetterFactory(final AsmFactory asmFactory) {
this.asmFactory = asmFactory;
}
public <T, P> Setter<T, P> getSetter(final Class<? extends T> target, final String property) {
// first look for method
final Method method = lookForMethod(target, property);
final Setter<T, P> setter;
if (method == null) {
setter = getFieldSetter(target, property);
} else {
setter = getMethodSetter(method);
}
return setter;
}
public <T, P> Setter<T, P> getMethodSetter(final Method method) {
boolean accessible = Modifier.isPublic(method.getModifiers()) && Modifier.isPublic(method.getDeclaringClass().getModifiers());
if (asmFactory != null && accessible) {
try {
return asmFactory.createSetter(method);
} catch(Throwable e) {
// ignore
}
}
if (!accessible) {
method.setAccessible(true);
}
return new MethodSetter<T, P>(method);
}
public <T, P> Setter<T, P> getFieldSetter(final Class<?> target, final String property) {
// look for field
final Field field = lookForField(target, property);
if (field != null) {
return getFieldSetter(field);
} else {
return null;
}
}
public <T, P> Setter<T, P> getFieldSetter(Field field) {
boolean accessible = Modifier.isPublic(field.getModifiers()) && Modifier.isPublic(field.getDeclaringClass().getModifiers());
if (asmFactory != null && accessible) {
try {
return asmFactory.createSetter(field);
} catch(Throwable e) {
}
}
if (!accessible) {
field.setAccessible(true);
}
return new FieldSetter<T, P>(field);
}
private Method lookForMethod(final Class<?> target, final String property) {
if (target == null) return null;
for(Method m : target.getDeclaredMethods()) {
if(SetterHelper.isSetter(m)
&& SetterHelper.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(SetterHelper.fieldModifiersMatches(field.getModifiers())
&& SetterHelper.fieldNameMatchesProperty(field.getName(), property)) {
return field;
}
}
if (!Object.class.equals(target)) {
return lookForField(target.getSuperclass(), property);
}
return null;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> BooleanSetter<? super T> toBooleanSetter(final Setter<? super T, ? super Boolean> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof BooleanSetter) {
return (BooleanSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new BooleanMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new BooleanFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
private static boolean isNullSetter(Setter<?, ?> setter) {
return NullSetter.isNull(setter);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> ByteSetter<? super T> toByteSetter(final Setter<? super T, ? super Byte> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof ByteSetter) {
return (ByteSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new ByteMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new ByteFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> CharacterSetter<? super T> toCharacterSetter(final Setter<? super T, ? super Character> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof CharacterSetter) {
return (CharacterSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new CharacterMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new CharacterFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> ShortSetter<? super T> toShortSetter(final Setter<? super T, ? super Short> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof ShortSetter) {
return (ShortSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new ShortMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new ShortFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> IntSetter<? super T> toIntSetter(final Setter<? super T, ? super Integer> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof IntSetter) {
return (IntSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new IntMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new IntFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> LongSetter<? super T> toLongSetter(final Setter<? super T, ? super Long> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof LongSetter) {
return (LongSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new LongMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new LongFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> FloatSetter<? super T> toFloatSetter(final Setter<? super T, ? super Float> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof FloatSetter) {
return (FloatSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new FloatMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new FloatFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> DoubleSetter<? super T> toDoubleSetter(final Setter<? super T, ? super Double> setter) {
if (isNullSetter(setter)) {
return null;
} else if (setter instanceof DoubleSetter) {
return (DoubleSetter<? super T>) setter;
} else if (setter instanceof MethodSetter) {
return new DoubleMethodSetter<T>(((MethodSetter) setter).getMethod());
} else if (setter instanceof FieldSetter) {
return new DoubleFieldSetter<T>(((FieldSetter) setter).getField());
} else {
throw new IllegalArgumentException("Invalid type " + setter);
}
}
}