Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java GSON:如何在保持循环引用的同时防止堆栈溢出错误?_Java_Json_Serialization_Gson - Fatal编程技术网

Java GSON:如何在保持循环引用的同时防止堆栈溢出错误?

Java GSON:如何在保持循环引用的同时防止堆栈溢出错误?,java,json,serialization,gson,Java,Json,Serialization,Gson,我有一个循环引用的结构。 出于调试目的,我想转储它。基本上和任何格式一样,但我选择了JSON 因为它可以是任何类,所以我选择了不需要JAXB注释的GSON 但是GSON命中循环引用并递归,直到StackOverflowError 如何将GSON限制为 忽略某些类成员? @xmltransive和@JsonIgnore都不遵守 忽略某些对象图路径?例如,我可以指示GSON不要序列化release.customFields.product 最多进入2层的深度 相关:只需将字段设置为瞬态(如私有瞬

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

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

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

如何将GSON限制为

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

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

  • 最多进入2层的深度


相关:

只需将字段设置为瞬态(如
私有瞬态int-field=4;
)。格森明白这一点

编辑

不需要内置注释;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;
    }
}
并将
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();

只需将字段设置为瞬态(如
专用瞬态int-field=4;
)。格森明白这一点

编辑

不需要内置注释;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;
    }
}
并将
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();

我知道这个问题有几年的时间了,但我想提出我的解决方案。 尽管@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#clear()
    方法来重新初始化计数器


  • 我希望这能有所帮助。

    我知道这个问题还有几年的时间,但我想为我的解决方案做出贡献。 尽管@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#clear()
    方法来重新初始化计数器


  • 我希望这有帮助。

    你可能想考虑使用杰克逊来解决这个问题。它有多种处理循环引用的方法,也不需要JAXB注释。您可能需要考虑使用杰克逊来实现。它有多个处理循环引用的方法,也不需要JAXB注释。。。没有特定于GSON的注释?既然它似乎有,那么接受它怎么样。。。?漂亮吗?:-)@翁德拉·伊泽卡:不,真的,我知道要求代表是一种糟糕的形式——所以请不要接受我的回答,甚至不要投票否决我的id(至少还有五个人认为这很有用)。但我真的,真的很好奇-这有什么问题吗?只要几句话就行了……@OndraŽižka:看来除了你自己的答案,你从来没有接受过一个答案?有什么特别的原因吗?@OndraŽižka:不,真的,我甚至不再要求你接受我的回答。我只是想从上面的评论中得到我最后一个问题的答案,如果你是这样的话?好的,但这也会影响Hibernate-这个类也是一个@Entity。。。没有特定于GSON的注释?既然它似乎有,那么接受它怎么样。。。?漂亮吗?:-)@翁德拉·伊泽卡:不,真的,我知道要求代表是一种糟糕的形式——所以请不要接受我的回答,甚至不要投票否决我的id(至少还有五个人认为这很有用)。但我真的,真的很好奇-这有什么问题吗?只要几句话就行了……@OndraŽižka:看来除了你自己的答案,你从来没有接受过一个答案?有什么特别的原因吗?@OndraŽižka:不,真的,我甚至不再要求你接受我的回答。我只是想从上面的评论中回答我的最后一个问题,如果你是这样的话?