Gson:参数被序列化,即使它有@Expose(序列化= false)

2022-09-04 06:38:19

我正在为JSON API编写SDK,我遇到了一个看似奇怪的问题。该 API 在 POST 数据验证方面非常严格,并且不允许在更新资源时存在某些参数,例如 .因此,我添加了资源类的 ID 字段。但是,它似乎仍然序列化此字段,从而导致请求被拒绝。资源类大致如下:id@Expose(serialize = false)

public class Organisation extends BaseObject
{
    public static final Gson PRETTY_PRINT_JSON = new GsonBuilder()
            .setPrettyPrinting()
            .create();

    @Expose(serialize = false)
    @SerializedName("_id")
    private String id;

    @SerializedName("email")
    private String email;

    @SerializedName("name")
    private String name;

    @SerializedName("parent_id")
    private String parentId;

    public String toJson()
    {
        return PRETTY_PRINT_JSON.toJson(this);
    }
}

我的单元测试通过 API 创建一个实例,将新创建的实例作为类参数保存到测试类中,并调用一个 update 方法,该方法将通过更新新资源来测试 SDK 的更新实现。这就是它出错的地方。即使新方法上调用了该方法以将其序列化为更新请求的 JSON,该字段仍然存在,从而导致 API 拒绝更新。测试代码如下所示。请注意代码中的注释。OrganisationtoJson()Organisation_id

@Test
public void testCreateUpdateAndDeleteOrganisation() throws RequestException
{
    Organisation organisation = new Organisation();
    organisation.setParentId(this.ORGANISATION_ID);
    organisation.setName("Java Test Organisation");

    Organisation newOrganisation = this.MySDK.organisation.create(organisation);
    this.testOrganisation(newOrganisation);
    this.newOrganisation = newOrganisation;

    this.testUpdateOrganisation();
}

public void testUpdateOrganisation() throws RequestException
{
    // I tried setting ID to null, but that doesn't work either
    // even though I've set Gson to not serialise null values
    this.newOrganisation.setId(null);
    this.newOrganisation.setName(this.newName);

    // For debugging
    System.out.println(this.newOrganisation.toJson());

    Organisation updatedOrganisation = this.MySDK.organisation.update(this.newOrganisation.getId(), this.newOrganisation);

    this.testOrganisation(updatedOrganisation);
    assertEquals(newOrganisation.getName(), this.newName);

    this.testDeleteOrganisation();
}

任何人都可以发现我做错了什么吗?我有一种感觉,它与实例已经/具有ID值的事实有关,但是如果我明确告诉它不要序列化它,那应该无关紧要吗?

提前感谢您的帮助。

编辑:在 处,不会编辑组织实例。给定的 ID 仅添加到 SDK 将发布到的 URL (this.MySDK.organisation.update(this.newOrganisation.getId(), this.newOrganisation);POST /organisation/{id})


答案 1

感谢@peitek指出,除非添加到 .但是,我选择不采用此路由,因为它需要我添加到模型类的每个参数中,只是为了忽略序列化的一个字段。相反,我编写了一个检查参数上是否存在自定义注释的方法。我实现了这些如下:@Expose.excludeFieldsWithoutExposeAnnotation()GsonBuilder()@ExposeExclusionStrategySkipSerialisation

完整的策略:GsonBuilder

public static final Gson PRETTY_PRINT_JSON = new GsonBuilder()
        .addSerializationExclusionStrategy(new ExclusionStrategy()
        {
            @Override
            public boolean shouldSkipField(FieldAttributes f)
            {
                return f.getAnnotation(SkipSerialisation.class) != null;
            }

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

和注释:

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

现在我可以做

@SkipSerialisation
@SerializedName("_id")
private String id;

它的工作原理!


答案 2

正如您在评论中提到的,应该是这里更好的选择。请务必注意,默认的 Gson 实例不考虑@Expose注释!它会简单地忽略它,无论你设置什么选项。@Exposetransient

如果要激活选项,则需要自定义Gson。根据上面的代码,将其更改为:@Expose

public static final Gson PRETTY_PRINT_JSON = new GsonBuilder()
        .setPrettyPrinting()
        .excludeFieldsWithoutExposeAnnotation();
        .create();

在序列化过程中,您应该处于活动状态并被排除。@Expose(serialize = false)