如何将字符串值转换为0与杰克逊?



我正在从外部API获取地址。这是表示地址的类:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Address implements Serializable {
private static final long serialVersionUID = -7134571546367230214L;
private String street;
private int houseNumber;
private String district;
private String city;
private String state;
private String zipCode;
}

然而,当给定的地址没有houseNumber时,API将返回一个字符串,如houseNumber字段上的"NO NUMBER",导致Jackson抛出反序列化错误,因为它期望得到一个整数,而得到一个字符串。

我怎么能告诉杰克逊转换houseNumber0时,它发现一个字符串值?

您可以尝试在字段上使用自定义反序列化器:

@JsonDeserialize(using = HouseNoDeserializer.class)
private int houseNumber;

反序列化器可以像这样:

class HouseNoDeserializer extends JsonDeserializer<Integer> {
@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
//read the value as a string since you don't know whether it is a number or a string
String v = p.readValueAs(String.class);
try {
//try to parse the string to an integer, if not return 0 as required (it is a non-numeric string)
return Integer.parseInt(v);
} catch(NumberFormatException nfe) {
return 0;
}
}
}

然而,我将houseNumber更改为String,因为现在你不能支持诸如"1/c", "123a"等数字,这些数字至少在一些国家很常见。

你可以不使用自定义反序列化器,只需在setter中添加一些逻辑,或者在解析json后应用它,即替换"NO NUMBER">

最简单的解决方法是添加setter方法,该方法取String的值。

class Address {
private String street;
private int houseNumber;
private String district;
private String city;
private String state;
private String zipCode;
public void setHouseNumber(String value) {
this.houseNumber = 0;
}
}

其他选项,您可以提供自定义com.fasterxml.jackson.databind.deser.DeserializationProblemHandler,并通常为所有POJO类处理所有这些类型的业务值:

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.IOException;
public class HandleErrorsApp {
private final static JsonMapper JSON_MAPPER = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(new JavaTimeModule())
.addHandler(new ProjectDeserializationProblemHandler())
.build();
public static void main(String[] args) throws Exception {
var json = "{"houseNumber":"NO_ADDRESS"}";
var address = JSON_MAPPER.readValue(json, Address.class);
System.out.println(address);
}
}
class ProjectDeserializationProblemHandler extends DeserializationProblemHandler {
@Override
public Object handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg) throws IOException {
if (targetType == int.class && valueToConvert.equals("NO_ADDRESS")) {
return 0;
}
return super.handleWeirdStringValue(ctxt, targetType, valueToConvert, failureMsg);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class Address {
private int houseNumber;
}

或者您可以提供自定义的com.fasterxml.jackson.databind.util.StdConverter实现,它具有比JsonDeserializer:

更简单的接口
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.util.StdConverter;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.math.NumberUtils;
public class HandleErrorsApp {
private final static JsonMapper JSON_MAPPER = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(new JavaTimeModule())
.build();
public static void main(String[] args) throws Exception {
var json = "{"houseNumber":"NO_ADDRESS"}";
var address = JSON_MAPPER.readValue(json, Address.class);
System.out.println(address);
}
}
class StringIntConverter extends StdConverter<String, Integer> {
@Override
public Integer convert(String value) {
return NumberUtils.toInt(value, 0);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class Address {
@JsonDeserialize(converter = StringIntConverter.class)
private int houseNumber;
}

在这两种情况下程序打印:

Address(houseNumber=0)

最新更新