【问题标题】:Gson trying to parse fields annotated with @Expose(false) and crashingGson 试图解析带有 @Expose(false) 注释的字段并崩溃
【发布时间】:2018-12-23 10:15:23
【问题描述】:

我正在尝试使用 Gson 将一个非常基本的对象序列化为 JSON。

这是课程

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

如您所见,我有 2 个字段我不想被序列化,所以我用 expose = false 注释它们,但即使使用这个 Gson 试图序列化它们并由于 OutOfMemory 而崩溃。 (UserOnGiveaway 对 Giveaway 有一个循环引用,这解释了它崩溃的原因。)

Gson 代码是:

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

我不想使用.excludeFieldsWithoutExposeAnnotation(),因为它迫使我编写不必要的内容并注释所有内容以排除 1 个字段...

我做错了什么?

【问题讨论】:

    标签: android json gson


    【解决方案1】:

    在您的 attendantsTickets 字段上使用 transient Java 关键字,不要在您的情况下使用 @Expose

    来自文档https://github.com/google/gson/blob/master/UserGuide.md: “如果一个字段被标记为瞬态,(默认情况下)它会被忽略并且不包含在 JSON 序列化或反序列化中。”

    private transient List<UserOnGiveaway> attendantsTickets;
    

    还可以查看这个 Gson 配置选项:GsonBuilder.excludeFieldsWithModifiers(int... modifiers)

    更多关于transient在java中的信息你可以在这里阅读https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3


    如果您的代码依赖于瞬态行为,例如 JPA 或其他数据映射工具,您将不得不使用 Gson 排除策略。

    您可以像这样创建注释并用它标记应该受自定义序列化影响的字段,然后在排除策略代码中使用它:

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

    【讨论】:

    • 它不起作用,因为它是一个域对象,我需要持久化它,用瞬态标记它们会使我的持久性框架忽略它们
    • 好的,那么你需要使用自定义排除策略。您可以创建注释并用它标记要排除的字段,将代码添加到我的答案中,见上文。
    • 这可能会起作用,但我仍然不喜欢这种方法,如果我明确告诉它不要这样做,为什么 gson 会试图解析某些东西......无论如何,如果我需要自己制作@987654331 @我不需要创建一个新的注释,我可以简单地使用Gson选择忽略的那个
    • @RafaelLima 我不知道为什么 Gson 开发人员决定实施 Expose 策略,而不是实施类似 Hide 策略的东西。如果你愿意,你可以尝试切换到 Jackson,它有不同的方法来管理排除/包含策略stackoverflow.com/questions/13764280/…
    【解决方案2】:
    excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.TRANSIENT)
    

    它说明如果任何变量被声明为最终、静态或瞬态,则不会被序列化(和反序列化)。 所以,而不是@Expose 注释

    @Expose(deserialize = false, serialize = false)
    

    使用上述三个关键字中的任何一个,即:

    private transient Long id;
    

    【讨论】:

    • 持久化是什么意思?
    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 2023-03-19
    • 2019-09-16
    • 2016-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多