Gson 试图解析带有 @Expose(false) 注释的字段并崩溃

Posted

技术标签:

【中文标题】Gson 试图解析带有 @Expose(false) 注释的字段并崩溃【英文标题】:Gson trying to parse fields annotated with @Expose(false) and crashing 【发布时间】: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 个字段...

我做错了什么?

【问题讨论】:

【参考方案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,它有不同的方法来管理排除/包含策略***.com/questions/13764280/…【参考方案2】:
excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.TRANSIENT)

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

@Expose(deserialize = false, serialize = false)

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

private transient Long id;

【讨论】:

持久化是什么意思?

以上是关于Gson 试图解析带有 @Expose(false) 注释的字段并崩溃的主要内容,如果未能解决你的问题,请参考以下文章

gson的 Expose注解和 SerializedName注解

Gson——如何忽略用@Expose标记的字段

GSON 不解析布尔值(始终为假)

“无法解析的日期:1302828677828”试图用 Gson 反序列化从服务器接收到的毫秒格式日期

在android中使用GSON解析带有动态“key”和“value”的JSON

通过Gson过滤多余的字段