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