Rufi
Rufi

Reputation: 2645

Response does not contain zero integers

I have restful API and use Jetty as a server. I send a post request to create my object which contains some skill list. Skill contains of String id and Integer value fields. When I use 0 or "0" for my Integer field with the get response I get the skill array without value field at all.

@XmlRootElement
@JsonAutoDetect(isGetterVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE,
        creatorVisibility = Visibility.NONE, fieldVisibility = Visibility.NONE)
public class Skill
{

    @com.fasterxml.jackson.annotation.JsonProperty(value="id")
    @javax.validation.constraints.NotNull
    private java.lang.String _id;

    @com.fasterxml.jackson.annotation.JsonProperty(value="value")
    @javax.validation.constraints.NotNull
    private java.lang.Integer _value;

    // getters and setters
}

My request body is like this:

{
  // some other fields
  "skills": [{
    "id":"Swedish",
    "value":0
  },{
    "id":"Finnish",
    "value":"0"
  }]
}

After applying necessary changes to my object I pass it to be returned via this line:

Response.ok().entity(myObject).build();

The body of the get response is like this:

{
  // some other fields
  "skills" : [ {
    "id" : "Finnish"
  }, {
    "id" : "Swedish"
  } ]
}

With other values everything works fine, however, 0 seems to be so special that it doesn't even include this field to the object.

The question is Why and How can I solve it?

Upvotes: 1

Views: 3476

Answers (4)

Matthew Kuraja
Matthew Kuraja

Reputation: 401

I had the same problem but I didn't use @javax.validation.constraints.NotNull.

What I had was

ObjectMapper objectMapper = new org.codehaus.jackson.map.ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_EMPTY);

MyClass myClass = new MyClass();
myClass.setStringField("some value");
myClass.setIntField(0);

String json = objectMapper.writeValueAsString(myClass);

System.out.println(json);    // --> { "stringField" : "some value" }

It didn't print the intField with value zero. All I had to change was the NON_EMPTY rule to this:

objectMapper.setSerializationInclusion(Include.NON_ABSENT);
String json = objectMapper.writeValueAsString(myClass);
System.out.println(json);    // --> { "stringField" : "some value" }

Upvotes: 0

Rufi
Rufi

Reputation: 2645

The problem is in version of Jackson library.

When we add JsonFeature by default we have serializeJsonEmptyValues=false.

In this case in the method JsonFeature#initDefaultObjectMapper we will come to the point where we do objMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

If we have a look to the javaDoc of NON_EMPTY field, we will see the following:

Compatibility note: Jackson 2.6 included a wider range of "empty" values than either earlier (up to 2.5) or later (2.7 and beyond) types; specifically: Default values of primitive types (like 0 for int/java.lang.Integer and false for bool/Boolean) Timestamp 0 for date/time types With 2.7, definition has been tightened back to only containing types explained above (null, absent, empty String, empty containers), and now extended definition may be specified using NON_DEFAULT.

So, which means that if you use the version 2.6 the zeros will disappear. And this happens to be in our project because we use Redisson which uses the version 2.6. of Jackson library.

Upvotes: 1

Rufi
Rufi

Reputation: 2645

The problem is not in Jetty, Jersey or YaaS. The problem seems to be in Jackson. Jackson does the serialization/deserialization and seems to have some optimization, thus zeros are skipped.

Unfortunately I haven't found any resource yet which says exactly why would you skip 0 and I didn't manage to find the place in Jackson code where this happens.

Possible solutions:

  1. Use annotation @JsonInclude(JsonInclude.Include.ALWAYS) for your field and it will not be skipped.
  2. Don't allow zeros for your Integer field.
  3. Use String type instead of Integer.

The problem is that my object is generated by YaaS, thus, I cannot just change by generated object and not sure if YaaS has the possibility to generate the object with the annotation from the 1 item. I assume that in this case the 2 option might be the best.

Upvotes: 1

Maxim Berezovsky
Maxim Berezovsky

Reputation: 497

you have different value types for similar keys: int 0 for "value" of "Swedish" and String "0" for "value" of "Finnish". This may cause problem if some kind of object by fields building is involved.

Upvotes: 0

Related Questions