java 如何使用Jackson将字符串值转换为0?

rvpgvaaj  于 2023-01-11  发布在  Java
关注(0)|答案(2)|浏览(171)

我正在从外部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抛出反序列化错误,因为它期望的是整数,而得到的是字符串。
当Jackson找到一个字符串值时,如何告诉它将houseNumber转换为0

gzjq41n4

gzjq41n41#

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

@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”、“123 a”等数字,这些数字至少在某些国家很常见。
然后,您可以不使用自定义反序列化器,而只向setter添加一些逻辑或在解析json之后应用它,即根据需要用另一个值替换“NO NUMBER”。

4nkexdtk

4nkexdtk2#

您可以提供定制的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)

相关问题