"person.username.firstname"类型参数字符串自动组装成对象的原理

在使用Struts2、WebWork框架开发Web应用时,JSP页中的表单项,常常会使用这样的参数名:

<input type="text" name="person.username" />
<input type="password" name="person.password" />

 

甚至,可以有更多层次的,如:

<input type="text" name="person.username.firstname" />
<input type="text" name="person.username.lastname" />

 
上面第一例,在后端Java代码中,自然有一个Person类与之对应。其中,这个Person类包含2个属性:username, password,还有必要的Setter和Getter方法。
上面第二例,同样有一个Person类与之相对应,而Person类中包括了一个Username类型的属性"username";而在Username类里,有firstname和lastname两个属性。同样,相应的Setter和Getter方法是必不可少的。
那么,那些框架是怎么自动将型如"person.username.firstname"的字符串,组装成相应的对象(如Person对象)的呢?
请看以下代码:

/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package com.opensymphony.provider.bean;

import com.opensymphony.provider.BeanProvider;
import com.opensymphony.provider.ProviderConfigurationException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.StringTokenizer;


/**
 * BeanProvider implementation for accessing properties.
 *
 * Can handle a.b.c.d -> getA().getB().getC().getD().
 * Access properties in this order: bean.getA(), bean.isA(), bean.a(), bean.a.
 *
 * Can also deal with setter methods.
 *
 * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
 * @version $Revision: 1.1.1.1 $
 */
public class DefaultBeanProvider implements BeanProvider {
    //~ Static fields/initializers /

    private static String GET = "get";
    private static String SET = "set";
    private static String IS = "is";

    //~ Methods 

    public boolean setProperty(Object object, String property, Object value) {
        if ((property == null) || (object == null)) {
            return false;
        }

        // Split out property on dots ( "person.name.first" -> "person","name","first" -> getPerson().getName().getFirst() )
        StringTokenizer st = new StringTokenizer(property, ".");

        if (st.countTokens() == 0) {
            return false;
        }

        // Holder for Object at current depth along chain.
        Object current = object;

        try {
            // Loop through properties in chain.
            for (int i = 0; st.hasMoreTokens(); i++) {
                String currentPropertyName = st.nextToken();

                if (i < st.countTokens()) {
                    // This is a getter
                    current = invokeProperty(current, currentPropertyName);
                } else {
                    // Final property in chain, hence setter
                    try {
                        // Call setter
                        Class cls = current.getClass();
                        PropertyDescriptor pd = new PropertyDescriptor(currentPropertyName, current.getClass());
                        pd.getWriteMethod().invoke(current, new Object[] {value});

                        return true;
                    } catch (Exception e) {
                        return false;
                    }
                }
            }

            // Return holder Object
            return true;
        } catch (NullPointerException e) {
            // It is very likely that one of the properties returned null. If so, catch the exception and return null.
            return false;
        }
    }

    public Object getProperty(Object object, String property) {
        if ((property == null) || (object == null)) {
            return null;
        }

        // Split out property on dots ( "person.name.first" -> "person","name","first" -> getPerson().getName().getFirst() )
        StringTokenizer st = new StringTokenizer(property, ".");

        if (st.countTokens() == 0) {
            return null;
        }

        // Holder for Object at current depth along chain.
        Object result = object;

        try {
            // Loop through properties in chain.
            while (st.hasMoreTokens()) {
                String currentPropertyName = st.nextToken();

                // Assign to holder the next property in the chain.
                result = invokeProperty(result, currentPropertyName);
            }

            // Return holder Object
            return result;
        } catch (NullPointerException e) {
            // It is very likely that one of the properties returned null. If so, catch the exception and return null.
            return null;
        }
    }

    public void destroy() {
    }

    public void init() throws ProviderConfigurationException {
    }

    /**
     * Convert property name into getProperty name ( "something" -> "getSomething" )
     */
    private String createMethodName(String prefix, String propertyName) {
        return prefix + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
    }

    /**
     * Invoke the method/field getter on the Object.
     * It tries (in order) obj.getProperty(), obj.isProperty(), obj.property(), obj.property.
     */
    private Object invokeProperty(Object obj, String property) {
        if ((property == null) || (property.length() == 0)) {
            return null; // just in case something silly happens.
        }

        Class cls = obj.getClass();
        Object[] oParams = {};
        Class[] cParams = {};

        try {
            // First try object.getProperty()
            Method method = cls.getMethod(createMethodName(GET, property), cParams);

            return method.invoke(obj, oParams);
        } catch (Exception e1) {
            try {
                // First try object.isProperty()
                Method method = cls.getMethod(createMethodName(IS, property), cParams);

                return method.invoke(obj, oParams);
            } catch (Exception e2) {
                try {
                    // Now try object.property()
                    Method method = cls.getMethod(property, cParams);

                    return method.invoke(obj, oParams);
                } catch (Exception e3) {
                    try {
                        // Now try object.property()
                        Field field = cls.getField(property);

                        return field.get(obj);
                    } catch (Exception e4) {
                        // oh well
                        return null;
                    }
                }
            }
        }
    }
}

 

oscore-2.2.5中的类,代码不难,且有注释,我就不多解析了。如有疑问,请提出来,我尽力解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值