Skip to content

SerializationFeature.APPLY_JSON_INCLUDE_FOR_CONTAINERS does not fully remove empty collection during serialization #6065

Description

@doeiqts

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

Hello, I originally raised issue #1649 where @JsonInclude(value=JsonInclude.Include.NON_EMPTY, content=JsonInclude.Include.NON_EMPTY) was not removing some content from the serialized response. It was closed as being fixed for Maps to now work at the class level and the field level.

There was then #5369 which added the same feature that existed for Maps to Collections/Arrays.

However, it seems that the feature does not fully remove empty collections like it does with maps. Using the same test cases as I originally reported...

@JsonInclude(value=JsonInclude.Include.NON_EMPTY, content=JsonInclude.Include.NON_EMPTY)
public class Bean {
    public String myString;

    public List<String> myList;

    public Map<String, String> myMap;
}
@Test
    public void test1() throws Exception {
        ObjectMapper objectMapper = JsonMapper.builder()
                .enable(SerializationFeature.APPLY_JSON_INCLUDE_FOR_CONTAINERS)
                .build();

        String expectedResult = "{}";

        String myString = null;

        List<String> myList = null;

        Map<String, String> myMap = null;

        Bean bean = new Bean();
        bean.myString = myString;
        bean.myList = myList;
        bean.myMap = myMap;

        String result = objectMapper.writeValueAsString(bean);

        assertEquals(expectedResult, result);
    }

@Test
    public void test2() throws Exception {
        ObjectMapper objectMapper = JsonMapper.builder()
                .enable(SerializationFeature.APPLY_JSON_INCLUDE_FOR_CONTAINERS)
                .build();

        String expectedResult = "{}";

        String myString = null;

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

        Map<String, String> myMap = new HashMap<>();

        Bean bean = new Bean();
        bean.myString = myString;
        bean.myList = myList;
        bean.myMap = myMap;

        String result = objectMapper.writeValueAsString(bean);

        assertEquals(expectedResult, result);
    }

@Test
    public void test3() throws Exception {
        ObjectMapper objectMapper = JsonMapper.builder()
                .enable(SerializationFeature.APPLY_JSON_INCLUDE_FOR_CONTAINERS)
                .build();

        String expectedResult = "{}";

        String myString = null;

        List<String> myList = new ArrayList<>();
        myList.add(null);

        Map<String, String> myMap = new HashMap<>();
        myMap.put("1", null);

        Bean bean = new Bean();
        bean.myString = myString;
        bean.myList = myList;
        bean.myMap = myMap;

        String result = objectMapper.writeValueAsString(bean);

        assertEquals(expectedResult, result);
    }

@Test
    public void test4() throws Exception {
        ObjectMapper objectMapper = JsonMapper.builder()
                .enable(SerializationFeature.APPLY_JSON_INCLUDE_FOR_CONTAINERS)
                .build();

        String expectedResult = "{}";

        String myString = "";

        List<String> myList = new ArrayList<>();
        myList.add("");

        Map<String, String> myMap = new HashMap<>();
        myMap.put("1", "");

        Bean bean = new Bean();
        bean.myString = myString;
        bean.myList = myList;
        bean.myMap = myMap;

        String result = objectMapper.writeValueAsString(bean);

        assertEquals(expectedResult, result);
    }

test1 and test2 pass as they did before, but test3 and test4 still fail, though they're slightly better. They both produce...

Expected :{}
Actual   :{"myList":[]}

We can see that the Map is fully removed since everything inside the Map was removed, but the List still exists, even though it's just an empty List (which should be removed by the JsonInclude.Include.NON_EMPTY). So things are better than they previously were for Lists, but still not in parity with Maps.

Version Information

3.2.0

Reproduction

Examples given above in description.

Expected behavior

I'd expect that at each nested level, the JsonInclude.Include.NON_EMPTY check would be applied for any classes at that level that have that annotation and then as the process walks back up the chain to the outer objects/collections/maps that it would then be applied for that outer object once all of the nested values are resolved. So if some nested object becomes empty, then it would be removed which might make the outer object empty which would then also be removed.

The result would be that at all levels of an object, that there would be nothing empty at any point.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions