论坛首页 Java企业应用论坛

JsonConvert 0.2.0正式版 发布~

浏览 3871 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-05-31   最后修改:2012-06-01

 

 --

      时隔大半年才有自己业余的时间对JsonConvert进行了一次大更新。

      更新内容:

           1、结构上进行大量的重构

           2、支持更全面的泛型解析

           3、支持json部分对象提取

           4、支持非空构造函数的类

           5、增加字段的具体类型配置

           6、增加功能但代码反而减少40%

 

        JsonConvert默认只提供支持最基本的类型:

                boolean--double、enum、Boolean--Double、String、以上类型的数组

 

 

下面介绍JsonConvert的使用方法:


      一、常用方法:

Java代码 
  1. public static class Record {  
  2.     public int id;  
  3.     public String name;  
  4.     public Record(){}  
  5. }  
  6.   
  7. //--------------------------序列化对象---------------------  
  8. Record record = ...;  
  9. String json = JsonConvert.convertTo(record);  
  10. //通常序列化后需要io操作, 所以提供了一个bytes方法调用  
  11. byte[] bytes = JsonConvert.convertToUTF8Bytes(record);  
  12. //--------------------------解析对象---------------------  
  13. //解析单个对象使用convertFrom方法, 数组则使用convertArrayFrom  
  14. record = JsonConvert.convertFrom(json, Record.class);  
  15. //------------------------解析部分json--------------------  
  16. String str = "{id:18,data:{name:'haha',info:{qq:10001,birth:[1988,8,8]}}}";  
  17. int[] birth = JsonConvert.convertFrom(str, "data.info.birth"int[].class);                                                              

 

 

   解析时默认情况下Record的实例化是通过DefaultCreator进行创建的, 而DefaultCreator使用的是反射。

所以如果注重这点反射性能的话可以给Record注册一个Creator:

 

Java代码 
  1. JsonFactory.register(Record.classnew Creator<Record>() {  
  2.   
  3.     public Record create(Object... params) {  
  4.       return new Record();  
  5.     }  
  6. });  

 

  注意: 所有JsonFactory.register的方法必须在第一次使用JsonConvert之前调用。


      二、无默认构造类:

       通常JavaBean都会有个public无参数的构造函数, 但是如果有特殊情况或者JavaBean是第三方提供的。

在解析之前就必须给这个类注册一个带有@CreatorFields的Creator :

Java代码 
  1. public static class Record {  
  2.     public final int id;  
  3.     public String name;  
  4.     public long qq;  
  5.     public Record(int id, String name) {  
  6.         this.id = id;  
  7.         this.name = name;  
  8.     }  
  9. }  
  10.   
  11. JsonFactory.register(Record.classnew Creator<Record>() {  
  12.     @CreatorFields({'id''name'})
  13.     public Record create(Object... params) {  
  14.         int id = params[0] == null ? 0 : (Integer) params[0];  
  15.         return new Record(id, (String) params[1]);  
  16.     }  
  17. });  

      刚开始准备把JsonCreator用annotation来表示, 考虑到如果类是第三方提供的, 就无法使用annotation。


      三、JsonListener的使用:

        JsonListener作用于为简单的数据,json里属性值为字符串或者数值的都会使用JsonListener来解析或序列化。

JsonConvert默认只支持java的基本数据类型, 如果使用到例如Date、BigInteger这样的类需要事先注册:

JsonFactory.register(Date.class, new JsonListener<Date>() {

	private final JsonListener<Long> listener = JsonFactory.findListener(long.class);

	@Override
	public void convertTo(JsonWriter out, Date value) {
		if (value == null) {
			out.writeNull();
		} else {
			listener.convertTo(out, value.getTime());
		}
	}
	@Override
	public Date convertFrom(final JsonReader in) {
		Long value = listener.convertFrom(in);
		return value == null ? null : new Date(value);
	}
	@Override
	public Class<Date> getType() {
		return Date.class;
	}
});

