Gson——循环摘引的解决方案
Gson——循环引用的解决方案
Gson本身并不提供循环引用的直接解决方案。我们可以通过以下方式来解决循环引用的问题:
使用ava关键字transient
private transient int value = 3;
在序列化的时候value不会生成到json字符串中。
使用Gson提供的注解@Expose
@Exclude private String value;
当然,要使用这个属性必须通过以下语句来构造Gson对象
new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
我们也可以自定义注解来标注需要过滤的属性,参见官方的User Guide,需要使用到过滤策略,在下文也会提到。
使用排除策略
以上只能是通过“硬编码”的方式来排除属性,有些时候我们需要根据某种来选择性得过滤一些属性。这是我们可以使用使用Gson提供的排除策略ExclusionStrategy接口。如:
public class MyExclusionStrategy implements ExclusionStrategy { private MyExclusionStrategy(Class<?> typeToSkip) { } public boolean shouldSkipClass(Class<?> clazz) { return false; } public boolean shouldSkipField(FieldAttributes f) { return false; } }
我们可以通过类级别和属性级别来过滤属性。以上提到的关于自定义注解的实现是在属性级别上实现的。具体方法是
public boolean shouldSkipField(FieldAttributes f) { // Foo是一个自定义注解 return f.getAnnotation(Foo.class) != null; }
一般情况下,我们可以通过根据属性名的判断来实现实现逻辑过滤。当然,在序列化之前,需要用一下代码来构造Gson对象:
Gson gson = new GsonBuilder() .setExclusionStrategies(new MyExclusionStrategy(SomeObject.class)) .create();
自定义序列化器
在有些情况下,我们可能会为某一个类来绑定一种序列化或反序列化器。
public class MyAdaper1 implements JsonSerializer<DataStore> { @Override public JsonElement serialize(DataStore src, Type typeOfSrc, JsonSerializationContext context) { ExclusionStrategy strategy = new DmsExclusionStrategy( src.getExcludeFields(), src.getExcludeClasses()); Gson gson = new GsonBuilder().setExclusionStrategies(strategy) .serializeNulls().create(); return gson.toJsonTree(src); } }
注册序列化器:
GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(MyType1.class, new MyTypeAdapter()) .registerTypeAdapter(MyType2.class, new MyTypeAdapter2());
最佳实践——综合使用自定义序列化器和排除策略
通常情况下,我们一下如下定义排除策略
public class DmsExclusionStrategy implements ExclusionStrategy { public DmsExclusionStrategy() { } public DmsExclusionStrategy(String[] excludeFields, Class<?>[] excludeClasses) { this.excludeFields = excludeFields; this.excludeClasses = excludeClasses; } private String[] excludeFields; private Class<?>[] excludeClasses; public boolean shouldSkipClass(Class<?> clazz) { if (this.excludeClasses == null) { return false; } for (Class<?> excludeClass : excludeClasses) { if (excludeClass.getName().equals(clazz.getName())) { return true; } } return false; } public boolean shouldSkipField(FieldAttributes f) { if (this.excludeFields == null) { return false; } for (String field : this.excludeFields) { if (field.equals(f.getName())) { return true; } } return false; } public final String[] getExcludeFields() { return excludeFields; } public final Class<?>[] getExcludeClasses() { return excludeClasses; } }
定义一个排除模型:
public class Excludable { /** * 不需要序列化的域. */ private transient String[] excludeFields; /** * 不需要序列化的类. */ private transient Class<?>[] excludeClasses; public void setExcludeFields(String[] excludeFields) { this.excludeFields = excludeFields; } public String[] getExcludeFields() { return excludeFields; } public void setExcludeClasses(Class<?>[] excludeClasses) { this.excludeClasses = excludeClasses; } public Class<?>[] getExcludeClasses() { return excludeClasses; } }
当我们需要为某个类应用过滤策略时,我们让这个类继承Excludable,自定义其相应的序列化器,在序列化的过程中应用排除策略。
public class MyTypeSerializer implements JsonSerializer<MyType> { @Override public JsonElement serialize(MyType src, Type typeOfSrc, JsonSerializationContext context) { ExclusionStrategy strategy = new DmsExclusionStrategy( src.getExcludeFields(), src.getExcludeClasses()); Gson gson = new GsonBuilder().setExclusionStrategies(strategy) .serializeNulls().create(); return gson.toJsonTree(src); } }
1 楼
遇见的秘密花园
2012-03-15
我没怎么看懂。。。我现在在做S2H集成的时候。遇到一个问题。dept 和 emp 我想点击部门名称时,异步显示 相应的emp 表的员工。可是,因为Hibernate会自动生成一些字段。。。我用@Util 把它过滤了。但是 我在JSP页面又要用到dept.dname 我该怎么办呀?
2 楼
strong_fee
2012-03-16
你可以从后台返回dept对象,这个对象里边包含emp集合。
3 楼
johlon
2012-04-26
能不能发个Demo看看,谢谢!