Suppose, I want Jackson to ignore nulls when serializing this particular object. I tried this (keep in mind, though, that the actual class being serialized is read-only)
@RestController
public class SomeObjectController {
@GetMapping("/some-object-with-no-nulls")
@JsonInclude(content = JsonInclude.Include.NON_NULL)
public Mono<SomeObject> getSomeObject() {
return Mono.just(new SomeObject(null, "string"));
}
@NoArgsContructor
@Getter
@Setter
public class SomeObject {
private String firstField;
private String secondField;
}
}
However, it doesn't work
{
firstField: null,
secondField: "string"
}
The expected result is:
{
secondField: "string"
}
I get what I want if I register a custom ObjectMapper
. But I may not necessarily want that behavior for all my endpoints (even if they serve SomeObject
too)
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return objectMapper;
}
I also would like to avoid writing a custom serializator. It may be possible, but I prefer declarative solutions (while realizing their drawbacks)
What should I do?
The cleaner solution is to to write custom serializer for SomeObject
and register it with the existing instance of ObjectMapper
.
Since you don't want to do that, if SomeObject
is extensible (non final), you can use inheritance and add @JsonInclude(JsonInclude.Include.NON_NULL)
on your class.
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SomeObjectInheritor extends SomeObject {
public static SomeObjectInheritor fromParent(SomeObject someObject) {
SomeObjectInheritor inheritor = new SomeObjectInheritor();
inheritor.setFirstField(someObject.getFirstField());
inheritor.setSecondField(someObject.getSecondField());
return inheritor;
}
}
You can replace SomeObject
instances with SomeObjectInheritor
, or you can use it only for the actual serialization.
public class Main {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//use SomeObjectInheritor instead of SomeObject
SomeObject someObject = new SomeObjectInheritor();
someObject.setSecondField("val");
System.out.println(mapper.writeValueAsString(someObject));
//use SomeObjectInheritor only for the actual serialization
SomeObject anotherObj = new SomeObject();
anotherObj.setSecondField("second value");
System.out.println(mapper.writeValueAsString(SomeObjectInheritor.fromParent(anotherObj)));
}
}
Prints:
{"secondField":"val"}
for someObject
and
{"secondField":"second value"}
for anotherObj
respectively. In both cases the null property is not serialized.
If SomeObject
is final
, I am afraid, that your only option is writing a serializer.