GSON:如何在保持循环引用的同时防止StackOverflowError?

我有一个带循环引用的结构。 出于调试目的,我想转储它。 基本上任何格式,但我选择了JSON。

因为它可以是任何类,所以我选择了不需要JAXB注释的GSON。

但是GSON命中循环引用并递归直到StackOverflowError

我怎样才能限制GSON

  • 忽略某些class级成员? @XmlTransient@JsonIgnore都没有服从。

  • 忽略某些对象图路径? 例如,我可以指示GSON不要序列化release.customFields.product

  • 去最多2个级别的深度?

相关: Gson.toJson给出了StackOverFlowError,在这种情况下如何获得正确的json? (公共静态类)

只需使字段成为瞬态(如private transient int field = 4; )。 GSON理解这一点。

编辑

无需内置注释; Gson允许您插入自己的策略来排除字段和类。 它们不能基于路径或嵌套级别,但注释和名称都可以。

如果我想跳过类“my.model.Person”上名为“lastName”的字段,我可以写一个这样的排除策略:

 class MyExclusionStrategy implements ExclusionStrategy { public boolean shouldSkipField(FieldAttributes fa) { String className = fa.getDeclaringClass().getName(); String fieldName = fa.getName(); return className.equals("my.model.Person") && fieldName.equals("lastName"); } @Override public boolean shouldSkipClass(Class type) { // never skips any class return false; } } 

我也可以自己做一个注释:

 @Retention(RetentionPolicy.RUNTIME) public @interface GsonRepellent { } 

并将shouldSkipField方法重写为:

 public boolean shouldSkipField(FieldAttributes fa) { return fa.getAnnotation(GsonRepellent.class) != null; } 

这将使我能够做到这样的事情:

 public class Person { @GsonRepellent private String lastName = "Troscianko"; // ... 

要使用自定义ExclusionStrategy,请使用构建器构建Gson对象:

 Gson g = new GsonBuilder() .setExclusionStrategies(new MyOwnExclusionStrategy()) .create(); 

我知道这个问题已经有几年了,但我想为我的解决方案做出贡献。 虽然@fdreger的答案在你想要总是排除一个字段的情况下是完全有效的,但如果你想在某些情况下排除它,它就不起作用,避免这种方式递归。 我解决问题的方法是:

  1. 我写自己的JsonSerializer 。 在其中,我定义了一个静态变量来控制同一个类的对象序列化的次数,并且根据值,该对象可以被序列化或不被序列化。

      import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; public class UserJsonSerializer extends JsonSerializer { private static final ThreadLocal depth = new ThreadLocal() { @Override protected Integer initialValue() { return 0; } }; @Override public void serialize(User user, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException { // Here, we limit the number of instances to return. In this case, just 1. depth.set(depth.get() + 1); if(depth.get() >= 1) { generator.writeNull(); } else { generator.writeObject(user); } } public static void clear() { depth.remove(); } } 
  2. UserJsonSerializer绑定到要控制的类

     public class SomeClass implements Serializable { @JsonSerialize(using = UserJsonSerializer.class) private User user; //...others fields... } 
  3. 每次要解析新实体时,不要忘记调用UserJsonSerializer#clear()方法重新初始化计数器。

我希望这有帮助。