我正在使用Jackson 2.10.x反序列化格式的Json
{ myKey: "true"}
。可能的变化形式为{ myKey: "True"}
,{ myKey: "TRUE"}
,对于false则类似。
我需要反序列化的POJO具有属性myKey :: Boolean.class。
我不拥有POJO源,因此无法在特定属性上设置Json属性。
当值是“ true”和“ True”时,Jackson可以反序列化,而当值是“ TRUE”时,则不能。 我尝试按如下方式使用MapperFeature ACCEPT_CASE_INSENSITIVE_VALUES,但这无济于事
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES)
异常消息是
Cannot deserialize value of type `java.lang.Boolean` from String "TRUE": only "true" or "false" recognized at [Source: UNKNOWN; line: -1, column: -1]
答案 0 :(得分:3)
您可以添加自定义com.fasterxml.jackson.databind.deser.DeserializationProblemHandler
并实现handleWeirdStringValue
方法,在该方法中,您可以检查文本并针对需要处理的其他情况返回Boolean.TRUE
或Boolean.FALSE
:>
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.json.JsonMapper;
import java.io.IOException;
public class JsonBooleanApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = JsonMapper.builder()
.addHandler(new DeserializationProblemHandler() {
@Override
public Object handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg) throws IOException {
if (targetType == Boolean.class) {
return Boolean.TRUE.toString().equalsIgnoreCase(valueToConvert);
}
return super.handleWeirdStringValue(ctxt, targetType, valueToConvert, failureMsg);
}
})
.build();
System.out.println(mapper.readValue("{\"value\": \"True\"}", BooleanHolder.class));
System.out.println(mapper.readValue("{\"value\": \"true\"}", BooleanHolder.class));
System.out.println(mapper.readValue("{\"value\": \"TRUE\"}", BooleanHolder.class));
}
}
class BooleanHolder {
private Boolean value;
public Boolean getValue() {
return value;
}
public void setValue(Boolean value) {
this.value = value;
}
@Override
public String toString() {
return "BooleanHolder{" +
"value=" + value +
'}';
}
}
上面的代码显示:
BooleanHolder{value=true}
BooleanHolder{value=true}
BooleanHolder{value=true}
版本Boolean
中的默认2.10.0
解串器不检查MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES
功能,它是最终类,不允许轻易覆盖它。为了使它了解某个功能,我们需要创建一个copy-paste
版本并进行一些更改。为了使其与原始版本尽可能接近,我创建了com.fasterxml.jackson.databind.deser.std
程序包,并将其移至类下:
package com.fasterxml.jackson.databind.deser.std;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import java.io.IOException;
public final class BooleanDeserializerIgnoreCase extends NumberDeserializers.PrimitiveOrWrapperDeserializer<Boolean> {
private static final long serialVersionUID = 1L;
public final static BooleanDeserializerIgnoreCase primitiveInstance = new BooleanDeserializerIgnoreCase(Boolean.TYPE, Boolean.FALSE);
public final static BooleanDeserializerIgnoreCase wrapperInstance = new BooleanDeserializerIgnoreCase(Boolean.class, null);
public BooleanDeserializerIgnoreCase(Class<Boolean> cls, Boolean nvl) {
super(cls, nvl, Boolean.FALSE);
}
@Override
public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
return _parseBoolean(p, ctxt);
}
// Since we can never have type info ("natural type"; String, Boolean, Integer, Double):
// (is it an error to even call this version?)
@Override
public Boolean deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws IOException {
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
return _parseBoolean(p, ctxt);
}
protected final Boolean _parseBoolean(JsonParser p, DeserializationContext ctxt)
throws IOException {
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return (Boolean) _coerceNullToken(ctxt, _primitive);
}
if (t == JsonToken.START_ARRAY) { // unwrapping?
return _deserializeFromArray(p, ctxt);
}
// should accept ints too, (0 == false, otherwise true)
if (t == JsonToken.VALUE_NUMBER_INT) {
return Boolean.valueOf(_parseBooleanFromInt(p, ctxt));
}
// And finally, let's allow Strings to be converted too
if (t == JsonToken.VALUE_STRING) {
return _deserializeFromString(p, ctxt);
}
// usually caller should have handled but:
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
if (t == JsonToken.VALUE_FALSE) {
return Boolean.FALSE;
}
// Otherwise, no can do:
return (Boolean) ctxt.handleUnexpectedToken(_valueClass, p);
}
protected final Boolean _deserializeFromString(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText().trim();
if (ctxt.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES)) {
if (Boolean.TRUE.toString().equalsIgnoreCase(text)) {
return Boolean.TRUE;
}
if (Boolean.FALSE.toString().equalsIgnoreCase(text)) {
return Boolean.FALSE;
}
} else {
if ("true".equals(text) || "True".equals(text)) {
_verifyStringForScalarCoercion(ctxt, text);
return Boolean.TRUE;
}
if ("false".equals(text) || "False".equals(text)) {
_verifyStringForScalarCoercion(ctxt, text);
return Boolean.FALSE;
}
if (text.length() == 0) {
return (Boolean) _coerceEmptyString(ctxt, _primitive);
}
if (_hasTextualNull(text)) {
return (Boolean) _coerceTextualNull(ctxt, _primitive);
}
}
return (Boolean) ctxt.handleWeirdStringValue(_valueClass, text,
"only \"true\" or \"false\" recognized");
}
}
测试用例:
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.BooleanDeserializerIgnoreCase;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class JsonBooleanApp {
public static void main(String[] args) throws Exception {
SimpleModule booleanIgnoreCaseModule = new SimpleModule();
booleanIgnoreCaseModule.addDeserializer(Boolean.class, BooleanDeserializerIgnoreCase.wrapperInstance);
booleanIgnoreCaseModule.addDeserializer(boolean.class, BooleanDeserializerIgnoreCase.primitiveInstance);
ObjectMapper mapper = JsonMapper.builder()
.addModule(booleanIgnoreCaseModule)
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES)
.build();
System.out.println(mapper.readValue("{\"value\": \"True\"}", BooleanHolder.class));
System.out.println(mapper.readValue("{\"value\": \"true\"}", BooleanHolder.class));
System.out.println(mapper.readValue("{\"value\": \"TRUE\"}", BooleanHolder.class));
}
}
class BooleanHolder {
private Boolean value;
public Boolean getValue() {
return value;
}
public void setValue(Boolean value) {
this.value = value;
}
@Override
public String toString() {
return "BooleanHolder{" +
"value=" + value +
'}';
}
}
上面的代码显示:
BooleanHolder{value=true}
BooleanHolder{value=true}
BooleanHolder{value=true}