Gson:即使具有@Expose(serialize = false),参数也会被序列化

Roe*_*ker 6 java json gson

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

@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();
}
Run Code Online (Sandbox Code Playgroud)

谁能发现我在做什么错?我觉得它与实例已经具有ID值有关,但是如果我明确告诉它不要序列化就没关系了吗?

在此先感谢您的帮助。

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

pei*_*tek 6

正如您在评论中提到的,这里@Expose应该是更好的选择transient。重要的是要注意,默认的Gson实例不考虑@Expose注释!无论您将其设置为什么选项,它都将忽略它。

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

public static final Gson PRETTY_PRINT_JSON = new GsonBuilder()
        .setPrettyPrinting()
        .excludeFieldsWithoutExposeAnnotation();
        .create();
Run Code Online (Sandbox Code Playgroud)

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

  • 您好,谢谢您的回答。我认为 `excludeFieldsWithoutExposeAnnotation()` 完全符合名称的建议,但是如果我想做一些特定的事情,`Expose` 仍然可以工作。这确实意味着我必须将 Expose 添加到所有模型中的每个字段,对吗? (2认同)

Roe*_*ker 6

感谢@peitek指出,@Expose除非.excludeFieldsWithoutExposeAnnotation()将其添加到中,否则将忽略该内容GsonBuilder()。但是,我选择不采用这种方法,因为这将需要我添加@Expose到模型类的每个参数中,而忽略序列化中的一个字段。取而代之的是,我写了一个ExclusionStrategy,检查SkipSerialisation参数上是否存在自定义注释。我将这些实现如下:

完整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();
Run Code Online (Sandbox Code Playgroud)

和注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SkipSerialisation
{
}
Run Code Online (Sandbox Code Playgroud)

现在我可以做

@SkipSerialisation
@SerializedName("_id")
private String id;
Run Code Online (Sandbox Code Playgroud)

而且有效!