I have a struts 2 action class:
public class MyAction{
private ArrayList<User> users;
public void setUsers(ArrayList<User> users){
this.users = users;
}
public String doMyAction(){
//...
}
}
the doMyAction method has a AOP pointcut, so MyAction
is actually a cglib proxied class at runtime, and the users
field will be populated by json data from client, when aop is enabled, struts JSONInterceptor
will fail to populate json data into users
field. I debuged with the source code of struts json plugin and found this in org.apache.struts2.json.JSONPopulator:
public void populateObject(Object object, final Map elements)
throws IllegalAccessException,
InvocationTargetException, NoSuchMethodException, IntrospectionException,
IllegalArgumentException, JSONException, InstantiationException {
Class clazz = object.getClass();
BeanInfo info = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] props = info.getPropertyDescriptors();
// iterate over class fields
for (int i = 0; i < props.length; ++i) {
PropertyDescriptor prop = props[i];
String name = prop.getName();
if (elements.containsKey(name)) {
Object value = elements.get(name);
Method method = prop.getWriteMethod();
if (method != null) {
JSON json = method.getAnnotation(JSON.class);
if ((json != null) && !json.deserialize()) {
continue;
}
// use only public setters
if (Modifier.isPublic(method.getModifiers())) {
Class[] paramTypes = method.getParameterTypes();
Type[] genericTypes = method.getGenericParameterTypes();
if (paramTypes.length == 1) {
Object convertedValue = this.convert(paramTypes[0],
genericTypes[0], value, method);
method.invoke(object, new Object[] { convertedValue });
}
}
}
}
}
}
and on this line:
Type[] genericTypes = method.getGenericParameterTypes();
when AOP is enabled, it returns java.util.ArrayList
against the setter method of users
field. but java.util.ArrayList<User>
expected.
It seems that my action class lose it's generic info when proxied by cglib. I also found a old bug about this.
I can exclude my method from aop configurations to fix this. but I still want to know if there is a better solution?
My idea is try to find the actual type behind the proxy. According to spring documentation, any proxy obtained from spring aop implements the
org.springframework.aop.framework.Advised
interface, and this interface expose method to query the target class.so here we have a considerable option, we can download the struts json plugin source code and build our own one, with modification on
populateObject
method ofJSONPopulator
please note these lines I added: