Search code examples
javajsonserializationgson

Execution strategy in GsonBuilder is not applied


I have the following example:

public class A implements Serializable {
    int a;
    B b;
    ...

    @Override
    public String toString() {
        Gson gson = new Gson();
        return gson.toJson(this);
    }

}
public class B implements Serializable {
    int c;
    byte[] d;
    ...

    @Override
    public String toString() {
        Gson gson = new GsonBuilder().setExclusionStrategies(new BExclusionStrategy()).create();
        return gson.toJson(this);
    }

    public class BExclusionStrategy implements ExclusionStrategy {
    @Override
    public boolean shouldSkipClass(Class<?> arg0) {
        return false;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes attr) {
        return attr.getName().equals("d") && attr.getDeclaringClass() == B.class;
    }
    }
}

I want to exclude filed d when calling the toString method of class A, because the byte array is extremely long. But if i specify the execution strategy in class B it does not apply when calling A.toString(). But if I move the execution strategy to the toString method of class A it does work and field d is omitted.

Why is this so? Also class B is used in multiple different classes, and I want to omit printing d for all of them.

Why is this so? Also class B is used in multiple different classes, and I want to omit printing d for all of them.

Note: I don't want to use transient byte[] d, this would solve the printing issue though. I also tried @Exclude on the other fileds of class B and excludeFieldsWithoutExposeAnnotation() but it also did not work.


Solution

  • But if i specify the execution strategy in class B it does not apply when calling A.toString(). But if I move the execution strategy to the toString method of class A it does work and field d is omitted.

    Why is this so?

    Because when you call A.toString() which calls Gson, it uses reflection to serialize the fields of A and then B. Due to this B.toString() is never called and therefore your exclusion strategy specified there has no effect.

    I also tried @Exclude on the other fields of class B

    Gson has no @Exclude annotation, it only has @Expose. That @Exclude annotation might come from a different library, but Gson will just ignore it.

    The easiest solution would be to use the transient field modifier. If you don't want to do that, then you could instead create a single Gson instance configured with your custom exclusion strategy which is then used by all of the toString() methods. You could also make the exclusion strategy more general by creating your own @Exclude annotation or similar and having the exclusion strategy check for that.

    However, since your concern seems to be the length of the byte array byte[] d, you could alternatively use Gson's @JsonAdapter annotation on that field to specify a custom adapter which creates a more concise JSON representation of the array.