Philip Voronov Philip Voronov - 1 month ago 8
Java Question

Gson: skip different fields with different gsons

Problem



Let us have a class:

class A {
int common;
int forGSON1;
int forGSON2;
int forGSON3;
int forGSON12;
}


For one situation I want to skip some fields during serialization, for different situation I want to skip some other ones; what fields I want to skip is fixed for each situation. For example, in situation #1 I want to save
common
,
forGSON1
and
forGSON12
; in situation #2 -
common
,
forGSON2
and
forGSON12
; in situation #3 -
common
,
forGSON3
.

What have I tried



I don't want to solve this via creating and then serializing a partial copy of the object (for me it's a bad solution). I suppose it can be done via different
Gson
objects, built with different configurations. If we have two situations we can use
@Expose
annotation and build
Gson
object for one situation with skipping fields with the annotation (via
.excludeFieldsWithoutExposeAnnotation()
) and other
Gson
object with keeping fields with the annotation and we can also use modifier
transient
(and even more existing modifiers) as mark for different behavior of our
Gson
s (via
.excludeFieldsWithModifiers
). But it will work for only few (2-3) situations (and the solution is more
hack
than normal solution); unfortunately I haven't found method like
.excludeFieldsWithoutAnnotation(customAnnotation)
.

How can I solve this problem?

Answer

This can be achieved using custom exclude strategy. Here is the code.

1) Create custom exclude annotations

2) Create custom exclude strategy classes

3) Use the exclude strategy class while creating Gson object

Exclude Strategy Classes:-

public class Strategy1 implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Strategy1Exclude.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}

public class Strategy2 implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Strategy2Exclude.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}

public class Strategy3 implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Strategy3Exclude.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}

Exclude Annotations:-

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Strategy1Exclude {    
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Strategy2Exclude {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Strategy3Exclude {
}

Class A:-

public class A {


    int common;

    @Strategy3Exclude
    @Strategy2Exclude
    int forGSON1;

    @Strategy3Exclude
    @Strategy1Exclude
    int forGSON2;


    @Strategy2Exclude
    @Strategy1Exclude
    int forGSON3;

    @Strategy3Exclude
    int forGSON12;
    ...
    getters and setters
}

Main method:-

public static void main(String[] args) {

        A a = new A();
        a.setCommon(1);
        a.setForGSON1(2);
        a.setForGSON12(12);
        a.setForGSON3(3);
        a.setForGSON2(2);

        Gson gsonStrategy1 = new GsonBuilder().setExclusionStrategies(new Strategy1()).create();
        Gson gsonStrategy2 = new GsonBuilder().setExclusionStrategies(new Strategy2()).create();
        Gson gsonStrategy3 = new GsonBuilder().setExclusionStrategies(new Strategy3()).create();

        System.out.println(gsonStrategy1.toJson(a));
        System.out.println(gsonStrategy2.toJson(a));
        System.out.println(gsonStrategy3.toJson(a));
    }

Output:-

{"common":1,"forGSON1":2,"forGSON12":12}
{"common":1,"forGSON2":2,"forGSON12":12}
{"common":1,"forGSON3":3}