FasterXML / FasterXML/jackson-databind
`JsonInclude.Include.NON_DEFAULT` doesn't seem to be working with collections/objects
- Dominant language
- Java
- Stars
- 3.7k
- Forks
- 1.5k
- Avg merge
- 3d 6h
- Merged PRs (30d)
- 28
Description
### Search before asking
- [x] I searched in the [issues](https://github.com/FasterXML/jackson-databind/issues) and found nothing similar.
### Describe the bug
Hello, I'm not 100% sure whether this is not working, not currently supported, or if I'm just doing it wrong. This can be considered a continuation of https://github.com/FasterXML/jackson-databind/issues/6065 for context.
After the above issue was fixed, I was doing some more testing with objects and found that it doesn't seem to remove sub-objects when those objects become empty. I looked further and it seemed that for POJOs to be removed in addition to scalar and collections/maps, I should use `JsonInclude.Include.NON_DEFAULT` instead. However, not only did it not seem to remove empty POJOs, it seemed to no longer be removing empty scalars/collections/maps within those POJOs, thus making the POJOs themselves non-default and thus not getting removed.
It was my understanding from the docs that non-POJOs would be treated as if `NON_EMPTY` was set, among other details listed.
I first tried the following object...
```
@JsonInclude(value=JsonInclude.Include.NON_EMPTY, content=JsonInclude.Include.NON_EMPTY)
public class Bean {
public String myString;
public Bean myBean;
public List myList;
public List myListOfBean;
public Map myMap;
public Map myMapOfBean;
public List> myListOfMapOfString;
}
```
with the following test...
```
@Test
public void test6() throws Exception {
final ObjectMapper objectMapper = JsonMapper.builder()
.enable(SerializationFeature.APPLY_JSON_INCLUDE_FOR_CONTAINERS)
.enable(MapperFeature.USE_REAL_INCLUDE_NON_DEFAULT)
.build();
String expectedResult = "{}";
// basic types
String myString = "";
List myList = new ArrayList<>();
myList.add("");
Map myMap = new HashMap<>();
myMap.put("1", "");
// object type
Bean innerBean = new Bean();
innerBean.myString = myString;
innerBean.myList = myList;
innerBean.myMap = myMap;
// object under test
Bean bean = new Bean();
bean.myString = myString;
bean.myList = myList;
bean.myMap = myMap;
bean.myBean = innerBean;
bean.myListOfBean = List.of(innerBean);
bean.myMapOfBean = Map.of("1", innerBean);
bean.myListOfMapOfString = List.of(Map.of("1", myString));
String result = objectMapper.writeValueAsString(bean);
assertEquals(expectedResult, result);
}
```
and I got the output where everything was removed except the "empty"/"default" objects...
```
Expected :{}
Actual :{"myBean":{},"myListOfBean":[{}],"myMapOfBean":{"1":{}}}
```
That is when I thought that since I was including POJOs now, I needed to use `NON_DEFAULT`. So I changed the object to be...
```
@JsonInclude(value=JsonInclude.Include.NON_DEFAULT, content=JsonInclude.Include.NON_DEFAULT)
public class Bean {
public String myString;
public Bean myBean;
public List myList;
public List myListOfBean;
public Map myMap;
public Map myMapOfBean;
public List> myListOfMapOfString;
}
```
and got an even worse result...
```
Expected :{}
Actual :{"myBean":{"myList":[],"myMap":{},"myString":""},"myList":[],"myListOfBean":[{"myList":[],"myMap":{},"myString":""}],"myListOfMapOfString":[{}],"myMap":{},"myMapOfBean":{"1":{"myList":[],"myMap":{},"myString":""}},"myString":""}
```
As you can see, I did set `MapperFeature.USE_REAL_INCLUDE_NON_DEFAULT` though I'm not sure that's actually necessary (and it obviously didn't help in this case).
Taking a specific field example, `public Bean myBean;`, I would've expected `NON_DEFAULT` to first clear out each field within that inner Bean object and then what's left for myBean would be `{}` which matches the default no-arg constructor and would then be removed from `NON_DEFAULT`. But it seems that not only does that not happen, but none of the scalars/collections/maps that were removed when using `NON_EMPTY` are removed either.
Am I just misunderstanding `NON_DEFAULT`? Again, not sure if I'm just not doing it correctly or if there's an actual bug where it's not removing everything it should?
I'm happy to try more things or provide more information, and I apologize that these issues keep extending.
### Version Information
3.2.1
### Reproduction
Examples provided above.
### Expected behavior
If I have a POJO where every field in it, of any type, all the way down is empty, that it would get removed from serialization.
### Additional context
_No response_
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the supplied test6 reproduction, focusing on JsonInclude.Include.NON_EMPTY/NON_DEFAULT, USE_REAL_INCLUDE_NON_DEFAULT, and ObjectMapper.writeValueAsString. Compare the expected and actual JSON for nested Bean, collection, and map fields; done means the behavior is clarified or corrected and the reproduction verifies the intended output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100