From 8b4f1e9ce360c8a7cdf92398e4a0e29b9a7a8cb8 Mon Sep 17 00:00:00 2001 From: Damian Serwin Date: Sat, 16 Dec 2017 13:42:03 +0100 Subject: [PATCH] handling DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES --- .../deser/OptimizedSettableBeanProperty.java | 29 ++++++- ...ailOnPrimitiveFromNullDeserialization.java | 75 +++++++++++++++++++ 2 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 afterburner/src/test/java/com/fasterxml/jackson/module/afterburner/deser/TestFailOnPrimitiveFromNullDeserialization.java diff --git a/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/deser/OptimizedSettableBeanProperty.java b/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/deser/OptimizedSettableBeanProperty.java index 3f5cfec7..3b626849 100644 --- a/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/deser/OptimizedSettableBeanProperty.java +++ b/afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/deser/OptimizedSettableBeanProperty.java @@ -178,7 +178,13 @@ protected final boolean _deserializeBoolean(JsonParser p, DeserializationContext JsonToken t = p.getCurrentToken(); if (t == JsonToken.VALUE_TRUE) return true; if (t == JsonToken.VALUE_FALSE) return false; - if (t == JsonToken.VALUE_NULL) return false; + if (t == JsonToken.VALUE_NULL) { + if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) { + _failNullToPrimitiveCoercion(ctxt, "boolean"); + } else { + return false; + } + } if (t == JsonToken.VALUE_NUMBER_INT) { // 11-Jan-2012, tatus: May be outside of int... @@ -264,7 +270,11 @@ protected final int _deserializeInt(JsonParser p, DeserializationContext ctxt) return p.getValueAsInt(); } if (t == JsonToken.VALUE_NULL) { - return 0; + if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) { + _failNullToPrimitiveCoercion(ctxt, "int"); + } else { + return 0; + } } if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { p.nextToken(); @@ -300,7 +310,11 @@ protected final long _deserializeLong(JsonParser p, DeserializationContext ctxt) } catch (IllegalArgumentException iae) { } throw ctxt.weirdStringException(text, Long.TYPE, "not a valid long value"); case JsonTokenId.ID_NULL: - return 0L; + if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) { + _failNullToPrimitiveCoercion(ctxt, "long"); + } else { + return 0L; + } case JsonTokenId.ID_START_ARRAY: if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { p.nextToken(); @@ -368,7 +382,14 @@ protected final boolean _deserializeBooleanFromOther(JsonParser p, Deserializati } // // More helper methods from StdDeserializer - + + protected void _failNullToPrimitiveCoercion(DeserializationContext ctxt, String type) throws JsonMappingException + { + ctxt.reportInputMismatch(getType(), + "Cannot map `null` into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)", + type); + } + protected void _failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt, String type) throws IOException { diff --git a/afterburner/src/test/java/com/fasterxml/jackson/module/afterburner/deser/TestFailOnPrimitiveFromNullDeserialization.java b/afterburner/src/test/java/com/fasterxml/jackson/module/afterburner/deser/TestFailOnPrimitiveFromNullDeserialization.java new file mode 100644 index 00000000..07952225 --- /dev/null +++ b/afterburner/src/test/java/com/fasterxml/jackson/module/afterburner/deser/TestFailOnPrimitiveFromNullDeserialization.java @@ -0,0 +1,75 @@ +package com.fasterxml.jackson.module.afterburner.deser; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.module.afterburner.AfterburnerTestBase; + +public class TestFailOnPrimitiveFromNullDeserialization extends AfterburnerTestBase +{ + static class LongBean + { + public long value; + } + + static class IntBean + { + public int value; + } + + static class BooleanBean + { + public boolean value; + } + + static class DoubleBean + { + public double value; + } + + private final static String BEAN_WITH_NULL_VALUE = "{\"value\": null}"; + + private final ObjectMapper MAPPER = newObjectMapper(); + private final ObjectMapper FAIL_ON_NULL_MAPPER = newObjectMapper() + .enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); + + public void testPassPrimitiveFromNull() throws Exception + { + LongBean longBean = MAPPER.readValue(BEAN_WITH_NULL_VALUE, LongBean.class); + IntBean intBean = MAPPER.readValue(BEAN_WITH_NULL_VALUE, IntBean.class); + BooleanBean booleanBean = MAPPER.readValue(BEAN_WITH_NULL_VALUE, BooleanBean.class); + DoubleBean doubleBean = MAPPER.readValue(BEAN_WITH_NULL_VALUE, DoubleBean.class); + assertEquals(longBean.value, 0); + assertEquals(intBean.value, 0); + assertEquals(booleanBean.value, false); + assertEquals(doubleBean.value, 0.0); + } + + public void testFailPrimitiveFromNull() throws Exception + { + try { + FAIL_ON_NULL_MAPPER.readValue(BEAN_WITH_NULL_VALUE, IntBean.class); + fail(); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot map `null` into type int"); + } + try { + FAIL_ON_NULL_MAPPER.readValue(BEAN_WITH_NULL_VALUE, LongBean.class); + fail(); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot map `null` into type long"); + } + try { + FAIL_ON_NULL_MAPPER.readValue(BEAN_WITH_NULL_VALUE, BooleanBean.class); + fail(); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot map `null` into type boolean"); + } + try { + FAIL_ON_NULL_MAPPER.readValue(BEAN_WITH_NULL_VALUE, DoubleBean.class); + fail(); + } catch (MismatchedInputException e) { + verifyException(e, "Cannot map `null` into type double"); + } + } +}