Json与JavaBean相互转换

转:http://xinyangwjb.iteye.com/blog/1450586

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

Java代码 复制代码 收藏代码
  1. String content = JSONUtil.serialize(javaBean);//将javaBean(包括Domain、List、Map等)转化为String类型的json
  2. JaveBean jb = (JaveBean)JSONUtil.deserialize(Stirng json);//将String类型的Json转化为JavaBean类型的javaBean
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。
具体实现为

Java代码 复制代码 收藏代码
  1. JSON json = JSONSerializer.toJSON( JaveBean );
  2. JSON json = JSONSerializer.toJSON( JaveBean , jsonConfig);
  3. JaveBean jb = (JaveBean)JSONSerializer.toJava( json );
  4. JaveBean jb = (JaveBean)JSONSerializer.toJava(json , jsonConfig);
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来简化处理代码

代码段一:

Java代码 复制代码 收藏代码
  1. import net.sf.json.JSONSerializer;
  2. import net.sf.json.JsonConfig;
  3. import net.sf.json.util.PropertyFilter;
  4. // 定义属性过滤器
  5. PropertyFilter filter = new PropertyFilter(
  6. publicboolean apply(Object source, String name, Object value) {
  7. if ( name.equals( “pojoId” ) ) {
  8. returntrue; // 返回 true, 表示这个属性将被过滤掉
  9. }
  10. returnfalse;
  11. }
  12. );
  13. // 注册属性过滤器
  14. JsonConfig config = new JsonConfig();
  15. config.setJsonPropertyFilter( filter );
  16. System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );
  17. // prints {"name":"json"}
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 方法加上标注,具体实现慢慢来

Java代码 复制代码 收藏代码
  1. import java.lang.annotation.Target;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.RetentionPolicy;
  6. @Documented
  7. @Target({ElementType.METHOD})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. public@interface Invisible {
  10. public String[] value();
  11. }
  12. // 为myBean中需要过滤的属性get方法(或者is方法)加上Invisible标注
  13. publicclass MyBean{
  14. private String name = "json";
  15. privateint pojoId = 1;
  16. // getters & setters
  17. public String getName() { return name; }
  18. @Invisible(“LIST”) // 在 “LIST” 情况下不要这个属性
  19. publicint getPojoId() { return pojoId; }
  20. }
				
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 类

Java代码 复制代码 收藏代码
  1. import java.util.Map;
  2. import java.lang.reflect.Method;
  3. import net.sf.json.util.PropertyFilter;
  4. // 先实现一个abstract类,将读取Bean属性的Method找到并传递给子类处理
  5. publicabstractclass AbstractMethodFilter implements PropertyFilter {
  6. // 这个方法留给子类实现,以便适应不同的过滤需求
  7. publicabstractboolean apply(final Method method);
  8. publicboolean apply(final Object source, final String name, final Object value) {
  9. if (source instanceof Map) {
  10. returnfalse;
  11. }
  12. String propName = name.substring(0, 1).toUpperCase() + name.substring(1);
  13. Class clz = source.getClass();
  14. String methodName = "get" + propName;
  15. Method method = null;
  16. try {
  17. method = clz.getMethod(methodName, (Class[]) null); // 寻找属性的get方法
  18. } catch (NoSuchMethodException nsme) {
  19. String methodName2 = "is" + propName; // 也许是个is方法
  20. try {
  21. method = clz.getMethod(methodName2, (Class[]) null);
  22. } catch (NoSuchMethodException ne) {
  23. // 没有找到属性的get或者is方法,打印错误,返回true
  24. System.err.println(“No such methods: ”
  25. + methodName + “ or “ + methodName2);
  26. returntrue;
  27. }
  28. }
  29. return apply(method);
  30. }
  31. } // END: AbstractMethodFilter
  32. publicclass InvisibleFilter extends AbstractMethodFilter {
  33. // 过滤条件,标注中有符合这个条件的property将被过滤掉
  34. private String _sGUIID;
  35. public InvisibleFilter(final String guiid) {
  36. _sGUIID = guiid;
  37. }
  38. publicboolean apply(final Method method) {
  39. if (_sGUIID == null || _sGUIID.equals(“”)) {
  40. returnfalse; // 表示不做限制
  41. }
  42. if (method.isAnnotationPresent(Invisible.class)) {
  43. Invisible anno = method.getAnnotation(Invisible.class);
  44. String[] value = anno.value();
  45. for (int i = 0; i < value.length; i++) {
  46. if (_sGUIID.equals(value[i])) {
  47. returntrue;
  48. }
  49. }
  50. }
  51. returnfalse;
  52. }
  53. }
				
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 中,就实现了属性的过滤。

