10

I'm trying to serialize one very basic object to JSON with Gson.

Here is the class

@org.greenrobot.greendao.annotation.Entity
public class Giveaway {

    @Id(autoincrement = true)
    @Expose(serialize = false,deserialize = false)
    private Long id;

    @NotNull
    private String owner;

    private Date raffleDate;
    private String thumbnailUrl;

    @ToMany(referencedJoinProperty = "giveawayId")
    private List<Influencer> mustFollowList;


    @NotNull
    @Convert(converter = GiveawayCommentTypeConverter.class, columnType = Integer.class)
    private GiveawayCommentType tipo;


    private String specifWordValue;
    private Integer amountFriendsToIndicate;

    @NotNull
    @Unique
    private String mediaId;


    //to reflect the relationships
    @ToMany(referencedJoinProperty = "raffle")
    @Expose(deserialize = false, serialize = false)
    private List<UserOnGiveaway> attendantsTickets;
}

As you can see I've 2 fields that i DONT WANT to be serialized so I annotated them with expose = false, but even with this Gson is trying to serialize them and crashing due OutOfMemory. (UserOnGiveaway has a circular reference with Giveaway and this explains why it crashes.)

The Gson code is:

        Gson parser = new GsonBuilder().setPrettyPrinting().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.TRANSIENT).create();
        StringBuilder sb = new StringBuilder(200);
        try {
            for (Giveaway g : this.dao.getGiveawayDao().loadAll())
                sb.append(parser.toJson(g) + "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }

I didn't want to use .excludeFieldsWithoutExposeAnnotation() since it forces me to write way more than necessary and anotate everything just to exclude 1 field...

What am I doing wrong?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Rafael Lima
  • 3,079
  • 3
  • 41
  • 105

2 Answers2

1

Use transient Java keyword on your attendantsTickets field and don't use @Expose for your case.

From documentation https://github.com/google/gson/blob/master/UserGuide.md: "If a field is marked transient, (by default) it is ignored and not included in the JSON serialization or deserialization."

private transient List<UserOnGiveaway> attendantsTickets;

Also check out this Gson configuration option: GsonBuilder.excludeFieldsWithModifiers(int... modifiers)

More info about transient in java you can read here https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3


In case if your code relays on transient behavior, like JPA or other data mapping tools you will have to use Gson exclusion strategy.

You can create annotation and mark with it fields which should be affected by custom serialisation like this, then use it in your exclusion strategy code:

    @Target(value = ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface ExcludeFromJson {
    }

.........

    void gson() {

        new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
          @Override
          boolean shouldSkipField(FieldAttributes f) {
            return f.getAnnotation(ExcludeFromJson.class) != null;
          }

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

..........

@ExcludeFromJson
private transient List<UserOnGiveaway> attendantsTickets;
Dmitry
  • 812
  • 8
  • 13
  • it doesn't work since it is a domain object and i need to persist it, marking them with transient would make my persistence framework ignore them – Rafael Lima Jul 23 '18 at 19:16
  • ok, then you need to use custom exclude strategy. You can create annotation and mark with it field to exclude, will add code to my answer, see above. – Dmitry Jul 23 '18 at 19:27
  • This will probably work but I still dont like the aproach, why the hell is gson trying to parse something if I explicitly told it to not do... Anyway if I need to make my own `ExclusionStrategy` I dont need to create a new annotation, i could simple use the one `Gson` is choosing to ignore – Rafael Lima Jul 23 '18 at 21:31
  • @RafaelLima I don't know why Gson developers decided to implement Expose strategy, but not to implement something like Hide strategy. You can try to switch to Jackson if you would like, it has different approach to manage Exclude/Include strategy https://stackoverflow.com/questions/13764280/how-do-i-exclude-fields-with-jackson-not-using-annotations – Dmitry Jul 24 '18 at 11:13
0
excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.TRANSIENT)

It states if any of the variables are declared either final, static or transient won't be serialized (and deserialized). So, instead of @Expose annotation

@Expose(deserialize = false, serialize = false)

use any of the above three keywords, i.e:

private transient Long id;
isamirkhaan1
  • 749
  • 7
  • 19