How do I deserialize to Boolean.class from Json object in case insensitive manner using Jackson? How do I deserialize to Boolean.class from Json object in case insensitive manner using Jackson? json json

How do I deserialize to Boolean.class from Json object in case insensitive manner using Jackson?


You can add your custom com.fasterxml.jackson.databind.deser.DeserializationProblemHandler and implement handleWeirdStringValue method in which you can check text and return Boolean.TRUE or Boolean.FALSE for other cases you want to handle:

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 +                '}';    }}

Above code prints:

BooleanHolder{value=true}BooleanHolder{value=true}BooleanHolder{value=true}

Enable MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES

Default Boolean deserialiser in version 2.10.0 does not check MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES feature and is a final class which does not allow to override it easily. To make it aware about a feature we need to create a copy-paste version with some changes. To make it as close as possible to original I created com.fasterxml.jackson.databind.deser.std package and moved there below class:

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");    }}

Test case:

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 +                '}';    }}

Above code prints:

BooleanHolder{value=true}BooleanHolder{value=true}BooleanHolder{value=true}