`
xinyangwjb
  • 浏览: 79852 次
  • 性别: Icon_minigender_1
  • 来自: 信阳
社区版块
存档分类
最新评论

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);
        Class clz = source.getClass();
        String methodName = "get" + propName;
        Method method = null;
        try {
            method = clz.getMethod(methodName, (Class[]) null);   // 寻找属性的get方法
        } catch (NoSuchMethodException nsme) {
            String methodName2 =  "is" + propName;                // 也许是个is方法
            try {
                method = clz.getMethod(methodName2, (Class[]) null);
            } catch (NoSuchMethodException ne) {
                // 没有找到属性的get或者is方法,打印错误,返回true
                System.err.println(“No such methods: ” 
					+ methodName + “ or “ + methodName2);
                return true;
            }
        }
        return apply(method);
    }
} // END: AbstractMethodFilter

public class InvisibleFilter extends AbstractMethodFilter {
    // 过滤条件,标注中有符合这个条件的property将被过滤掉
    private String _sGUIID;
    public InvisibleFilter(final String guiid) {
        _sGUIID = guiid;
    }

    public boolean apply(final Method method) {
        if (_sGUIID == null || _sGUIID.equals(“”)) {
            return false;                                         // 表示不做限制
        }
        if (method.isAnnotationPresent(Invisible.class)) {
            Invisible anno = method.getAnnotation(Invisible.class);
            String[] value = anno.value();
            for (int i = 0; i < value.length; i++) {
                if (_sGUIID.equals(value[i])) {
                    return true;
                }
            }
        }
        return false;
    }
}


现在只要把这个 filter 注册到 JsonConfig 中,就实现了属性的过滤。

JsonConfig config = new JsonConfig();
config.setJsonPropertyFilter( new InvisibleFilter(“LIST”)); //标注了LIST的属性将被过滤掉

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



使用 annotation 自定义 Bean 属性的转换方式
Json-lib 通过 JsonConfig 提供了自定义属性转换方式的接口。


			
JsonConfig config = new JsonConfig();
config.registerJsonValueProcessor(java.util.Date.class, new JsDateJsonValueProcessor());

注册后 Json-lib 在遇到 java.uitl.Date 类型的属性时,会应用 JsDateJsonValueProcessor 的处理方法。
所以,只要实现自己的 JsonValueProcessor 就可以自定义各种 Object 的转换方式了
根据上一节的讨论,Json-lib 在转换 Bean 属性之前,会将属性数据传递给 PropertyFilter 来判断是否需要过滤掉。因此,我们可以通过一个 Filter 对象获得 Bean 的属性的标注数据,并将它传递给特定的 Processor,Processor 根据得到的标注值知道应该怎么处理这个属性。下面以整型代码为例,说明处理的方法。
一般情况下,一个项目中会涉及许多种不同的代码,我们会为每一种代码定义一个主代码号(代码往往都是整型的),为它的子项定义几个子代码号。例如,我们定义性别的主代码号为 100,并定义男:1,女:2。
首先,需要一个代码标注(IntegerCode)及一个处理这种标注的 PropertyFilter。


				
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IntegerCode {
    public int value();
}

public class IntegerCodeFilter extends AbstractMethodFilter {
    // 代码处理器
    private IntegerCodeProcessor _processor;
    public IntegerCodeFilter(final IntegerCodeProcessor processor) {
        _processor = processor;
    }

    // 不过滤属性,但当发现IntegerCode标注时,将数据传递给Processor
    public boolean apply(final Method method) {
        if (_processor == null) {
            return false;                                // 表示没有特别的处理
        }
        if (method.isAnnotationPresent(IntegerCode.class)) {
            IntegerCode anno = method.getAnnotation(IntegerCode.class);
            int code = anno.value();
            _processor.setMainCode(code);                // 将code设置为主代码
        }
        return false;
    }
}

public class IntegerCodeProcessor implements JsonValueProcessor {

    private int _iMainCode;

    public void setMainCode(final int mainCode) { _iMainCode = mainCode; }

    public IntegerCodeProcessor() {
        super();
    } // END: IntegerCodeProcessor

    private void reset() {
        _iMainCode = -1;
    }

    public Object processArrayValue(Object value, JsonConfig jsonConfig) {
        return process(value, jsonConfig);
    } // END: processArrayValue

    public Object processObjectValue(
            String key, Object value, JsonConfig jsonConfig ) {
        return process( value, jsonConfig );
    } // END: processObjectValue

    private Object process(Object value, JsonConfig jsonConfig) {
        if (value == null) {
            return null;
        }
        String ret = null;
        if (value instanceof Integer && _iMainCode >= 0) {
            int code = value.intValue();
            switch (_iMainCode) {
                case 100:                    // 这里使用简单的case 处理不同的代码
                    if (code == 1) {         // 好一点的方式是从资源文件中读取对应值
                        ret = "man";
                    } else if (code == 2) {
                        ret = "woman";
                    } else {
                        ret = value.toString();
                    }
                    break;
                default:
                    ret = value.toString();
                    break;
            }
        } else {
            ret = value.toString();
        }
        reset();                             // 处理后重置,以免影响其他 Integer 属性

        return ret;
    } // END: process
}


				
public class Student {
    private String name = "camry";
    private int gender = 1;
    
    // getters & setters
    public String getName() { return name; }
    @IntegerCode(100)                              // 性别主代码为 100
    public int getGender() { return gender; }}
}

...
IntegerCodeProcessor processor = new IntegerCodeProcessor();
IntegerCodeFilter filter = new IntegerCodeFilter(processor);
JsonConfig config = new JsonConfig();
config.setJsonPropertyFilter( filter );
config.registerJsonValueProcessor(Integer.class, processor);

System.out.println( JSONSerializer.toJSON( new Student(), config ) );
// prints {“gender”:”man”, "name":"camry"}

分享到:
评论

相关推荐

    jackson json与JavaBean互相转换

    json 所需要的jackson-annotations-2.4.0.jar,jackson-core-2.4.2.jar, jackson-databind-2.4.2.jar,jackson-mapper-asl-1.9.11.jar

    xml与json、javabean的互相转换

    xml与json、javabean的互相转换

    json对象与javabean相互转化

    json对象与javabean相互转化 JSONObject jsonObj=JSONObject.fromObject(s);//将字符串转化为json对象 //写数据库处理 ObjBean bean=(ObjBean)JSONObject.toBean(jsonObj,ObjBean.class); ObjBean bean=new ...

    JavaBean与Json相互转换

    将JavaBean对象与Json字符串相互转换,将Java集合与Json字符串集合相互转换。

    JavaBean与JsonString的相互转换

    小测试,将JavaBean与JsonString的相互转换。

    javaBean--jsonObject--jsonString相互转化

    最近在研究Webservice的时候遇到一个问题,把java对象转化问json后传过去,接受的是String类型,怎么恢复到原来的java对象呢,后来再一个项目中看到了转换方法,转换顺序为javaBean--jsonObject--jsonString,还原...

    JavaBean-xml-Json转换

    XStream示例代码,JavaBean与XML,JSON之间互相转换(包含完整jar包)jettison-1.3.3.jar、xmlpull-1.1.3.1.jar、xstream-1.4.7.jar

    XStream在JavaBean与XML/JSON 之间相互转换

    NULL 博文链接:https://kingxss.iteye.com/blog/1037741

    FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换操作

    主要介绍了FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换,非常不错,具有参考借鉴价值,需要的朋友可以参考下

    JSON.xmind

    此文档包含了对JSON的由来,组成以及fastJSON与javaBean对象的相互转换的详细描述,还具有在日常工作中经过总结而写的工具类,在工作中非常实用

    json_lib使用实例:java对象与json字符串的互转

    里面有详细的json字符串和java对象(JavaBean,HashMap,ArrayList,Array...)的互相转化

    fastjson下载包

    json工具,FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换非常便捷

    fastjson包和使用说明

    Java编程中有时候会遇到JavaBean对象、json字符串、json对象之间互相转换的问题,个人感觉使用fastjson很方便,把jsonfast包和使用方法分享给大家.

    XStream示例(含jar包)

    XStream示例,JavaBean与XML,JSON之间互相转换(含jar包) jettison-1.3.3.jar、xmlpull-1.1.3.1.jar、xstream-1.4.7.jar

    XStream示例(包含完整jar包)

    XStream示例代码,JavaBean与XML,JSON之间互相转换(包含完整jar包)jettison-1.3.3.jar、xmlpull-1.1.3.1.jar、xstream-1.4.7.jar

    基于Java的XML解析与反射设计模式.doc

    所以在读取大型xml时可以把 xstream与saxparser结合起来使用,用saxparser读取整个xml把核心数据部分让xstrea m来解析成javabean,这样既解决了大数据的问题又利用了xstream快速转化javabean的 优点。 为了利于多...

    Struts2 in action中文版

    3.4.1 对象支持的JavaBean属性 52 3.4.2 ModelDriven动作 54 3.4.3 域对象用作数据转移的潜在危险 55 3.5 案例研究:文件上传 56 3.5.1 通过struts-default包获得内建的支持 56 3.5.2 fileUpload拦截器做什么 57 ...

    Spring.3.x企业应用开发实战(完整版).part2

    5.2.1 JavaBean的编辑器 5.2.2 Spring默认属性编辑器 5.2.3 自定义属性编辑器 5.3 使用外部属性文件 5.3.1 使用外部属性文件 5.3.2 使用加密的属性文件 5.3.3 属性文件自身的引用 5.4 引用Bean的属性值 5.5 国际化...

    Spring3.x企业应用开发实战(完整版) part1

    5.2.1 JavaBean的编辑器 5.2.2 Spring默认属性编辑器 5.2.3 自定义属性编辑器 5.3 使用外部属性文件 5.3.1 使用外部属性文件 5.3.2 使用加密的属性文件 5.3.3 属性文件自身的引用 5.4 引用Bean的属性值 5.5 国际化...

    JAVA上百实例源码以及开源项目源代码

     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...

Global site tag (gtag.js) - Google Analytics