日期:2014-05-16  浏览次数:20296 次

Json与JavaBean相互转换

Json与JavaBean相互转换的工具有很多,比如下面附件中的struts2-json-plugin-2.1.8.1.jar。
具体实现为

String content = JSONUtil.serialize(javaBean);//将javaBean(包括Domain、List、Map等)转化为String类型的json
JaveBean jb = (JaveBean)JSONUtil.deserialize(Stirng json);//将String类型的Json转化为JavaBean类型的javaBean


还有一种就是很常用的json-lib,比如下面附件中的json-lib-2.2.1-jdk15.jar。
具体实现为

JSON json = JSONSerializer.toJSON( JaveBean );
JSON json = JSONSerializer.toJSON( JaveBean , jsonConfig);
JaveBean jb = (JaveBean)JSONSerializer.toJava( json );
JaveBean jb = (JaveBean)JSONSerializer.toJava(json , jsonConfig);



以上俩个工具都很好,但是有以下问题:
问题 1: 需要有选择的提取 JavaBean 中的属性
转换后的 JSON 数据中包含了 JavaBean 中的全部属性,可是我们常常需要有选择的提取 JavaBean 中的特定属性出来。例如:
需要过滤掉循环引用的属性,这一点 json-lib 提供了 CycleDetectionStrategy 来处理,但是直接过滤掉更简单;
不同的情况下只需要 JavaBean 中的部分属性:比如列表界面只需要显示 Bean 的几个重要属性,而详情界面则需要显示更多的 Bean 的属性;
不同的用户权限限制用户只能获得某些属性数据;

问题 2: 需要自定义某些属性的转换方式
对于普通的 Object 类型(如 Long,String 等),json-lib 有缺省的值转换处理方式,但是对于一些特殊的类型,我们希望用自定义的方式来转换该属性的值。例如:
对于 java.util.Date 类型,我们希望直接转换成时间串:2010-04-10,而不希望得到一个类似 {"year":"2010","month":"4","day":"10"} 这样的结果
对于常用到的代码数据(比如:性别),在定义时它也许是个 Integer(男:1;女:2),我们希望在转换后直接得到:{"性别":"男",...},而不是 {"性别":"1",...}
Json-lib 已经预留出一些接口,让用户修改它的缺省行为。

具体实现我是参考http://www.ibm.com/developerworks/cn/java/j-lo-jsonlib/index.html,以下代码纯属copy,感谢原作者的分享,详细实现请查看原博客:

该博客使用PropertyFilter和JsonConfig来实现过滤,并引入annotation来简化处理代码

代码段一:
import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;
import net.sf.json.util.PropertyFilter;
// 定义属性过滤器
PropertyFilter filter = new PropertyFilter(
    public boolean apply(Object source, String name, Object value) {
        if ( name.equals( “pojoId” ) ) {
            return true;   // 返回 true, 表示这个属性将被过滤掉
        }
        return false;
    }
);
// 注册属性过滤器
JsonConfig config = new JsonConfig();
config.setJsonPropertyFilter( filter );

System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );
// prints {"name":"json"}


首先先定义annotation和MyBean,并给 MyBean 的 get 方法加上标注,具体实现慢慢来


				
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Invisible {
    public String[] value();
}

// 为myBean中需要过滤的属性get方法(或者is方法)加上Invisible标注
public class MyBean{
    private String name = "json";
    private int pojoId = 1;
    
    // getters & setters
    public String getName() { return name; }
    @Invisible(“LIST”)   // 在 “LIST” 情况下不要这个属性
    public int getPojoId() { return pojoId; }
}


然后,我们需要一些能处理 annotation 的 PropertyFilter 类

				
import java.util.Map;
import java.lang.reflect.Method;
import net.sf.json.util.PropertyFilter;
// 先实现一个abstract类,将读取Bean属性的Method找到并传递给子类处理
public abstract class AbstractMethodFilter implements PropertyFilter {
    // 这个方法留给子类实现,以便适应不同的过滤需求
    public abstract boolean apply(final Method method);

    public boolean apply(final Object source, final String name, final Object value) {
        if (source instanceof Map) {
            return false;
        }
        String propName = name.substring(0, 1).toUpperCase() + name.substring(1);