Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class level @JsonInclude(JsonInclude.Include.NON_EMPTY) is ignored #1327

Closed
elruwen opened this issue Aug 10, 2016 · 8 comments
Closed

Class level @JsonInclude(JsonInclude.Include.NON_EMPTY) is ignored #1327

elruwen opened this issue Aug 10, 2016 · 8 comments
Milestone

Comments

@elruwen
Copy link

elruwen commented Aug 10, 2016

Hi!

I am upgrading from Jackson 2.4.6 to 2.8.1 and I have an issue with a class level @JsonInclude annotation.

The following class runs perfectly with 2.4.6:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;

public class JacksonBug {

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public static class MyObject {

        private String myString;
        private List<String> myList = new ArrayList<>();

        public String getMyString() {
            return myString;
        }

        public void setMyString(String myString) {
            this.myString = myString;
        }

        public List<String> getMyList() {
            return myList;
        }

        public void setMyList(List<String> myList) {
            this.myList = myList;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper om = new ObjectMapper();
        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        final MyObject myObject = new MyObject();
        myObject.setMyString("hehe");

        final String jsonString = om.writeValueAsString(myObject);
        System.out.println(jsonString);

        if (jsonString.contains("myList")) {
            throw new RuntimeException("JsonString contains myList");
        }
    }
}

When I switch to 2.8.1, it does not worker anymore. The list myList is serialised as an empty list: {"myString":"hehe","myList":[]}

I can work around that issue by moving the exclude to the field level.

I guess this is a bug? Or was the behaviour change intended?

Cheers
Ruwen

@cowtowncoder
Copy link
Member

That would appear like a bug, at first glance. Per-class @JsonInclude should override the default settings.

@richturner
Copy link

richturner commented Aug 13, 2016

Similarly if configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false) is set on the mapper then you try and use @JsonInclude(JsonInclude.Include.ALWAYS) annotation on a property that contains an empty array then it is not included. The JsonInclude annotation should take precedence over the global mapper configuration.

@cowtowncoder
Copy link
Member

@richturner I agree, per-property annotation should have precedence over global defaults. I assume it's easy to reproduce, if not I'll ask for repro.

@richturner
Copy link

@cowtowncoder Indeed this is easy to reproduce: -

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false)
.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE)

Simple POJO: -

public class Test {
   @JsonInclude(JsonInclude.Include.ALWAYS)
   protected List<String> strings = new ArrayList<String>();

   public List<String> getStrings() {
      return strings;
   }
}

Output serialised POJO: -

try {
   Test test = new Test();
   String str = mapper.writeValueAsString(test);
   System.out.print(str);
} catch (JsonProcessingException e) {
   e.printStackTrace();
}

@richturner
Copy link

I see that WRITE_EMPTY_JSON_ARRAYS is deprecated from 2.8 onwards, is there an alternative global config for this?

@cowtowncoder
Copy link
Member

@richturner This should be documented better, but 2.8 introduced a way to apply @JsonFormat and @JsonInclude defaults for specific types. In this case @JsonInclude is what you want (javadocs incorrectly refer to @JsonFormat).

From JsonIncludeTest:

    mapper = new ObjectMapper();
    mapper.configOverride(List.class)
        .setInclude(JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, null));

which should have similar effect for List valued properties, further overridable on per-property basis if necessary. For arrays type must be specified (String[].class and so on).

@cowtowncoder
Copy link
Member

As to the problem(s) here: looks like 2.7.x still works as expected, so this looks like a regression in 2.8.
No idea yet why, but wanted to verify version(s) affected, and add failing test. Due to backlog of issues fix may take a while.

cowtowncoder added a commit that referenced this issue Aug 18, 2016
@cowtowncoder cowtowncoder modified the milestones: 2/8.2, 2.8.2 Aug 18, 2016
@cowtowncoder
Copy link
Member

Problem was with handling of multi-level defaulting: there are no fewer than 6 levels (!) of potential inclusion settings for POJO properties now:

  1. Global defaults
  2. Class annotation on containing POJO (one that encloses property in question)
  3. Per-type overrides for containing POJO
  4. Class annotation on type of property
  5. Per-type overrides for type of property
  6. Property annotations on property itself

and care must be taken when applying overrides... turns out (1) was applied multiple times, effectively overriding later settings inappropriately.
I managed to fix reported issue, but it is trick to test all kinds of combinations.

@cowtowncoder cowtowncoder changed the title Classlevel @JsonInclude(JsonInclude.Include.NON_EMPTY) is ignored Class level @JsonInclude(JsonInclude.Include.NON_EMPTY) is ignored Aug 18, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants