/*
* Copyright 2013 eXo Platform SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package juzu.impl.request;
import juzu.impl.common.AbstractAnnotatedElement;
import juzu.impl.plugin.controller.ControllerService;
import juzu.impl.value.ValueType;
import juzu.request.RequestParameter;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A bean control parameter.
*
* @author Julien Viet
*/
public class BeanParameter extends ControlParameter {
public BeanParameter(String name, Class<?> type) throws NullPointerException {
super(name, type);
}
public BeanParameter(String name, AnnotatedElement annotations, Class<?> type) throws NullPointerException {
super(name, annotations, type);
}
<T> T createMappedBean(ControllerService plugin, boolean requiresPrefix, Class<T> clazz, String beanName, Map<String, RequestParameter> parameters) throws IllegalAccessException, InstantiationException {
// Extract parameters
Map<String, String[]> beanParams = new HashMap<String, String[]>();
String prefix = requiresPrefix ? beanName + "." : "";
for (String key : parameters.keySet()) {
if (key.startsWith(prefix)) {
String paramName = key.substring(prefix.length());
beanParams.put(paramName, parameters.get(key).toArray());
}
}
// Build bean
T bean = clazz.newInstance();
for (String key : beanParams.keySet()) {
String[] value = beanParams.get(key);
String setterName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1);
try {
boolean success = callSetter(plugin, setterName, clazz, bean, value);
if (!success) {
Field f = clazz.getField(key);
Object o = getValue(plugin, f, f.getGenericType(), value);
if (o != null) {
f.set(bean, o);
}
}
}
catch (Exception e) {
// Do something better
}
}
return bean;
}
Object getValue(ControllerService plugin, AnnotatedElement annotated, Type type, String[] value) throws Exception {
if (type instanceof Class<?>) {
Class<?> clazz = (Class<?>)type;
if (clazz.isArray()) {
clazz = clazz.getComponentType();
ValueType valueType = plugin.resolveValueType(clazz);
if (valueType != null) {
Object array = Array.newInstance(clazz, value.length);
for (int i = 0;i < value.length;i++) {
Array.set(array, i, valueType.parse(annotated, value[i]));
}
return array;
}
} else {
ValueType valueType = plugin.resolveValueType(clazz);
if (valueType != null) {
return valueType.parse(annotated, value[0]);
}
}
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type;
if (List.class.equals(parameterizedType.getRawType())) {
Type typeArg = parameterizedType.getActualTypeArguments()[0];
if (typeArg instanceof Class) {
ValueType valueType = plugin.resolveValueType((Class)typeArg);
if (valueType != null) {
ArrayList list = new ArrayList(value.length);
for (String s : value) {
list.add(valueType.parse(annotated, s));
}
return list;
}
}
}
}
return null;
}
<T> boolean callSetter(ControllerService plugin, String methodName, Class<T> clazz, T target, String[] value) throws Exception {
for (final java.lang.reflect.Method m : clazz.getMethods()) {
if (m.getName().equals(methodName)) {
int modifiers = m.getModifiers();
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
Type[] parameterTypes = m.getGenericParameterTypes();
if (parameterTypes.length == 1) {
AbstractAnnotatedElement element = new AbstractAnnotatedElement() {
@Override
public Annotation[] getDeclaredAnnotations() {
return m.getParameterAnnotations()[0];
}
};
Object o = getValue(plugin, element, parameterTypes[0], value);
if (o != null) {
m.invoke(target, o);
return true;
}
}
}
}
}
return false;
}
Map<String, String[]> buildBeanParameter(ControllerService plugin, boolean requiresPrefix, String baseName, Object value) {
Map<String, String[]> parameters = new HashMap<String, String[]>();
try {
for (Field f : value.getClass().getFields()) {
if (Modifier.isPublic(f.getModifiers())) {
Object v = f.get(value);
if (v != null) {
String name = requiresPrefix ? baseName + "." + f.getName() : f.getName();
addParameter(plugin, parameters, name, f, f.getGenericType(), v);
}
}
}
for (java.lang.reflect.Method m : value.getClass().getMethods()) {
if (Modifier.isPublic(m.getModifiers()) && !Modifier.isStatic(m.getModifiers()) && m.getName().startsWith("get") && m.getName().length() > 3 && m.getParameterTypes().length == 0) {
Object v = m.invoke(value);
if (v != null) {
String n = Character.toLowerCase(m.getName().charAt(3)) + m.getName().substring(4);
String name = requiresPrefix ? baseName + "." + n : n;
addParameter(plugin, parameters, name, m, m.getGenericReturnType(), v);
}
}
}
}
catch (Exception e) {
}
return parameters;
}
private void addParameter(ControllerService plugin, Map<String, String[]> parameters, String name, AnnotatedElement annotated, Type type, Object value) {
String[] v = getParameters(plugin, annotated, type, value);
if (v != null) {
parameters.put(name, v);
}
}
private String[] getParameters(ControllerService plugin, AnnotatedElement annotated, Type type, Object value) {
if (type instanceof Class) {
Class clazz = (Class)type;
if (clazz.isArray()) {
clazz = clazz.getComponentType();
int length = Array.getLength(value);
if (length > 0) {
ValueType valueType = plugin.resolveValueType(clazz);
if (valueType != null) {
String[] ret = new String[length];
for (int i = 0;i < length;i++) {
Object element = Array.get(value, i);
ret[i] = valueType.format(annotated, element);
}
return ret;
}
}
} else {
ValueType valueType = plugin.resolveValueType(clazz);
if (valueType != null) {
return new String[]{valueType.format(annotated, value)};
}
}
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type;
if (parameterizedType.getRawType().equals(List.class)) {
List list = (List)value;
int size = list.size();
if (size > 0) {
Type typeArg = parameterizedType.getActualTypeArguments()[0];
if (typeArg instanceof Class) {
ValueType valueType = plugin.resolveValueType((Class)typeArg);
if (valueType != null) {
String[] ret = new String[size];
for (int i = 0;i < size;i++) {
Object element = list.get(i);
ret[i] = valueType.format(annotated, element);
}
return ret;
}
}
}
}
}
return null;
}
}