hibernate使用CGLIB把POJO的domain对象动态代理,实现它的魔法,但是给JSON的序列化带来了麻烦,因为JSON无法对lazy的属性进行序列化。有以下的四个方法可以解决hibernate的序列化问题
domain类实现JSONString接口
- 建立JsonConfig实例,并配置属性排除列表
用属性过滤器
- 写一个自定义的JsonBeanProcessor
1. 实现JSONString接口是侵入性最强的方法
Java代码
- public class Person implements JSONString {
- private String name;
- private String lastname;
- private Address address;
- // getters & setters
- public String toJSONString() {
- return "{name:‘"+name+"‘,lastname:‘"+lastname+"‘}";
- }
- }
2.第二种方法通过jsonconfig实例,对包含和需要排除的属性进行方便添加删除
Java代码
- public class Person {
- private String name;
- private String lastname;
- private Address address;
- // getters & setters
- }
- JsonConfig jsonConfig = new JsonConfig();
- jsonConfig.setExclusions( new String[]{ "address" } );
- Person bean = /* initialize */;
- JSON json = JSONSerializer.toJSON( bean, jsonConfig );
注意:这种方法不区分目标类,就是说如果有2个bean当中都存在“address”属性,那么采用这种方法,这两个bean中的address属性都将被排除
3. 使用propertyFilter可以允许同时对需要排除的属性和类进行控制,这种控制还可以是双向的,也可以应用到json字符串到java对象
Java代码
- public class Person {
- private String name;
- private String lastname;
- private Address address;
- // getters & setters
- }
- JsonConfig jsonConfig = new JsonConfig();
- jsonConfig.setJsonPropertyFilter( new PropertyFilter(){
- public boolean apply( Object source, String name, Object value ){
- // return true to skip name
- return source instanceof Person && name.equals("address");
- }
- });
- Person bean = /* initialize */;
- JSON json = JSONSerializer.toJSON( bean, jsonConfig )
4. 最后来看JsonBeanProcessor,这种方式和实现JsonString很类似,返回一个代表原来的domain类的合法JSONOBJECT
Java代码
- public class Person {
- private String name;
- private String lastname;
- private Address address;
- // getters & setters
- }
- JsonConfig jsonConfig = new JsonConfig();
- jsonConfig.registerJsonBeanProcessor( Person.class,
- new JsonBeanProcessor(){
- public JSONObject processBean( Object bean, JsonConfig jsonConfig ){
- if( !(bean instanceof Person) ){
- return new JSONObject(true);
- }
- Person person = (Person) bean;
- return new JSONObject()
- .element( "name", person.getName() )
- .element( "lastname", person.getLastname() );
- }
- });
- Person bean = /* initialize */;
- JSON json = JSONSerializer.toJSON( bean, jsonConfig );
And it is here with JsonBeanProcessors where we encounter the second gotcha related to CGlib. As you noticed we registered the processor using Person as target class, but Hibernate returns a Proxy that is not exactly a Person but a subclass (if possible) of Person. The default matching algorithm used by Json-lib will try to match the exact class (using equals), meaning that your processor will not be called when you expect it to be,this is why JsonBeanProcessorMatcher was introduced, now you are be able to write the following code
<textarea class="java:nocontrols:nogutter" cols="80" rows="34" name="srccode">public class Person { private String name; private String lastname; private Address address; // getters & setters } JsonConfig jsonConfig = new JsonConfig(); jsonConfig.registerJsonBeanProcessor( Person.class, new JsonBeanProcessor(){ public JSONObject processBean( Object bean, JsonConfig jsonConfig ){ if( !(bean instanceof Person) ){ return new JSONObject(true); } Person person = (Person) bean; return new JSONObject() .element( "name", person.getName() ) .element( "lastname", person.getLastname() ); } }); jsonConfig.registerJsonBeanProcessorMatcher( new JsonBeanProcessorMatcher(){ public Object getMatch( Class target, Set/*<Class>*/ matches ){ for( Object match : matches ){ if( ((Class)match).isAssignableFrom(target) ){ return match; } } return null; } }); Person bean = /* initialize */; JSON json = JSONSerializer.toJSON( bean, jsonConfig );</textarea>
I hope these examples help dispel some doubts, in any case please feel free to drop by Json-lib‘s forum and mailing lists.