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

bzzcjhmw  于 2023-10-18  发布在  其他
关注(0)|答案(4)|浏览(125)

我正在为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);
    }
}

我的单元测试通过API创建了一个Organisation的示例,将新创建的示例作为类参数保存到测试类中,并调用一个更新方法,该方法将通过更新新资源来测试SDK的更新实现。这就是问题所在。即使在新的Organisation上调用toJson()方法将其序列化为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();
}

有人能看出我哪里做错了吗?我有一种感觉,这与示例已经有/有ID值的事实有关,但如果我明确告诉它不要序列化它,那就没关系了,对吗?
先谢谢你的帮助。
EDIT:在this.MySDK.organisation.update(this.newOrganisation.getId(), this.newOrganisation);中,不会编辑组织示例。给定的ID只是添加到SDK将POST到的URL(POST /organisation/{id}

55ooxyrt

55ooxyrt1#

感谢@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();

注解:

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

现在我只能

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

而且很有效!

5n0oy7gb

5n0oy7gb2#

正如您在评论中提到的,@Expose应该是比transient更好的选择。需要注意的是,默认Gson示例不考虑@Expose注解!不管你设置了什么选项,它都会忽略它。
如果你想激活@Expose选项,你需要自定义Gson。根据上面的代码,将其更改为:

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

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

nhjlsmyf

nhjlsmyf3#

我只是想在这里补充一下,你可以像这样以所需的方式使用Expose:

builder.addSerializationExclusionStrategy(new ExclusionStrategy() {
        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            Expose annotation = f.getAnnotation(Expose.class);
            if(annotation != null)
                return !annotation.serialize();
            else
                return false;
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            Expose annotation = clazz.getAnnotation(Expose.class);
            if(annotation != null)
                return !annotation.serialize();
            else
                return false;
        }
    });
    builder.addDeserializationExclusionStrategy(new ExclusionStrategy() {
        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            Expose annotation = f.getAnnotation(Expose.class);
            if(annotation != null)
                return !annotation.deserialize();
            else
                return false;
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            Expose annotation = clazz.getAnnotation(Expose.class);
            if(annotation != null)
                return !annotation.deserialize();
            else
                return false;
        }
    });
s5a0g9ez

s5a0g9ez4#

GsonBuilder()
        /**   WARN : the function result is :
         *         just Serialization the field and class which with @Expose
         * */
        /*.excludeFieldsWithoutExposeAnnotation()*/


          /** addXxxxxxxxxExclusionStrategy Function is the best selection
                 define yourself exclusion rule
          */
        .addSerializationExclusionStrategy(
            object : ExclusionStrategy {
                override fun shouldSkipField(fieldAttr: FieldAttributes?): Boolean {
                    return fieldAttr?.getAnnotation(Expose::class.java)?.serialize == false
                }

                override fun shouldSkipClass(clazz: Class<*>?): Boolean {
                    return clazz?.getAnnotation(Expose::class.java)?.serialize == false
                }
            })
        .addDeserializationExclusionStrategy(object : ExclusionStrategy {

            override fun shouldSkipField(fieldAttr: FieldAttributes?): Boolean {
                return fieldAttr?.getAnnotation(Expose::class.java)?.deserialize == false
            }

            override fun shouldSkipClass(clazz: Class<*>?): Boolean {
                return clazz?.getAnnotation(Expose::class.java)?.deserialize == false
            }
        })
        .create()

相关问题