JsonFactory.register(BigInteger.class, new JsonListener<BigInteger>() {

	@Override
	public void convertTo(JsonWriter out, BigInteger value) {
		if (value == null) {
			out.writeNull();
		} else {
			out.write(true, value.toString());
		}
	}
	@Override
	public BigInteger convertFrom(JsonReader in) {
		char[] text = in.readValue();
		return text == null ? null : new BigInteger(new String(text));
	}
	@Override
	public Class<BigInteger> getType() {
		return BigInteger.class;
	}
});

   如果需要时间格式化之类的可以自定义JsonListener通过@JsonRef注册给字段。

       之所以不提供Date类的 JsonListener 是因为long/int就足以表示时间, 无需Dae这么大的对象传递。



      四、@JsonRef/JsonField的使用:

          @JsonRef与JsonField提供的功能几乎一样(JsonField多了一个type)。 为什么需要JsonField类呢, 因为当JavaBean是第三方提供的话, 就无法使用@JsonRef给JavanBean进行设置, 只能依靠JsonField。

@JsonRef的定义:

Java代码 
  1. public @interface JsonRef {  
  2.   
  3.     /** 给字段取个别名 */  
  4.     String alias() default "";  
  5.   
  6.     /** 解析/序列化时是否屏蔽该字段 */  
  7.     boolean ignore() default false;  
  8.   
  9.     /** 给指定的属性赋予特定的JsonListener */  
  10.     Class<? extends JsonListener> listener() default JsonListener.class;  
  11.   
  12.     /** 
  13.      * 如果setter getter方法不是简单的直接操作field则设为true,  
  14.      * 为false框架会直接调用field, 而不是method 
  15.      * 例如: public int getNumber(){ return number; }  
  16.      * 这种情况应该设置为false, 默认值也就是false;  
  17.      * public int getNumber(){ return number > 0 ? -1 : number; } 
  18.      * 这种不是直接返回number的情况应该设置为true  
  19.      * setter getter方法都一样 
  20.      */  
  21.     boolean indirect() default false;  
  22. }  

    例如给某个字段指定JsonListener:

 

Java代码 
  1. public class Record {  
  2.   
  3.     //自定义实现JsonDateFormatListener   
  4.     @JsonRef(listener = JsonDateFormatListener.class)  
  5.     public Date time;  
  6.   
  7. }  

 

      剩下部分见楼下~~

   发表时间:2012-05-31   最后修改:2012-06-01

  五、泛型的支持:

         在0.1版本里面支持只Class,  新版开始支持Type。

       简单的泛型解析:

Java代码 
  1. public class CaseRecord {  
  2.   
  3.     private static final Type Type_1 = new GenericType<List<Integer>>() {}.getType();  
  4.   
  5.     private static Type Type_2 = new GenericType<List<Map<Integer, String>>>() {}.getType();  
  6.   
  7.     private static Type Type_3 = new GenericType<List<Map<Integer, String>>[]>() {}.getType();  
  8.   
  9.     public static void main(String[] args) throws Throwable {  
  10.         String str1 = "[{1:'a',2:'b'},{3:'c',4:'d'}]";  
  11.         List<Map<Integer, String>> value1 = JsonConvert.convertFrom(str1, Type_2);  
  12.         System.out.println(value1);  
  13.         List<Integer> value2 = JsonConvert.convertFrom("[1,2,3,4,5]", Type_1);  
  14.         System.out.println(value2);  
  15.           
  16.         String str2 = "[" + str1 + "]";  
  17.         List<Map<Integer, String>>[] obj2 = JsonConvert.convertFrom(str2, Type_3);  
  18.         System.out.println(JsonConvert.convertTo(obj2));  
  19.         List<Map<Integer, String>>[] obj3 = JsonConvert.convertArrayFrom(str2, Type_3);  
  20.         System.out.println(JsonConvert.convertTo(obj3));  
  21.     }  
  22. }  

     给类注入具体的解析类型:

Java代码 
  1. public class A {  
  2.     public BaseRecord record;  
  3.     public List names;  
  4.     public Map<?, ?> address;  
  5. }  
  6.   
  7.   
  8. //注册实现类  
  9. JsonFactory.register(A.classnew JsonField("record", RecordImpl.class);   
  10. //注册具体的类型  
  11. JsonFactory.register(A.classnew JsonField("names"new GenericType<ArrayList<String>>() {}.getType()));   
  12. //注册具体的类型  
  13. JsonFactory.register(A.classnew JsonField("address"new GenericType<Map<Integer, String>>() {}.getType()));   
 

 

      六、拦截器:

       JsonConvert 提供一个在解析后、序列化前调用的拦截器:

Java代码 
  1. public interface JsonInterceptor<T> {  
  2.   
  3.     //解析后调用  
  4.     public T postDecode(T obj);  
  5.   
  6.     //序列化之前调用  
  7.     public T preEncode(T obj);  
  8. }  

   例如:

Java代码 
  1. JsonFactory.register(Record.classnew JsonInterceptor<Record>(){  
  2.   
  3.     public Record postDecode(Record obj) {  
  4.         if(obj.getTime() < 1) obj.setTime(System.currentTimeMillis());  
  5.         return obj;  
  6.     }  
  7.   
  8.     public Record preEncode(Record obj) {  
  9.         return obj;  
  10.     }  
  11. });  
 


      七、循环引用:

       JsonConvert 在几乎没有性能影响下使用栈支持简单的树型循环引用, 毕竟json的规范中无循环引用。

只有当解析类或序列化类存在循环的可能才会启动栈。

                                          parent

                                           /       \

                                          /         \

                          /            \

                                    node1       node2

                                    /   \               /   \

                                   /     \             /     \

                                  /       \           /       \

                           child1    child2  child3   child4

    如图树型引用就是child1只能引用node1、parent;node1只能引用parent。而child1不能引用node2、child2。

 


      八、压缩序列化:

       为了让输出的json字符串长度尽量减少, 可以进行以下设置:

                  //输出字段名不需要引号。   

          1、  JsonFactory.setFieldQutoable(false);

                  //boolean 值以0、1输出。   

          2、  JsonFactory.register(boolean.class, JsonBoolListener.JsonBoolHexListener.getInstance());

                  //boolean[] 值以01010011字符串输出。   

          3、  JsonFactory.register(boolean[].class, JsonBoolArrayListener.JsonBoolArrayHexListener.getInstance());

                  //byte[] 值以16进制字符串输出。   

          3、  JsonFactory.register(byte[].class, JsonByteArrayListener.JsonByteArrayHexListener.getInstance());

                  //char[] 值以字符串输出。   

          4、  JsonFactory.register( char[].class, JsonCharArrayListener.JsonCharArrayHexListener.getInstance());

 


      九、性能比较:

       目前fastjson是号称性能最好的json库, 下面是与fastjon 1.1.17版本简单性能的比较结果:  

 



    由结果看出jsonconvert性能比fastjson稍好些~

    说明一点: MediaContent是根据jvm-serializers提供的数据类

                    MediaContent2跟MediaContent的区别只是将List<Image> images 改成 Image[] images.

 


    附件提供test源码~~

 


      十、Jsonconvert 0.2.0 源码与jar包路径:

              https://tendon.googlecode.com/svn/trunk/tendon.jsonconvert/tags/0.2.0/

 

 

0 请登录后投票
   发表时间:2012-05-31  
LZ 那个循环引用你怎么处理的啊?
0 请登录后投票
   发表时间:2012-05-31  
char1st 写道
LZ 那个循环引用你怎么处理的啊?

JsonConvert只实现了简单树型循环, 不支持网状的嵌套循环, 毕竟json的规范是不支持循环的。
循环是通过JsonSimpleable来判断对象类是不是有包含循环的可能。 如果存在循环的可能, 在序列化的时候构建一个栈,每序列化一个对象时判断是否在栈内存在。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics