package org.webpieces.router.impl.params;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.function.BiFunction;
import org.webpieces.util.logging.Logger;
import org.webpieces.util.logging.LoggerFactory;
public class FieldMeta implements Meta {
private static final Logger log = LoggerFactory.getLogger(FieldMeta.class);
private Field field;
public FieldMeta(Field field) {
this.field = field;
}
@Override
public Type getParameterizedType() {
return field.getGenericType();
}
@Override
public Class<?> getFieldClass() {
return field.getType();
}
public void setValueOnBean(Object bean, Object translatedValue) {
BiFunction<Object, Object, Void> applyBeanValueFunction = createFunction(bean.getClass(), field);
//skip setting to null if it is a primitive(allow setting null on a String
if(translatedValue != null)
applyBeanValueFunction.apply(bean, translatedValue);
else if(!getFieldClass().isPrimitive())
applyBeanValueFunction.apply(bean, translatedValue);
}
private BiFunction<Object, Object, Void> createFunction(Class<? extends Object> beanClass, Field field) {
String key = field.getName();
String cap = key.substring(0, 1).toUpperCase() + key.substring(1);
String methodName = "set"+cap;
//What is slower....throwing exceptions or looping over methods to not through exception?....
try {
Method method = beanClass.getMethod(methodName, field.getType());
return (bean, val) -> invokeMethod(method, bean, val);
} catch (NoSuchMethodException e) {
log.warn("performance penalty since method="+methodName+" does not exist on class="+beanClass.getName()+" using field instead to set data");
return (bean, val) -> setField(field, bean, val);
} catch (SecurityException e) {
throw new RuntimeException(e);
}
}
private Void setField(Field field, Object bean, Object val) {
field.setAccessible(true);
try {
field.set(bean, val);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return null;
}
private Void invokeMethod(Method method, Object bean, Object val) {
try {
method.invoke(bean, val);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return null;
}
@Override
public String toString() {
return "FieldMeta [field=" + field + "]";
}
@Override
public void validateNullValue() {
//by default fields are nullable(not required) UNLESS @Required annotation
//is used
throw new UnsupportedOperationException("need to implement/test");
}
}