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.Advisedinterface, 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
populateObjectmethod ofJSONPopulatorplease note these lines I added: