Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

355
Views
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})

about 4 years ago · Santiago Trujillo
3 answers
Answer question

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!

about 4 years ago · Santiago Trujillo Report

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.

about 4 years ago · Santiago Trujillo Report

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;
        }
    });
about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!