• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

beetl-json: json序列化另外一种实现方式(暂停维护)

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

beetl-json

开源软件地址:

https://gitee.com/xiandafu/beetl-json

开源软件介绍:

beetl-json-logo.jpg##介绍:

- 作者:闲.大赋(同时也开发了Beetl模版语言)- 功能:Beetl-JsonTool 作为beetl模板引擎的一个附属工具,提供了对象序列化成json技术。其原理是基于(Location:action)*,功能强大,扩展性强,比fastjson,jackson,gosn基于annotatoin的强大,也远远超过了jodd json,flexjson序列化能力 而体积小,仅仅不到80K。它能允许通过序列化策略来个性化的序列化对象到JSON而无需编程或者包装原有对象,而它的性能也是相当优秀。

##例子:

  • api 例子如下

      JsonTool tool = new JsonTool();  String json = tool.serialize(user);			  String json1 = tool.serialize(user,"id:i"));		//忽略属性         String json2 = JsonTool.serialize(list,"[1].id:i"));			//忽略第二个元素的id属性  //所有属性都会执行hinernateCheck的回调  String json2 = JsonTool.serialize(obj,"*:!hibernate"));
  • 序列化策略的简单例子:

    • name:i 忽略name属性
    • id:i,obj.id:i 忽略属性id,忽略属性obj对象的id的属性.可以将多个序列化策略组合在一起,用逗号分开
    • name:nn/myName/ 将属性name输出成myName
    • ~L/com.test.User/:o/name, age/ User对象实例排序输出,name,age 先输出,其他按照定义输出
    • [1].date:f/yyyy-MM-dd/ 列表第二项目的date属性格式化输出
  • 序列化规则

序列化规则可以有多个,每个包含一个location和action对,用冒号分开,每个序列化规则用逗号分开,这个类似json的格式,如name:i,user.id:i,~L/#ju.Collection*/:->null如上表示三个序列化规则,*第一个是忽略属性name*第二个是忽略user属性的id属性*第三个要复杂一些,意思当序列到Collecton类及其子类时候,直接赋值为null(#jl是java.util的别名)。

location和action有可能出现//,这类似程序语言的(),里面是参数,如~L/#ju.Collection*/

##Action定义了一个匹配动作的输出,有忽略属性,包含属性,排序,改名,条件判断,直接赋值,调用回调等

  • i:表示忽略,如name:i 遇到name属性,忽略. ~*:i/age,bir/ 忽略类的属性age,bir,[1]:i 表示忽略第2项,[name]:i 表示忽略key为name的项 ,~L/org.beetl.json.Foo/:i ,类型为Foo的都忽略。name和age属性总是排在最前面.其他属性按顺序排(内置的AttributeComparator完成属性排序,原始类型排在最前,其次是pojo类型,再次是java类型,最后是集合类型)

  • u:表示使用类的属性,如~*:u/name,age,bir/。 其他属性忽略

  • nn 表示更改名字,{nane:nn/myName/} 将输出myName

  • ? 代表一个if,如果满足条件,则指定一个输出,如xxList:?null->[],如果某集合xxList 为null,则输出一个[],?后年可以指定null,empty,以及某个数字。->表示输出

  • $.xxx,用于调用当前位置对象的某个方法,如{ts:$.get},并不是输出ts,而是输出ts.get(). 调用后,可以使用->在使用一个Action,比如:"~L/java.util.Calendar*/:$.getTime->f/yyyy-MM-dd/" 遇到Calendar和其子类,先获取Date类型,然后格式化

  • f 用于格式化输出,如number:f/#.##/,也可以自定义格式化函数并注册,比如注册一个格式化函数Money,则number:fMoney 则会调用money做输出

  • -> 直接输出 ,比如 name:->'unkown'.

  • !xxx 调用自定义Action,xxx为注册的自定义Action。

  • f: 格式化日期或者数字类型,也可以调用使自定义格式化

  • o:表示排序,如~L/xxxxClass/:o/name, age/

  • asJson 直接输出对象toString方法,不加引号

  • 当循环引用的时候,允许输出一些额外字段而不是单纯的引

    • cu:出现循环引用,仅仅显示参数指定的字段,如{~L/Department/*:ci/name,id/} ,对于Department类,如果被重复引用,则只显示name和id,其他字段不显示。
    • ci:出现循环引用,不显示参数指定的字段,如{~L/Department/*:ci/users/} ,对于Department类,如果被重复引用,则不显示users字段。

##循环处理

注意,当序列化出现循环引用的,beetl-json不会再列化已经序列化过的对象,取而代之是用$ref:path来指向上次序列化的对象,path从根目录开始,如

	user:{ "$ref":"$.list[0].user"}

如果同时还使用了ci,cu,可以选择性额外的输出一些属性,而不是枯燥的 "$ref":path,如:序列化规则是~/User/:cu/name/ 意思当User对象出现在循环引用里,除了输出$ref外,还输出name属性。生成结果类似如下:

	user:{ "$ref":"$.list[0].user",name:'xiandafu'} 

这样使得输json更容易阅读,有些JS前端框架也可以利用额外的这些属性

##Location定义了一个序列化的位置,如属性名,或者属性表达式,列表(数组)元素,类等

  • 简单属性 如name:nn/myName/ 当前实例遇到name属性,输出的是myName,nn是action指示,表示New Name

  • 复杂属性,如 user.age:->0 当前实例遇到user属性下的age属性,总是输出0.

  • 属性正则表达式,如/id|name/ 当前实例所有id或着name属性

  • * 表示所有属性,如*:!hibernate, 所有属性序列化前都会执行hibernate

  • *./reg/" 表示符合正则表达式的所有属性,如*./id/, 所有属性名为id的。

  • L 后面是个具体类,如L/com.test.User/:u/id,name/ 在序列化过程中,所有类型为User的仅仅输出id和name。

    • 可以在类名后面使用*,表示也匹配子类,如~L/com.test.User*/
    • 可以通过调用JsonTool.addAlias("shortName", "longName");为包名增加别名。系统默认增加ju 代表java.util,jl代表java.lang,如果addAlias("com.test", "ct"),那么,~L/com.test.User*/可以简写为 ~L/#ct.User/
  • [] 代表集合

    • [*],位置是集合所有元素
    • [1],位置是集合第二个元素
    • [xxkey] 集合是个Map,位置是xxKey对应的元素
  • ~ 代表当前实例的某个类型:

    • ~d 遇到类型为日期的,格式化输出。d是Java.Util.Date的简称。
    • ~n 表示一个number类型
    • ~c 表示是一个集合
    • ~d 表示一个日期
  • *:表示当前实例所有类型,即所有属性字段,如*:o/age,name/,当前实例的属性,按照age,name先后顺序输出,其他保持不变

locaton 可以是属性表达式

  • obj.aaa.xx,指属性obj的属性aa的属性xx的位置
  • obj./.*str/ 指属性obj下的所有以str结尾的属性,.*str是正则表达式
  • obj.~* 指属性obj下的所有属性
  • obj[1].name ,指属性obj是个集合,位置是第二元素的name属性。
  • obj[*].name ,指属性obj是个集合,位置是所有元素。
  • ["key"].name ,指map的key项。
  • obj.aaa.* .指属性obj的属性aa,如obj.aaa.*:i/users,orgs/
  • [*].tt.~L/#ct.User/:i/users,orgs/ 位置是集合元素的tt属性下的所有类型是User的对象,序列化仅仅输出users,和orgs

注意,目前不支持在~L/Class/后面继续用属性表达式

##API例子:

	//全局设定,对于所有对象都适用		JsonTool tool = new JsonTool();	tool.addLocationAction("~d","f/yyyy.MM.dd/");		tool.addLocationAction("~L/java.util.Calendar*/","$.getTime->f/yyyy-MM-dd/");	//类json格式的策略,用逗号分开多个locationAction	tool.addPolicy("~f:n/#.##/,~c:?null->[]");	// 默认是紧凑输出,使用true,将换行和缩进		tool.pretty = true;	tool.addAlias("loc", "org.beetl.json.test.location");	//序列化User	String json = tool.serialize(User);	//or  指定一个序列化策略,age,name先输出,适合有特殊需求的对象或者无法注解(第三方)对象	String json2 = tool.serialize(User,"~*:o/age,name/"));	// 同上策略,但name属性输出改为code	String json2 = tool.serialize(User,"~*:o/age,name/,name:nn/code/"));	// 同上策略,像api传递俩个策略	String json2 = tool.serialize(User,"~*:o/age,name/","name:nn/code/"));	//序列化dept,Department跟SysUser是一对多关系,如果俩个类都重复引用,则忽略导致重复引用的dept字段和users字段	String json1 = tool.serialize(dept, "~L/#loc.SysUser/:ci/dept/,~L/#loc.Department/:ci/users/");

注解

默认情况下,也可以用注解来作为序列化策略。

@Json(	policys={			@JsonPolicy(location="name", action="nn/newUserName/"),			@JsonPolicy(location="deleteList", action="?empty->[]")							})public class User{		String name="joel";	int age =12;		double salary=12.32266;	Customer  customer = new Customer();	List<Customer>  list = new ArrayList<Customer>();	List<Customer>  deleteList = null;	//getter and setter 	方法必须有,在此忽略}@Json(	policys={			@JsonPolicy(location="name", action="nn/userName/")				})class Customer{	String name="lijz";	int age=11;	Date bir = new Date();	//getter and setter 	方法必须有,在此忽略}

##Action扩展

允许自定义Action来处理序列化特殊需求,Action可以实现IValueAction,用来处理渲染对象,也可以实现IKeyAction,IInstanceAction等。如下代码实现一个IValueAction,当检测到对象并未真正hibernate加载的时候,不序列化,从而避免hibernate懒加载问题

	JsonTool tool = new JsonTool();		tool.addAction("hibernate", new IValueAction() {				@Override		public int getIndex() {			// TODO Auto-generated method stub			return 0;		}				@Override		public ActionReturn doit(OutputNodeKey field, Object value,				OutputNode thisNode, JsonWriter w) {			if (value instanceof HibernateProxy) {// hibernate代理对象                LazyInitializer initializer = ((HibernateProxy) value).getHibernateLazyInitializer();                if (initializer.isUninitialized()) {                    return new ActionReturn(null,ActionReturn.RETURN);                }            } else if (value instanceof PersistentCollection) {// 实体关联集合                PersistentCollection collection = (PersistentCollection) value;                if (!collection.wasInitialized()) {                    return new ActionReturn(null,ActionReturn.RETURN);                } else if (collection.getValue() == null) {                    return new ActionReturn(null,ActionReturn.RETURN);                }            }            return new ActionReturn(value,ActionReturn.CONTINUE);		}	});		String joins = "location,customer"	List cars = service.findAll(joins);	String json = tool.serialize(cars,"*:!hibernate");

##格式化扩展可以自定义一个格式化函数,如下代码

	JsonTool.addFormat("simple", new MyDateFomrat());		public class MyDateFomrat implements Format{			public Object format(Object o) {			// TODO Auto-generated method stub			return "2015";		}		}	//序列化item,其属性bir按照simple来格式化,f是acton前缀,simple是注册的格式化函数			String json1 = JsonTool.serialize(item, "bir:fsimple");

主要api:

  • JsonTool.addLocationAction(String loc,String action) :增加一个全局的序列化策略,如JsonTool.addLocationAction("~d","f/yyyy.MM.dd/");
  • JsonTool.pretty:默认是紧凑输出,改为true,则有缩进和换行
  • JsonTool.serialize(Object o) :序列化对象,返回String
  • JsonTool.serialize(Object o,Writer w) :序列化对象到Writer里
  • JsonTool.serialize(Object o,String policy) :序列化对象,返回String,并使用额外的序列化策略
  • JsonTool.serialize(Object o,String... policy) :序列化对象,使用多个序列化策略
  • JsonTool.serialize(Object o,Writer w,String policy) :序列化对象到Writer里,并使用额外的序列化策略
  • JsonTool.serialize(Object o,Writer w,String... policy) :序列化对象到Writer里,使用多个序列化策略
  • JsonTool.addFormat(Class type, Format format) 注册一个格式化函数,然后可以通过f来格式化此属性,如xxx:f,f后面也可以使用参数,如xxx:f/yyy/,参数将传入Format类
  • JsonTool.addAction("hibernate", new HibernateAction() ); 注册一个Action
  • JsonTool.addAlias(String shortName,String name) 增加别名
  • JsonTool.attributeErrorHander 当属性获取错误的时候如果处理,默认为抛出异常,也可以实现AttribiuteErrorHandler 实现自己的错误处理,如Hibernate lazy load 会抛错,可以设置此接口忽略错误

SpringMVC集成:

配置如下:

	<mvc:annotation-driven>    <mvc:message-converters register-defaults="true">      <bean class="org.beetl.json.ext.BeetlJsonHttpMessageConverter">        <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>        <property name="policys">             <map>               <entry key="~d" value="f/yyyy-MM-dd/"/>            </map>        </property>      </bean>    </mvc:message-converters>  </mvc:annotation-driven>

代码例子

	@RequestMapping(value = "/json.html", method = RequestMethod.GET)    @ResponseBody    public List index1(HttpServletRequest req) {    	List list = new ArrayList();    	list.add(1);    	list.add(2);    	list.add(new Date());        return list;    }

如果想自定义序列化策略,而不是用Annotaion,可以采用SerObject对象

	@RequestMapping(value = "/json2.html", method = RequestMethod.GET)	@ResponseBody	public SerObject index2(HttpServletRequest req) {		List list = new ArrayList();		list.add(1);		list.add(2);		list.add(new Date());		SerObject s = new SerObject(list,"[1]:i"); //忽略第2个元素	    return s;	}

更多例子参考单元测试代码 https://git.oschina.net/xiandafu/beetl-json/tree/master/test

maven 地址

<dependency>    <groupId>com.ibeetl</groupId>    <artifactId>btjson</artifactId>    <version>0.94</version></dependency>

下一步:

  • 性能优化,争取前2,将增加asm优化,unsafe 优化
  • 简单反序列化,总体大小不超过140k。

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap