From a066415d66a6b1a4688ff0ed25695aa3a86ac130 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 8 Feb 2019 17:56:54 -0800 Subject: [PATCH] Fix #2236 --- release-notes/VERSION-2.x | 2 ++ .../databind/ser/std/NumberSerializers.java | 22 +++++++++++++++--- .../jackson/databind/BaseMapTest.java | 3 ++- .../deftyping/TestDefaultForScalars.java | 23 +++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index cc335e4921..da80d547cb 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -33,6 +33,8 @@ Project: jackson-databind (reported by RightHandedMonkey@github) #2230: `WRITE_BIGDECIMAL_AS_PLAIN` is ignored if `@JsonFormat` is used (reported by Pavel C) +#2236: Type id not provided on `Double.NaN`, `Infinity` with `@JsonTypeInfo` + (reported by C-B-B@github) #2241: Add `JsonPropertyNamingStrategy.LOWER_DOT_CASE` for dot-delimited names (contributed by zenglian@github.com) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java index 510a545b4b..9c4061cd7c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java @@ -7,7 +7,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.core.*; - +import com.fasterxml.jackson.core.type.WritableTypeId; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; @@ -220,11 +220,27 @@ public void serialize(Object value, JsonGenerator gen, // IMPORTANT: copied from `NonTypedScalarSerializerBase` @Override - public void serializeWithType(Object value, JsonGenerator gen, + public void serializeWithType(Object value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer) throws IOException { // no type info, just regular serialization - serialize(value, gen, provider); + // 08-Feb-2018, tatu: Except that as per [databind#2236], NaN values need + // special handling + Double d = (Double) value; + if (notFinite(d)) { + WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, + // whether to indicate it's number or string is arbitrary; important it is scalar + typeSer.typeId(value, JsonToken.VALUE_NUMBER_FLOAT)); + g.writeNumber(d); + typeSer.writeTypeSuffix(g, typeIdDef); + } else { + g.writeNumber(d); + } + } + + public static boolean notFinite(double value) { + // `jackson-core` has helper method in 3 but not yet + return Double.isNaN(value) || Double.isInfinite(value); } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java b/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java index 92b7236ee6..5cd5ab7b02 100644 --- a/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/BaseMapTest.java @@ -77,7 +77,8 @@ public StringWrapper(String value) { protected static class ObjectWrapper { final Object object; - protected ObjectWrapper(final Object object) { + + public ObjectWrapper(final Object object) { this.object = object; } public Object getObject() { return object; } diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForScalars.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForScalars.java index cc8b7afc15..135e741d9c 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForScalars.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForScalars.java @@ -23,6 +23,18 @@ static class Data { public long key; } + // Basic `ObjectWrapper` from base uses delegating ctor, won't work well; should + // figure out why, but until then we'll use separate impl + protected static class ObjectWrapperForPoly { + Object object; + + protected ObjectWrapperForPoly() { } + public ObjectWrapperForPoly(final Object o) { + object = o; + } + public Object getObject() { return object; } + } + /* /********************************************************************** /* Test methods @@ -128,4 +140,15 @@ public void testDefaultTypingWithLong() throws Exception assertNotNull(result); assertEquals(2, result.size()); } + + // [databind#2236]: do need type info for NaN + public void testDefaultTypingWithNaN() throws Exception + { + final ObjectWrapperForPoly INPUT = new ObjectWrapperForPoly(Double.POSITIVE_INFINITY); + final String json = DEFAULT_TYPING_MAPPER.writeValueAsString(INPUT); + final ObjectWrapperForPoly result = DEFAULT_TYPING_MAPPER.readValue(json, ObjectWrapperForPoly.class); + assertEquals(Double.class, result.getObject().getClass()); + assertEquals(INPUT.getObject().toString(), result.getObject().toString()); + assertTrue(((Double) result.getObject()).isInfinite()); + } }