Java代码 复制代码 收藏代码
  1. JsonConfig config = new JsonConfig();
  2. config.setJsonPropertyFilter( new InvisibleFilter(“LIST”)); //标注了LIST的属性将被过滤掉
  3. System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );
  4. // prints {"name":"json"}
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 提供了自定义属性转换方式的接口。

Java代码 复制代码 收藏代码
  1. JsonConfig config = new JsonConfig();
  2. config.registerJsonValueProcessor(java.util.Date.class, new JsDateJsonValueProcessor());
			
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。

Java代码 复制代码 收藏代码
  1. @Documented
  2. @Target({ElementType.METHOD})
  3. @Retention(RetentionPolicy.RUNTIME)
  4. public@interface IntegerCode {
  5. publicint value();
  6. }
  7. publicclass IntegerCodeFilter extends AbstractMethodFilter {
  8. // 代码处理器
  9. private IntegerCodeProcessor _processor;
  10. public IntegerCodeFilter(final IntegerCodeProcessor processor) {
  11. _processor = processor;
  12. }
  13. // 不过滤属性,但当发现IntegerCode标注时,将数据传递给Processor
  14. publicboolean apply(final Method method) {
  15. if (_processor == null) {
  16. returnfalse; // 表示没有特别的处理
  17. }
  18. if (method.isAnnotationPresent(IntegerCode.class)) {
  19. IntegerCode anno = method.getAnnotation(IntegerCode.class);
  20. int code = anno.value();
  21. _processor.setMainCode(code); // 将code设置为主代码
  22. }
  23. returnfalse;
  24. }
  25. }
				
@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;
    }
}
Java代码 复制代码 收藏代码
  1. publicclass IntegerCodeProcessor implements JsonValueProcessor {
  2. privateint _iMainCode;
  3. publicvoid setMainCode(finalint mainCode) { _iMainCode = mainCode; }
  4. public IntegerCodeProcessor() {
  5. super();
  6. } // END: IntegerCodeProcessor
  7. privatevoid reset() {
  8. _iMainCode = -1;
  9. }
  10. public Object processArrayValue(Object value, JsonConfig jsonConfig) {
  11. return process(value, jsonConfig);
  12. } // END: processArrayValue
  13. public Object processObjectValue(
  14. String key, Object value, JsonConfig jsonConfig ) {
  15. return process( value, jsonConfig );
  16. } // END: processObjectValue
  17. private Object process(Object value, JsonConfig jsonConfig) {
  18. if (value == null) {
  19. returnnull;
  20. }
  21. String ret = null;
  22. if (value instanceof Integer && _iMainCode >= 0) {
  23. int code = value.intValue();
  24. switch (_iMainCode) {
  25. case100: // 这里使用简单的case 处理不同的代码
  26. if (code == 1) { // 好一点的方式是从资源文件中读取对应值
  27. ret = "man";
  28. } elseif (code == 2) {
  29. ret = "woman";
  30. } else {
  31. ret = value.toString();
  32. }
  33. break;
  34. default:
  35. ret = value.toString();
  36. break;
  37. }
  38. } else {
  39. ret = value.toString();
  40. }
  41. reset(); // 处理后重置,以免影响其他 Integer 属性
  42. return ret;
  43. } // END: process
  44. }
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
}
Java代码 复制代码 收藏代码
  1. publicclass Student {
  2. private String name = "camry";
  3. privateint gender = 1;
  4. // getters & setters
  5. public String getName() { return name; }
  6. @IntegerCode(100) // 性别主代码为 100
  7. publicint getGender() { return gender; }}
  8. }
  9. ...
  10. IntegerCodeProcessor processor = new IntegerCodeProcessor();
  11. IntegerCodeFilter filter = new IntegerCodeFilter(processor);
  12. JsonConfig config = new JsonConfig();
  13. config.setJsonPropertyFilter( filter );
  14. config.registerJsonValueProcessor(Integer.class, processor);
  15. System.out.println( JSONSerializer.toJSON( new Student(), config ) );
  16. // prints {“gender”:”man”, "name":"camry"}

猜你喜欢

转载自wanxiaotao12-126-com.iteye.com/blog/1808941