Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
549 views
in Technique[技术] by (71.8m points)

java - GSON: how to prevent StackOverflowError while keeping circular references?

I have a structure with circular references. And for debug purposes, I want to dump it. Basically as any format, but I chose JSON.

Since it can be any class, I chose GSON which doesn't needs JAXB annotations.

But GSON hits the circular references and recurses until StackOverflowError.

How can I limit GSON to

  • ignore certain class members? Both @XmlTransient and @JsonIgnore are not obeyed.

  • ignore certain object graph paths? E.g. I could instruct GSON not to serialize release.customFields.product.

  • go to the depth of at most 2 levels?

Related: Gson.toJson gives StackOverFlowError, how to get proper json in this case? (public static class)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Simply make the fields transient (as in private transient int field = 4;). GSON understands that.

Edit

No need for a built-in annotation; Gson lets you plug in your own strategies for excluding fields and classes. They cannot be based on a path or nesting level, but annotations and names are fine.

If I wanted to skip fields that are named "lastName" on class "my.model.Person", I could write an exclusion strategy like this:

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;
    }
}

I could also make my own annotation:

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

}

And rewrite the shouldSkipField method as:

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

This would enable me to do things like:

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

    // ...

To use a custom ExclusionStrategy, build Gson object using the builder:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...