当前位置: 首页 > 知识库问答 >
问题:

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

尉迟边浩
2023-03-14

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

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

但是GSON会命中循环引用并递归,直到StackOverFlow Error

如何将 GSON 限制为

>

  • 忽略某些类成员?不遵守@XmlTransient@JsonIgnore

    忽略某些对象图路径?例如,我可以指示GSON不要序列化< code > release . custom fields . product 。

    达到最多2级的深度?

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

  • 共有2个答案

    平羽
    2023-03-14

    我知道这个问题已经有几年了,但我想为我的解决方案做出贡献。尽管@fdreger的答案在您希望始终排除字段的情况下是完全有效的,但如果您只想在某些情况下排除它,则它不起作用,从而避免这种递归。我处理这个问题的方法是:

    >

  • 我自己编写了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<User> {
    
         private static final ThreadLocal<Integer> depth = new ThreadLocal<Integer>() {
            @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();
         }
    }
    

    UserJsonSerializer 绑定到要控制的类

    public class SomeClass implements Serializable {
        @JsonSerialize(using = UserJsonSerializer.class)
        private User user;
    
       //...others fields...
    }
    

    每次解析新实体时,不要忘记调用UserJsonSeri照相机#明确()方法来重新初始化计数器。

    我希望这能有所帮助。

  • 太叔繁
    2023-03-14

    只需使字段瞬态(如私有瞬态 int 字段 = 4;)。GSON明白这一点。

    编辑

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

    如果我想跳过类“my.model.人”上名为“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";
    
        // ...
    

    要使用自定义排除策略,请使用构建器构建Gson对象:

    Gson g = new GsonBuilder()
           .setExclusionStrategies(new MyOwnExclusionStrategy())
           .create();
    
     类似资料:
    • 问题内容: 我有一个带有循环引用的结构。出于调试目的,我想将其转储。基本上是任何格式,但我选择了JSON。 由于可以是任何类,因此我选择了不需要JAXB批注的GSON。 但是GSON击中了循环引用并递归直到。 如何将GSON限制为 忽略某些班级成员?两者和都不服从。 忽略某些对象图路径?例如,我可以指示GSON不要序列化。 最多达到2个级别的深度? 问题答案: 只需将字段设为瞬态(如中的)。GSO

    • 今天,我开始使用MapSTRt为我的项目创建我的模型到DTO转换器,我想知道它是否自动处理循环引用,但事实证明它没有。 这是我用来测试它的转换器: 这就是测试: Notifica、AvvisionNotifica及其各自的模型都是带有setter和getter的简单POJO,因此我认为无需发布代码(如果您想知道,Notifica扩展了Corrispondenza) 这段代码进入了一个无限的循环,这

    • 我在反序列化遵循以下格式的Json数组时遇到了一些问题: 它基本上是一个类别数组,其中每个类别也可以有一个子类别列表,依此类推。我的类模型看起来有点像这样: 现在,Gson显然抱怨循环引用。有没有办法解析这个Json输入,因为我不能假设有多少个类别级别?提前感谢。 编辑:以防万一有人有类似的问题,根据Spaeth的回答,我将解决方案调整为使用反射的更一般的情况。唯一的要求是JSON数组表示的对象列

    • 我有三块地 小时——分钟——和总数 如果小时或分钟发生变化,我想计算一个总数。如果总数发生变化,我想计算相应的分钟和小时数。 例子: 1h 30分钟=1.5总计 2.25总计=2h 15分钟 我正试图用手表来达到这个目的 但是,这会导致一个循环,因为on处理程序总是调用另一个处理程序。如何以更明智的方式实现这一点?

    • 我搜索了Google、StackOverflow和Github问题,但没有找到任何内容 https://docs.temporal.io/docs/java-implementing-workflows#child-workflows 似乎我可以轻松地创建一个包含多个工作流的圆圈,将其他人称为子工作流。工作流甚至可以一遍又一遍地调用自己。节奏/时间是否提供任何东西来防止这种情况或超出范围? 提前感

    • 我目前正在Leetcode中处理问题1,名为“两个和” 给定一个整数数组,返回两个数字的索引,使它们相加到一个特定的目标。 您可以假设每个输入都有一个精确的解决方案,并且您可以不使用相同的元素两次。 示例:给定, 因为,所以返回。 我目前的代码是: 在这种情况下,Nums是一个整数列表,程序必须在列表中返回两个不同的索引,这样它们的真实值加起来就是给定的目标。尽管这在大多数测试用例上运行良好,但它