All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
play.data.binding.BeanWrapper Maven / Gradle / Ivy
package play.data.binding;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import play.Logger;
import play.classloading.enhancers.PropertiesEnhancer.PlayPropertyAccessor;
import play.exceptions.UnexpectedException;
import play.utils.Utils;
/**
* Parameters map to POJO binder.
*/
public class BeanWrapper {
final static int notwritableField = Modifier.FINAL | Modifier.NATIVE | Modifier.STATIC;
final static int notaccessibleMethod = Modifier.NATIVE | Modifier.STATIC;
private Class> beanClass;
/**
* a cache for our properties and setters
*/
private Map wrappers = new HashMap();
public BeanWrapper(Class> forClass) {
if (Logger.isTraceEnabled()) {
Logger.trace("Bean wrapper for class %s", forClass.getName());
}
this.beanClass = forClass;
boolean isScala = false;
for (Class> intf : forClass.getInterfaces()) {
if ("scala.ScalaObject".equals(intf.getName())) {
isScala = true;
break;
}
}
registerSetters(forClass, isScala);
if(isScala) {
registerAllFields(forClass);
} else {
registerFields(forClass);
}
}
public Collection getWrappers() {
return wrappers.values();
}
public void set(String name, Object instance, Object value) {
for (Property prop : wrappers.values()) {
if (name.equals(prop.name)) {
prop.setValue(instance, value);
return;
}
}
String message = String.format("Can't find property with name '%s' on class %s", name, instance.getClass().getName());
Logger.warn(message);
throw new UnexpectedException(message);
}
private boolean isSetter(Method method) {
return (!method.isAnnotationPresent(PlayPropertyAccessor.class) && method.getName().startsWith("set") && method.getName().length() > 3 && method.getParameterTypes().length == 1 && (method.getModifiers() & notaccessibleMethod) == 0);
}
private boolean isScalaSetter(Method method) {
return (!method.isAnnotationPresent(PlayPropertyAccessor.class) && method.getName().endsWith("_$eq") && method.getParameterTypes().length == 1 && (method.getModifiers() & notaccessibleMethod) == 0);
}
protected Object newBeanInstance() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Constructor constructor = beanClass.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
}
private void registerFields(Class> clazz) {
// recursive stop condition
if (clazz == Object.class) {
return;
}
Field[] fields = clazz.getFields();
for (Field field : fields) {
if (wrappers.containsKey(field.getName())) {
continue;
}
if ((field.getModifiers() & notwritableField) != 0) {
continue;
}
Property w = new Property(field);
wrappers.put(field.getName(), w);
}
registerFields(clazz.getSuperclass());
}
private void registerAllFields(Class> clazz) {
// recursive stop condition
if (clazz == Object.class) {
return;
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (wrappers.containsKey(field.getName())) {
continue;
}
/*if ((field.getModifiers() & notwritableField) != 0) {
continue;
}*/
field.setAccessible(true);
Property w = new Property(field);
wrappers.put(field.getName(), w);
}
registerAllFields(clazz.getSuperclass());
}
private void registerSetters(Class> clazz, boolean isScala) {
if (clazz == Object.class) {
return;
// deep walk (superclass first)
}
registerSetters(clazz.getSuperclass(), isScala);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String propertyname;
if (isScala) {
if (!isScalaSetter(method)) {
continue;
}
propertyname = method.getName().substring(0, method.getName().length() - 4);
} else {
if (!isSetter(method)) {
continue;
}
propertyname = method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4);
}
Property wrapper = new Property(propertyname, method);
wrappers.put(propertyname, wrapper);
}
}
public static class Property {
private Annotation[] annotations;
private Method setter;
private Field field;
private Class> type;
private Type genericType;
private String name;
private String[] profiles;
Property(String propertyName, Method setterMethod) {
name = propertyName;
setter = setterMethod;
type = setter.getParameterTypes()[0];
annotations = setter.getAnnotations();
genericType = setter.getGenericParameterTypes()[0];
setProfiles(this.annotations);
}
Property(Field field) {
this.field = field;
this.field.setAccessible(true);
name = field.getName();
type = field.getType();
annotations = field.getAnnotations();
genericType = field.getGenericType();
setProfiles(this.annotations);
}
public void setProfiles(Annotation[] annotations) {
if (annotations != null) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(NoBinding.class)) {
NoBinding as = ((NoBinding) annotation);
profiles = as.value();
}
}
}
}
public void setValue(Object instance, Object value) {
try {
if (setter != null) {
if (Logger.isTraceEnabled()) {
Logger.trace("invoke setter %s on %s with value %s", setter, instance, value);
}
setter.invoke(instance, value);
return;
} else {
if (Logger.isTraceEnabled()) {
Logger.trace("field.set(%s, %s)", instance, value);
}
field.set(instance, value);
}
} catch (Exception ex) {
Logger.warn(ex, "ERROR in BeanWrapper when setting property %s value is %s (%s)", name, value, value == null ? null : value.getClass());
throw new UnexpectedException(ex);
}
}
String getName() {
return name;
}
Class> getType() {
return type;
}
Type getGenericType() {
return genericType;
}
Annotation[] getAnnotations() {
return annotations;
}
@Override
public String toString() {
return type + "." + name;
}
}
public Object bind(String name, Type type, Map params, String prefix, Annotation[] annotations) throws Exception {
Object instance = newBeanInstance();
return bind(name, type, params, prefix, instance, annotations);
}
public Object bind(String name, Type type, Map params, String prefix, Object instance, Annotation[] annotations) throws Exception {
RootParamNode paramNode = RootParamNode.convert( params);
// when looking at the old code in BeanBinder and Binder.bindInternal, I
// think it is correct to use 'name+prefix'
Binder.bindBean( paramNode.getChild(name+prefix), instance, annotations);
return instance;
}
}