`
rongxh2010
  • 浏览: 48869 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

"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中的类,代码不难,且有注释,我就不多解析了。如有疑问,请提出来,我尽力解决。

分享到:
评论
2 楼 rongxh2010 2010-06-14  
heqishan 写道
   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;  
                     }  


这段不明白。。。

PropertyDescriptor 这个是什么?

Java的一个类,用来获取Getter和Setter方法很方便。具体,请看JDK的文档相关说明:http://java.sun.com/j2se/1.5.0/docs/api/java/beans/PropertyDescriptor.html
1 楼 heqishan 2010-06-09  
   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;  
                     }  


这段不明白。。。

PropertyDescriptor 这个是什么?

相关推荐

    freemarker总结

    2,使用+运算符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串再连接,如:${3 + "5"},结果是:35 使用内建的int函数可对数值取整,如: ${ (x/2)?int } ${ 1.1?int } ${ 1.999?int } ${ -1.1?int } ...

    PHP程序设计PPT

    2. **数据类型**:PHP支持整型、浮点型、字符串、布尔型、数组、对象、NULL以及资源等多种数据类型。 3. **流程控制**:包括条件语句(if...else)、循环结构(for、while、do...while、foreach)、开关结构...

    PHP作业.rar

    3. 数据类型:PHP支持多种数据类型,包括整型、浮点型、字符串、布尔型、数组、对象、NULL等。 4. 条件语句:如`if...else`,`switch...case`用于根据条件执行不同的代码块。 5. 循环结构:`for`、`while`、`do......

    PHP结课作业1931-php2-源码.rar

    2. 输出:`echo` 和 `print` 用于输出字符串,`echo` 比 `print` 稍快,两者都可以同时输出多个值。 3. 注释:单行注释使用 `//` 或 `#`,多行注释使用 `/* ... */`。 【控制结构】 1. 条件语句:`if...else if......

    PHP编程起步自学教程2.pdf

    3. **数据类型**:PHP支持多种数据类型,包括字符串、整型、浮点型、数组、对象等。例如: ```php $age = 30; // 整型 $height = 1.78; // 浮点型 $name = "Jane Smith"; // 字符串 $isActive = true; // 布尔...

    phpexample

    3. 字符串(string) 4. 布尔型(bool) 5. 数组(array) 6. 对象(object) 7. NULL 8. 资源(resource) **流程控制** - 条件语句:`if...else`、`switch...case` - 循环语句:`for`、`while`、`do...while`、`...

    conform:根据struct标记(go,golang)整理,清理和清理数据

    根据标签修剪,清理和修改结构字符串字段。 更新2016年1月12日-现在也适用于嵌入式结构 变成这个... type Person struct { FirstName string `conform:"name"` LastName string `conform:"ucfirst,trim"` ...

    php 中文教程 初学者必备

    常见的数据类型有字符串、整型、浮点型、布尔型、数组和对象。 ```php $greeting = "你好"; // 字符串 $age = 25; // 整型 $height = 1.78; // 浮点型 $isStudent = true; // 布尔型 ``` ### 控制结构 PHP提供了...

    PHP语言入门教程-学习了PHP的基础语法、案例示例和进阶内容

    - **字符串**(string) - **数组**(array) - **对象**(object) 这些数据类型覆盖了常见的编程需求,为编写灵活多变的应用程序提供了支持。 ##### 3.3 条件语句 条件语句允许根据不同的条件执行不同的代码块...

    m.tintafresca.net

    PHP支持多种数据类型,包括字符串、整型、浮点型、布尔型、数组和对象等。数组在PHP中尤为重要,因为它们可以用来存储和操作大量数据。例如: ```php $myArray = array("apple", "banana", "cherry"); echo $...

    php_demo

    这段代码定义了一个字符串变量并将其打印出来。 【PHP与HTML的结合】 在PHP中,我们可以直接在HTML代码中嵌入PHP语句,实现动态网页生成。例如: ```html &lt;!DOCTYPE html&gt; echo "当前时间是:" . date("Y-m-d ...

Global site tag (gtag.js) - Google Analytics