问题
I'm developing a PATCH API. If the fields are sent as JSON
null
value I need to save them as null
. However I can't distinguish if they're sent as null
or never sent.
{
"max_amount": null
}
Double maxAmount;
I have Double
, Integer
, Date
etc. fields. I can deserialize them to Double.NAN
, Integer.MIN_VALUE
when they're really sent as null
to understand if they're sent as null
. But Deserializers don't work when the field is null
. Of course it's an option to send "-1" or an impossible value to define null
but I didn't like this approach. I will have to agree with the clients for all types. What's the best approach in this case?
回答1:
In cases like this you should define POJO
class with properties set to predefined undefined like
data. For example, for Integer
property if negative numbers are not allowed from business point of view, it could be -1
. Then, when JSON
is deserialised to POJO
properties set to null
override default values and you will know it was sent. There should be 3 options:
- Regular value in
JSON
- properly deserialised to a value inPOJO
null
value inJSON
- deserialised tonull
inPOJO
- Not available pair
key-value
- default value inPOJO
is not overridden.
Below example uses Jackson
in version 2.9.9
:
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.LocalDateTime;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
String[] jsons = {
"{\"number\":1,\"date\":\"2019-01-01T22:23:11\",\"max_amount\":4.9}",
"{\"number\":null,\"date\":null,\"max_amount\":null}",
"{}",
"{\"number\":1}",
"{\"date\":\"2019-01-01T22:23:11\"}",
"{\"max_amount\":4.9}",
"{\"number\":1,\"date\":null,\"max_amount\":null}"
};
for (String json : jsons) {
System.out.println(json + " => " + mapper.readValue(json, Pojo.class));
}
}
}
class Pojo {
private static final LocalDateTime NULL_DATE = LocalDateTime.of(1900, 1, 1, 12, 13);
@JsonProperty("max_amount")
private Double maxAmount = Double.MIN_VALUE;
private Integer number = Integer.MIN_VALUE;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private LocalDateTime date = NULL_DATE;
public Double getMaxAmount() {
return maxAmount;
}
public void setMaxAmount(Double maxAmount) {
this.maxAmount = maxAmount;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public LocalDateTime getDate() {
return date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
@Override
public String toString() {
return "{" +
"number=" + number +
", date=" + date +
", maxAmount=" + maxAmount +
'}';
}
}
Above code prints:
{"number":1,"date":"2019-01-01T22:23:11","max_amount":4.9} => {number=1, date=2019-01-01T22:23:11, maxAmount=4.9}
{"number":null,"date":null,"max_amount":null} => {number=null, date=null, maxAmount=null}
{} => {number=-2147483648, date=1900-01-01T12:13, maxAmount=4.9E-324}
{"number":1} => {number=1, date=1900-01-01T12:13, maxAmount=4.9E-324}
{"date":"2019-01-01T22:23:11"} => {number=-2147483648, date=2019-01-01T22:23:11, maxAmount=4.9E-324}
{"max_amount":4.9} => {number=-2147483648, date=1900-01-01T12:13, maxAmount=4.9}
{"number":1,"date":null,"max_amount":null} => {number=1, date=null, maxAmount=null}
Of course, you should pick default values in the way it will minimise possibility of collision that client by accident send value treated as undefined
by your API
.
来源:https://stackoverflow.com/questions/57911836/how-to-deserialize-null-type-json-fields-with-jackson