我已启用 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一起使用?
答案 0 :(得分:4)
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;