java - 如何从 JSON 反序列化为 LocalDate,同时还使用 JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS?

标签 java json spring spring-mvc jackson

我已启用 jackson-datatype-joda,但它无法与 JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS 一起使用。

我已经按如下方式设置了 ObjectMapper:

ObjectMapper jacksonObjectMapper = new ObjectMapper();
jacksonObjectMapper.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
jacksonObjectMapper.registerModule(new JodaModule());

反序列化时(使用 com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer),我最终遇到错误:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Current token (VALUE_STRING) not numeric, can not use numeric value accessors
at [...]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Current token (VALUE_STRING) not numeric, can not use numeric value accessors

我调试了 LocalDateDeserializer 并发现它期望 VALUE_NUMBER_INT - 而 JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS 使日期具有字符串。

当我关闭该功能时,一切正常。

此功能(或类似功能)是否有可能与 Joda Time 一起使用?

最佳答案

Joda 模块使用 com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer用于反序列化 org.joda.time.LocalDate 对象。这个类看起来像这样:

@Override
public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
    throws IOException, JsonProcessingException
{
    // [yyyy,mm,dd]
    if (jp.isExpectedStartArrayToken()) {
        jp.nextToken(); // VALUE_NUMBER_INT 
        int year = jp.getIntValue(); 
        jp.nextToken(); // VALUE_NUMBER_INT
        int month = jp.getIntValue();
        jp.nextToken(); // VALUE_NUMBER_INT
        int day = jp.getIntValue();
        if (jp.nextToken() != JsonToken.END_ARRAY) {
            throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDate ints");
        }
        return new LocalDate(year, month, day);
    }
    switch (jp.getCurrentToken()) {
    case VALUE_NUMBER_INT:
        return new LocalDate(jp.getLongValue());            
    case VALUE_STRING:
        String str = jp.getText().trim();
        if (str.length() == 0) { // [JACKSON-360]
            return null;
        }
        return parser.parseLocalDate(str);
    default:
    }
    throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, String or Number");
}

如您所见,如果 LocalDate 是数组,则此反序列化器需要此数组中的整数。您可以编写自定义反序列化器并扩展此实现。请参见以下示例:

class LocalDateWithStringsDeserializer extends LocalDateDeserializer {

    private static final long serialVersionUID = 1L;

    @Override
    public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
            JsonProcessingException {
        // [yyyy,mm,dd] or ["yyyy","mm","dd"]
        if (jp.isExpectedStartArrayToken()) {
            return parseArray(jp, ctxt);
        }

        return super.deserialize(jp, ctxt);
    }

    private LocalDate parseArray(JsonParser jp, DeserializationContext ctxt)
            throws JsonParseException, IOException {
        int year = getNextValue(jp);
        int month = getNextValue(jp);
        int day = getNextValue(jp);
        if (jp.nextToken() != JsonToken.END_ARRAY) {
            throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDate ints");
        }
        return new LocalDate(year, month, day);
    }

    private int getNextValue(JsonParser jp) throws IOException, JsonParseException {
        jp.nextToken();

        return new Integer(jp.getText());
    }
}

现在您可以链接上面的反序列化器和您的属性:

@JsonDeserialize(using = LocalDateWithStringsDeserializer.class)
private LocalDate date;

关于java - 如何从 JSON 反序列化为 LocalDate,同时还使用 JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24432828/

相关文章:

json - 这些 JSON Perl 模块之间有什么区别?

django - 使用 json 使用 djangorestframework 将图像上传到 imagefield 并使用 CURL 进行测试

java - 如何在 mapstruct 中使用来自不同类的另一个映射

java - 从函数构建端点值 - 注释属性 X 的值必须是常量表达式

java - Gradle 'apply from:'抛出异常

java - 将 SoapHeader 添加到 org.springframework.ws.WebServiceMessage

java - 静态对象(例如单例)会泄漏非静态上下文吗?为什么?

java - super 和 extends 组合用于 Java 中的泛型

json - 从 ASMX Web 服务返回 JSON,没有 XML 包装器?

java - 如何在 Spring Rest Controller 中获取发件人的 uri?