Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

361
Visualizações
Gson: parameter get serialised even though it has @Expose(serialize = false)

I'm writing an SDK for a JSON API and I'm running into a seemingly weird problem. The API is quite strict in it's POST data validation and it does not allow certain parameters to be present when updating resources, like an id. For this reason, I added @Expose(serialize = false) the ID field of my resource class. It seems however, that it still serializes this field, causing the request to be rejected. The resource class roughly is as follows:

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

My unit tests create an instance of Organisation via the API, saves the newly created instance to the test class as a class parameter and calls an update method that will test the update implementation of the SDK by updating the new resource. This is where it goes wrong. Even though the toJson() method is called on the new Organisation to serialise it to JSON for the update request, the _id field remains present, causing the API to decline the update. The test code is as follows. Notice the comments in the code.

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

Can anyone spot what I'm doing wrong? I have a feeling it has something to do with the fact that the instance already has/had a value for ID, but that shouldn't matter if I explicity tell it not to serialise it right?

Thanks in advance for the help.

EDIT: At this.MySDK.organisation.update(this.newOrganisation.getId(), this.newOrganisation);, that does not edit the organisation instance. The given ID is merely added to the URL that the SDK will POST to (POST /organisation/{id})

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Thanks to @peitek for pointing out that @Expose is ignored unless .excludeFieldsWithoutExposeAnnotation() is added to the GsonBuilder(). However, I choose not to go with this route as it would require me to add @Expose to every single parameter of my model classes just to ignore one field on serialisation. Instead I wrote a ExclusionStrategy that checks for the presence of a custom SkipSerialisation annotation on the parameter. I implemented these as follows:

The full GsonBuilder with the strategy:

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

And the annotation:

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

Now I can just do

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

and it works!

over 4 years ago · Santiago Trujillo Relatório

0

As you mentioned in your comments, @Expose should be the better choice over transient here. It's important to note that the default Gson instance does not regard the @Expose annotation! It'll simply ignore it, no matter what you set as option.

If you want to activate the @Expose options, you need to customize Gson. Based on your code above, change it to:

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

Your @Expose(serialize = false) should be active and excluded during serialization.

over 4 years ago · Santiago Trujillo Relatório

0

I just wanted to add here that you could use Expose in the desired way like this:

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;
        }
    });
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda