/*
* Copyright (C) 2014 Civilian Framework.
*
* Licensed under the Civilian License (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.civilian-framework.org/license.txt
*
* 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 org.civilian.internal.controller.arg.misc;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import org.civilian.Request;
import org.civilian.controller.MethodArgFactory;
import org.civilian.controller.MethodArg;
public class BeanParamArg extends MethodArg
{
public BeanParamArg(MethodArgFactory factory, Class<?> beanClass) throws Exception
{
beanClass_ = beanClass;
Init init = new Init(factory);
// 1. use bean setters
BeanInfo info = Introspector.getBeanInfo(beanClass);
for (PropertyDescriptor pd : info.getPropertyDescriptors())
init.addSetter(pd.getWriteMethod(), pd.getName());
// 2. use public methods
for (Method method : beanClass.getMethods())
init.addSetter(method, null);
// 3. use public fields
for (Field field : beanClass.getFields())
init.addSetter(field);
setters_ = init.getSetters();
}
@Override public Object getValue(Request request) throws Exception
{
Object bean = beanClass_.newInstance();
for (Setter setter : setters_)
setter.injectParam(request, bean);
return bean;
}
private static abstract class Setter
{
public Setter(MethodArg arg)
{
arg_ = arg;
}
public void injectParam(Request request, Object bean) throws Exception
{
Object value = arg_.getValue(request);
try
{
inject(value, bean);
}
catch(Exception e)
{
throw new IllegalArgumentException("error when injecting value " + value + " from " + arg_ + " into " + this, e);
}
}
public abstract void inject(Object value, Object bean) throws Exception;
@Override public abstract String toString();
private MethodArg arg_;
}
private static class MethodSetter extends Setter
{
public MethodSetter(MethodArg arg, Method method)
{
super(arg);
method_ = method;
}
@Override public void inject(Object value, Object bean) throws Exception
{
method_.invoke(bean, value);
}
@Override public String toString()
{
return method_.toString();
}
private Method method_;
}
private static class FieldSetter extends Setter
{
public FieldSetter(MethodArg arg, Field field)
{
super(arg);
field_ = field;
if (!Modifier.isPublic(field_.getModifiers()))
field_.setAccessible(true);
}
@Override public void inject(Object value, Object bean) throws Exception
{
field_.set(bean, value);
}
@Override public String toString()
{
return field_.toString();
}
private Field field_;
}
private static class Init
{
public Init(MethodArgFactory factory)
{
factory_ = factory;
}
public Setter[] getSetters()
{
return setters_.toArray(new Setter[setters_.size()]);
}
public void addSetter(Method method, String propertyName)
{
if (method != null)
{
MethodArg arg = factory_.createSetterMethodArg(method, propertyName, false);
if (arg != null)
add(new MethodSetter(arg, method), method.toString());
}
}
public void addSetter(Field field)
{
if (field != null)
{
MethodArg arg = factory_.createFieldArg(field, false);
if (arg != null)
add(new FieldSetter(arg, field), field.toString());
}
}
private void add(Setter setter, String key)
{
if (!done_.contains(key))
{
done_.add(key);
setters_.add(setter);
}
}
private MethodArgFactory factory_;
private ArrayList<Setter> setters_ = new ArrayList<>();
private HashSet<String> done_ = new HashSet<>();
}
private Class<?> beanClass_;
private Setter[] setters_;
}