Gson本身并不提供循环引用的直接解决方案。我们可以通过以下方式来解决循环引用的问题:
使用ava关键字transient
- private transient int value = 3;
private transient int value = 3;
在序列化的时候value不会生成到json字符串中。
使用Gson提供的注解@Expose
- @Exclude
- private String value;
@Exclude
private String value;
当然,要使用这个属性必须通过以下语句来构造Gson对象
- new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
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 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;
- }
public boolean shouldSkipField(FieldAttributes f) {
// Foo是一个自定义注解
return f.getAnnotation(Foo.class) != null;
}
一般情况下,我们可以通过根据属性名的判断来实现实现逻辑过滤。当然,在序列化之前,需要用一下代码来构造Gson对象:
- Gson gson = new GsonBuilder()
- .setExclusionStrategies(new MyExclusionStrategy(SomeObject.class))
- .create();
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);
- }
- }
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());
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 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;
- }
- }
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);
- }
- }