簡體   English   中英

Spring AOP,Cglib增強類丟失通用信息

[英]Spring aop, cglib enhanced class lose generic info

我有一個struts 2動作類:

public class MyAction{
    private ArrayList<User> users;
    public void setUsers(ArrayList<User> users){
        this.users = users;
    }
    public String doMyAction(){
        //...
    }
}

doMyAction方法具有AOP切入點 ,因此MyAction實際上是運行時由cglib代理的類,並且users字段將由來自客戶端的json數據填充,啟用aop時,struts JSONInterceptor將無法將json數據填充至users字段。 我調試了struts json插件的源代碼,並在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 });
                        }
                    }
                }
            }
        }
    }

在這一行上:

Type[] genericTypes = method.getGenericParameterTypes();

啟用AOP時,它將根據users字段的setter方法返回java.util.ArrayList 但應使用java.util.ArrayList<User>

似乎我的動作類在由cglib代理時丟失了它的通用信息。 我還發現了一個與此有關的舊錯誤

我可以從aop配置中排除我的方法以解決此問題。 但我仍然想知道是否有更好的解決方案?

我的想法是嘗試找到代理后面的實際類型。 根據spring文檔,從spring aop獲得的任何代理都實現org.springframework.aop.framework.Advised接口,並且此接口暴露方法以查詢目標類。

Any AOP proxy obtained from Spring can be cast to this interface to allow manipulation of its AOP advice.

所以在這里我們有一個JSONPopulator選擇,我們可以下載struts json插件源代碼並構建我們自己的源代碼,並修改JSONPopulator populateObject方法

public void populateObject(Object object, final Map elements) throws IllegalAccessException,
            InvocationTargetException, NoSuchMethodException, IntrospectionException,
            IllegalArgumentException, JSONException, InstantiationException {

        Class clazz = object.getClass();

        // if it is a proxy, find the actual type behind it
        if(Advised.class.isAssignableFrom(clazz)){
            clazz = ((Advised)object).getTargetSource().getTargetClass();
        }

        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 });
                        }
                    }
                }
            }
        }
    }

請注意我添加的這些行:

 // if it is a proxy, find the actual type behind it
            if(Advised.class.isAssignableFrom(clazz)){
                clazz = ((Advised)object).getTargetSource().getTargetClass();
            }

Cglib是在泛型類型存在之前創建的。 代理在cglib中作為代理類的子類生成,該代理不保留通用類型信息。 因此,您不能從代理類中查詢它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM