Reputation: 6516
I have an entity that contains collection as attribute:
public class Entity {
@JsonProperty(value="homes")
@JsonDeserialize(as=HashSet.class, contentAs=HomeImpl.class)
private Collection<Home> homes = new ArrayList<Home>();
}
If request contains null as request property:
{
"homes": null
}
then homes is set to null. What I want to do is to set homes to empty list. Do I need to write special deserializer for this or is there one for collections? What I tried is this deserializer but it looks ugly (it's not generic and uses implementation instead of interface).
public class NotNullCollectionDeserializer extends JsonDeserializer<Collection<HomeImpl>> {
@Override
public Collection<HomeImpl> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return jsonParser.readValueAs(new TypeReference<Collection<HomeImpl>>(){});
}
@Override
public Collection<HomeImpl> getNullValue() {
return Collections.emptyList();
}
}
So few questions:
Upvotes: 44
Views: 58553
Reputation: 376
At least in 2.16, this can be set by using configOverride
.
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MutableConfigOverride;
import org.junit.jupiter.api.Test;
import java.util.List;
public class Temp {
static class Dto {
public List<Object> list;
}
@Test
void test() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
MutableConfigOverride override = mapper.configOverride(List.class);
override.setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
Dto temp = mapper.readValue("{\"list\":null}", Dto.class);
System.out.println(temp.list.size()); // -> 0
}
}
Upvotes: 3
Reputation: 944
I think the cleanest solution in my case which is working as expected (get empty list instead of null after deserialization) in both cases:
is:
@Valid // javax.validation
@Schema(required = false) // swagger.v3
@JsonProperty(required = false, defaultValue = "") // jackson 2.13
private List<@NotEmpty @Size(max = 100) String> actions = new ArrayList<>();
public List<String> getActions() {
return actions;
}
@JsonSetter(nulls = Nulls.AS_EMPTY)
public void setActions(List<String> actions) {
this.actions = actions;
}
Notes:
= new ArrayList<>();
required = false
) listsUpvotes: 0
Reputation: 5281
As of Jackson 2.9, it looks like null-handling for specific properties can be configured with @JsonSetter
, for example:
@JsonSetter(nulls = Nulls.AS_EMPTY)
public void setStrings(List<String> strings) {
this.strings = strings;
}
Similar configuration can also be applied globally for collections:
ObjectMapper mapper = objectMapperBuilder()
.changeDefaultNullHandling(n -> n.withContentNulls(Nulls.AS_EMPTY))
.build();
Or by type:
ObjectMapper mapper = objectMapperBuilder()
.withConfigOverride(List.class,
o -> o.setNullHandling(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY)))
.build();
I haven't been able to try the feature out, so this is based on the feature discussion and examination of unit tests. YMMV.
Upvotes: 63
Reputation: 313
What worked for me was simply to remove the setter and make the attribute final. jackson 2 will then use the getter to modify the list.
public class Entity {
@JsonProperty(value="homes")
@JsonDeserialize(as=HashSet.class, contentAs=HomeImpl.class)
private final Collection<Home> homes = new ArrayList<Home>();
public List<Home> getHomes() {
return homes;
}
}
The responsible feature is USE_GETTERS_AS_SETTERS which is turned on by default: https://github.com/FasterXML/jackson-databind/wiki/Mapper-Features
Upvotes: 3
Reputation: 22224
I also couldn't find a Jackson property or annotation for this. So I'll have to answer no to the first question. But I would recommend a simple setter instead of the special deserializer :
public class Entity {
@JsonDeserialize(contentAs = HomeImpl.class)
private Collection<Home> homes = new ArrayList<>();
public void setHomes(List<Home> homes) {
if (homes != null)
this.homes = homes;
}
}
This is generic as it only uses the Home
interface instead of HomeImpl
. You don't need @JsonProperty
as Jackson will associate setHomes
and homes
.
Upvotes: 15