Gson——循环引用的解决方案

博客分类:

Gson本身并不提供循环引用的直接解决方案。我们可以通过以下方式来解决循环引用的问题:

 

使用ava关键字transient

 

Java代码 复制代码  收藏代码
  1. private transient int value = 3;  
private transient int value = 3;

在序列化的时候value不会生成到json字符串中。

 

使用Gson提供的注解@Expose

 

Java代码 复制代码  收藏代码
  1. @Exclude  
  2. private String value;  
@Exclude
private String value;

 

 当然,要使用这个属性必须通过以下语句来构造Gson对象

 

Java代码 复制代码  收藏代码
  1. new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()  
new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()

 我们也可以自定义注解来标注需要过滤的属性,参见官方的User Guide,需要使用到过滤策略,在下文也会提到。

 

使用排除策略

 

以上只能是通过“硬编码”的方式来排除属性,有些时候我们需要根据某种来选择性得过滤一些属性。这是我们可以使用使用Gson提供的排除策略ExclusionStrategy接口。如:

 

Java代码 复制代码  收藏代码
  1. public class MyExclusionStrategy implements ExclusionStrategy {   
  2.     private MyExclusionStrategy(Class<?> typeToSkip) {   
  3.          
  4.     }   
  5.   
  6.     public boolean shouldSkipClass(Class<?> clazz) {   
  7.       return false;   
  8.     }   
  9.   
  10.     public boolean shouldSkipField(FieldAttributes f) {   
  11.       return false;   
  12.     }   
  13.   }  
public class MyExclusionStrategy implements ExclusionStrategy {
    private MyExclusionStrategy(Class<?> typeToSkip) {
      
    }

    public boolean shouldSkipClass(Class<?> clazz) {
      return false;
    }

    public boolean shouldSkipField(FieldAttributes f) {
      return false;
    }
  }

 

我们可以通过类级别和属性级别来过滤属性。以上提到的关于自定义注解的实现是在属性级别上实现的。具体方法是

 

Java代码 复制代码  收藏代码
  1. public boolean shouldSkipField(FieldAttributes f) {   
  2.       // Foo是一个自定义注解   
  3.       return f.getAnnotation(Foo.class) != null;   
  4.     }  
public boolean shouldSkipField(FieldAttributes f) {
      // Foo是一个自定义注解
      return f.getAnnotation(Foo.class) != null;
    }

 

一般情况下,我们可以通过根据属性名的判断来实现实现逻辑过滤。当然,在序列化之前,需要用一下代码来构造Gson对象:

 

Java代码 复制代码  收藏代码
  1. Gson gson = new GsonBuilder()   
  2.        .setExclusionStrategies(new MyExclusionStrategy(SomeObject.class))   
  3.        .create();  
 Gson gson = new GsonBuilder()
        .setExclusionStrategies(new MyExclusionStrategy(SomeObject.class))
        .create();

 

自定义序列化器 

在有些情况下,我们可能会为某一个类来绑定一种序列化或反序列化器。

 

Java代码 复制代码  收藏代码
  1. public class MyAdaper1 implements JsonSerializer<DataStore> {   
  2.   
  3.     @Override  
  4.     public JsonElement serialize(DataStore src, Type typeOfSrc,   
  5.             JsonSerializationContext context) {   
  6.         ExclusionStrategy strategy = new DmsExclusionStrategy(   
  7.                 src.getExcludeFields(), src.getExcludeClasses());   
  8.         Gson gson = new GsonBuilder().setExclusionStrategies(strategy)   
  9.                 .serializeNulls().create();   
  10.         return gson.toJsonTree(src);   
  11.     }   
  12. }  
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);
	}
}

 注册序列化器:

 

Java代码 复制代码  收藏代码
  1. GsonBuilder builder = new GsonBuilder();   
  2. builder.registerTypeAdapter(MyType1.classnew MyTypeAdapter())   
  3. .registerTypeAdapter(MyType2.classnew MyTypeAdapter2());  
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MyType1.class, new MyTypeAdapter())
.registerTypeAdapter(MyType2.class, new MyTypeAdapter2());

 

最佳实践——综合使用自定义序列化器和排除策略

通常情况下,我们一下如下定义排除策略

 

Java代码 复制代码  收藏代码
  1. public class DmsExclusionStrategy implements ExclusionStrategy {   
  2.     public DmsExclusionStrategy() {   
  3.   
  4.     }   
  5.   
  6.     public DmsExclusionStrategy(String[] excludeFields,   
  7.             Class<?>[] excludeClasses) {   
  8.         this.excludeFields = excludeFields;   
  9.         this.excludeClasses = excludeClasses;   
  10.     }   
  11.   
  12.     private String[] excludeFields;   
  13.     private Class<?>[] excludeClasses;   
  14.   
  15.     public boolean shouldSkipClass(Class<?> clazz) {   
  16.         if (this.excludeClasses == null) {   
  17.             return false;   
  18.         }   
  19.   
  20.         for (Class<?> excludeClass : excludeClasses) {   
  21.             if (excludeClass.getName().equals(clazz.getName())) {   
  22.                 return true;   
  23.             }   
  24.         }   
  25.   
  26.         return false;   
  27.     }   
  28.   
  29.     public boolean shouldSkipField(FieldAttributes f) {   
  30.         if (this.excludeFields == null) {   
  31.             return false;   
  32.         }   
  33.   
  34.         for (String field : this.excludeFields) {   
  35.             if (field.equals(f.getName())) {   
  36.                 return true;   
  37.             }   
  38.         }   
  39.   
  40.         return false;   
  41.     }   
  42.   
  43.     public final String[] getExcludeFields() {   
  44.         return excludeFields;   
  45.     }   
  46.   
  47.     public final Class<?>[] getExcludeClasses() {   
  48.         return excludeClasses;   
  49.     }   
  50. }  
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;
	}
}
 

定义一个排除模型:

 

 

Java代码 复制代码  收藏代码
  1. public class Excludable {   
  2.     /**  
  3.      * 不需要序列化的域.  
  4.      */  
  5.     private transient String[] excludeFields;   
  6.   
  7.     /**  
  8.      * 不需要序列化的类.  
  9.      */  
  10.     private transient Class<?>[] excludeClasses;   
  11.   
  12.     public void setExcludeFields(String[] excludeFields) {   
  13.         this.excludeFields = excludeFields;   
  14.     }   
  15.   
  16.     public String[] getExcludeFields() {   
  17.         return excludeFields;   
  18.     }   
  19.   
  20.     public void setExcludeClasses(Class<?>[] excludeClasses) {   
  21.         this.excludeClasses = excludeClasses;   
  22.     }   
  23.   
  24.     public Class<?>[] getExcludeClasses() {   
  25.         return excludeClasses;   
  26.     }   
  27. }  
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,自定义其相应的序列化器,在序列化的过程中应用排除策略。

 

Java代码 复制代码  收藏代码
  1. public class MyTypeSerializer implements JsonSerializer<MyType> {   
  2.   
  3.     @Override  
  4.     public JsonElement serialize(MyType src, Type typeOfSrc,   
  5.             JsonSerializationContext context) {   
  6.         ExclusionStrategy strategy = new DmsExclusionStrategy(   
  7.                 src.getExcludeFields(), src.getExcludeClasses());   
  8.         Gson gson = new GsonBuilder().setExclusionStrategies(strategy)   
  9.                 .serializeNulls().create();   
  10.         return gson.toJsonTree(src);   
  11.     }   
  12. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值