Skip to content

Commit

Permalink
Backport #2236 fix, accidentally started from master
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Feb 9, 2019
1 parent 8a32f54 commit 2c8c3f6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 27 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -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 [email protected])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,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;
Expand Down Expand Up @@ -231,11 +231,26 @@ 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,29 @@ 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
/**********************************************************
*/


private final ObjectMapper DEFAULT_TYPING_MAPPER = newObjectMapper();
{
DEFAULT_TYPING_MAPPER.enableDefaultTyping();
}

/**
* Unit test to verify that limited number of core types do NOT include
* type information, even if declared as Object. This is only done for types
Expand All @@ -39,45 +56,36 @@ static class Data {
*/
public void testNumericScalars() throws Exception
{
ObjectMapper m = new ObjectMapper();
m.enableDefaultTyping();

// no typing for Integer, Double, yes for others
assertEquals("[123]", m.writeValueAsString(new Object[] { Integer.valueOf(123) }));
assertEquals("[[\"java.lang.Long\",37]]", m.writeValueAsString(new Object[] { Long.valueOf(37) }));
assertEquals("[0.25]", m.writeValueAsString(new Object[] { Double.valueOf(0.25) }));
assertEquals("[[\"java.lang.Float\",0.5]]", m.writeValueAsString(new Object[] { Float.valueOf(0.5f) }));
assertEquals("[123]", DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { Integer.valueOf(123) }));
assertEquals("[[\"java.lang.Long\",37]]", DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { Long.valueOf(37) }));
assertEquals("[0.25]", DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { Double.valueOf(0.25) }));
assertEquals("[[\"java.lang.Float\",0.5]]", DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { Float.valueOf(0.5f) }));
}

public void testDateScalars() throws Exception
{
ObjectMapper m = new ObjectMapper();
m.enableDefaultTyping();

long ts = 12345678L;
assertEquals("[[\"java.util.Date\","+ts+"]]",
m.writeValueAsString(new Object[] { new Date(ts) }));
DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { new Date(ts) }));

// Calendar is trickier... hmmh. Need to ensure round-tripping
Calendar c = Calendar.getInstance();
c.setTimeInMillis(ts);
String json = m.writeValueAsString(new Object[] { c });
String json = DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { c });
assertEquals("[[\""+c.getClass().getName()+"\","+ts+"]]", json);
// and let's make sure it also comes back same way:
Object[] result = m.readValue(json, Object[].class);
Object[] result = DEFAULT_TYPING_MAPPER.readValue(json, Object[].class);
assertEquals(1, result.length);
assertTrue(result[0] instanceof Calendar);
assertEquals(ts, ((Calendar) result[0]).getTimeInMillis());
}

public void testMiscScalars() throws Exception
{
ObjectMapper m = new ObjectMapper();
m.enableDefaultTyping();

// no typing for Strings, booleans
assertEquals("[\"abc\"]", m.writeValueAsString(new Object[] { "abc" }));
assertEquals("[true,null,false]", m.writeValueAsString(new Boolean[] { true, null, false }));
assertEquals("[\"abc\"]", DEFAULT_TYPING_MAPPER.writeValueAsString(new Object[] { "abc" }));
assertEquals("[true,null,false]", DEFAULT_TYPING_MAPPER.writeValueAsString(new Boolean[] { true, null, false }));
}

/**
Expand All @@ -101,11 +109,9 @@ public void testScalarArrays() throws Exception

public void test417() throws Exception
{
ObjectMapper m = new ObjectMapper();
m.enableDefaultTyping();
Jackson417Bean input = new Jackson417Bean();
String json = m.writeValueAsString(input);
Jackson417Bean result = m.readValue(json, Jackson417Bean.class);
String json = DEFAULT_TYPING_MAPPER.writeValueAsString(input);
Jackson417Bean result = DEFAULT_TYPING_MAPPER.readValue(json, Jackson417Bean.class);
assertEquals(input.foo, result.foo);
assertEquals(input.bar, result.bar);
}
Expand Down Expand Up @@ -136,4 +142,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());
}
}

0 comments on commit 2c8c3f6

Please sign in to comment.