Skip to content

Commit

Permalink
Implement part of #865
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Oct 17, 2016
1 parent ed41686 commit 7ad6bae
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1552,14 +1552,8 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
}
if (rawType == CLASS_MAP_ENTRY) {
// 28-Apr-2015, tatu: TypeFactory does it all for us already so
JavaType kt = type.containedType(0);
if (kt == null) {
kt = TypeFactory.unknownType();
}
JavaType vt = type.containedType(1);
if (vt == null) {
vt = TypeFactory.unknownType();
}
JavaType kt = type.containedTypeOrUnknown(0);
JavaType vt = type.containedTypeOrUnknown(1);
TypeDeserializer vts = (TypeDeserializer) vt.getTypeHandler();
if (vts == null) {
vts = findTypeDeserializer(ctxt.getConfig(), vt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,12 @@ protected JsonSerializer<?> buildMapEntrySerializer(SerializerProvider prov,
JavaType keyType, JavaType valueType)
throws JsonMappingException
{
// [databind#865]: Allow serialization "as POJO" -- note: to undo, declare
// serialization as `Shape.NATURAL` instead; that's JSON Object too.
JsonFormat.Value format = beanDesc.findExpectedFormat(null);
if (format != null && format.getShape() == JsonFormat.Shape.OBJECT) {
return null;
}
MapEntrySerializer ser = new MapEntrySerializer(valueType, keyType, valueType,
staticTyping, createTypeSerializer(prov.getConfig(), valueType), null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.ser.impl.MapEntrySerializer;
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
import com.fasterxml.jackson.databind.ser.impl.PropertyBasedObjectIdGenerator;
import com.fasterxml.jackson.databind.ser.impl.WritableObjectId;
Expand Down Expand Up @@ -46,6 +47,11 @@ public abstract class BeanSerializerBase
/**********************************************************
*/

/**
* @since 2.9
*/
final JavaType _beanType;

/**
* Writers used for outputting actual property values
*/
Expand Down Expand Up @@ -103,6 +109,7 @@ protected BeanSerializerBase(JavaType type, BeanSerializerBuilder builder,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties)
{
super(type);
_beanType = type;
_props = properties;
_filteredProps = filteredProperties;
if (builder == null) { // mostly for testing
Expand All @@ -125,6 +132,7 @@ public BeanSerializerBase(BeanSerializerBase src,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties)
{
super(src._handledType);
_beanType = src._beanType;
_props = properties;
_filteredProps = filteredProperties;

Expand All @@ -148,6 +156,7 @@ protected BeanSerializerBase(BeanSerializerBase src,
ObjectIdWriter objectIdWriter, Object filterId)
{
super(src._handledType);
_beanType = src._beanType;
_props = src._props;
_filteredProps = src._filteredProps;

Expand All @@ -168,6 +177,7 @@ protected BeanSerializerBase(BeanSerializerBase src, Set<String> toIgnore)
{
super(src._handledType);

_beanType = src._beanType;
final BeanPropertyWriter[] propsIn = src._props;
final BeanPropertyWriter[] fpropsIn = src._filteredProps;
final int len = propsIn.length;
Expand Down Expand Up @@ -415,11 +425,25 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
case NUMBER_INT:
// 12-Oct-2014, tatu: May need to introspect full annotations... but
// for now, just do class ones
BeanDescription desc = config.introspectClassAnnotations(_handledType);
JsonSerializer<?> ser = EnumSerializer.construct(_handledType,
BeanDescription desc = config.introspectClassAnnotations(_beanType);
JsonSerializer<?> ser = EnumSerializer.construct(_beanType.getRawClass(),
provider.getConfig(), desc, format);
return provider.handlePrimaryContextualization(ser, property);
}
// 16-Oct-2016, tatu: Ditto for `Map.Entry` subtypes
} else if (Map.Entry.class.isAssignableFrom(_handledType)) {
if (shape == JsonFormat.Shape.NATURAL) {
JavaType mapEntryType = _beanType.findSuperType(Map.Entry.class);

JavaType kt = mapEntryType.containedTypeOrUnknown(0);
JavaType vt = mapEntryType.containedTypeOrUnknown(1);

// 16-Oct-2016, tatu: could have problems with type handling, as we do not
// see if "static" typing is needed, nor look for `TypeSerializer` yet...
JsonSerializer<?> ser = new MapEntrySerializer(_beanType, kt, vt,
false, null, property);
return provider.handlePrimaryContextualization(ser, property);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.JDKScalarsTest.PrimitivesBean;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class NullHandlingTest extends BaseMapTest
Expand Down Expand Up @@ -98,82 +97,6 @@ public void testCustomRootNulls() throws Exception
assertEquals("funny", str);
}

public void testNullForPrimitives() throws IOException
{
// by default, ok to rely on defaults
PrimitivesBean bean = MAPPER.readValue(
"{\"intValue\":null, \"booleanValue\":null, \"doubleValue\":null}",
PrimitivesBean.class);
assertNotNull(bean);
assertEquals(0, bean.intValue);
assertEquals(false, bean.booleanValue);
assertEquals(0.0, bean.doubleValue);

bean = MAPPER.readValue("{\"byteValue\":null, \"longValue\":null, \"floatValue\":null}",
PrimitivesBean.class);
assertNotNull(bean);
assertEquals((byte) 0, bean.byteValue);
assertEquals(0L, bean.longValue);
assertEquals(0.0f, bean.floatValue);

// but not when enabled
final ObjectReader reader = MAPPER
.readerFor(PrimitivesBean.class)
.with(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
// boolean
try {
reader.readValue("{\"booleanValue\":null}");
fail("Expected failure for boolean + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type boolean");
}
// byte/char/short/int/long
try {
reader.readValue("{\"byteValue\":null}");
fail("Expected failure for byte + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type byte");
}
try {
reader.readValue("{\"charValue\":null}");
fail("Expected failure for char + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type char");
}
try {
reader.readValue("{\"shortValue\":null}");
fail("Expected failure for short + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type short");
}
try {
reader.readValue("{\"intValue\":null}");
fail("Expected failure for int + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type int");
}
try {
reader.readValue("{\"longValue\":null}");
fail("Expected failure for long + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type long");
}

// float/double
try {
reader.readValue("{\"floatValue\":null}");
fail("Expected failure for float + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type float");
}
try {
reader.readValue("{\"doubleValue\":null}");
fail("Expected failure for double + null");
} catch (JsonMappingException e) {
verifyException(e, "Can not map JSON null into type double");
}
}

// [databind#407]
public void testListOfNulls() throws Exception
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ public static KeyType create(String v) {
}
}

// Issue #142
public static class EnumMapContainer {
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
public EnumMap<KeyEnum,ITestType> testTypes;
Expand Down Expand Up @@ -519,78 +518,6 @@ public void testMapWithDeserializer() throws Exception
assertEquals("xyz", result.get("x"));
}

/*
/**********************************************************
/* Test methods, annotated Map.Entry
/**********************************************************
*/

public void testMapEntrySimpleTypes() throws Exception
{
List<Map.Entry<String,Long>> stuff = MAPPER.readValue(aposToQuotes("[{'a':15},{'b':42}]"),
new TypeReference<List<Map.Entry<String,Long>>>() { });
assertNotNull(stuff);
assertEquals(2, stuff.size());
assertNotNull(stuff.get(1));
assertEquals("b", stuff.get(1).getKey());
assertEquals(Long.valueOf(42), stuff.get(1).getValue());
}

public void testMapEntryWithStringBean() throws Exception
{
List<Map.Entry<Integer,StringWrapper>> stuff = MAPPER.readValue(aposToQuotes("[{'28':'Foo'},{'13':'Bar'}]"),
new TypeReference<List<Map.Entry<Integer,StringWrapper>>>() { });
assertNotNull(stuff);
assertEquals(2, stuff.size());
assertNotNull(stuff.get(1));
assertEquals(Integer.valueOf(13), stuff.get(1).getKey());

StringWrapper sw = stuff.get(1).getValue();
assertEquals("Bar", sw.str);
}

public void testMapEntryFail() throws Exception
{
try {
/*List<Map.Entry<Integer,StringWrapper>> stuff =*/ MAPPER.readValue(aposToQuotes("[{'28':'Foo','13':'Bar'}]"),
new TypeReference<List<Map.Entry<Integer,StringWrapper>>>() { });
fail("Should not have passed");
} catch (Exception e) {
verifyException(e, "more than one entry in JSON");
}
}

/*
/**********************************************************
/* Test methods, other exotic Map types
/**********************************************************
*/

// [databind#810]
public void testReadProperties() throws Exception
{
Properties props = MAPPER.readValue(aposToQuotes("{'a':'foo', 'b':123, 'c':true}"),
Properties.class);
assertEquals(3, props.size());
assertEquals("foo", props.getProperty("a"));
assertEquals("123", props.getProperty("b"));
assertEquals("true", props.getProperty("c"));
}

// JDK singletonMap
public void testSingletonMapRoundtrip() throws Exception
{
final TypeReference<?> type = new TypeReference<Map<String,IntWrapper>>() { };

String json = MAPPER.writeValueAsString(Collections.singletonMap("value", new IntWrapper(5)));
Map<String,IntWrapper> result = MAPPER.readValue(json, type);
assertNotNull(result);
assertEquals(1, result.size());
IntWrapper w = result.get("value");
assertNotNull(w);
assertEquals(5, w.i);
}

/*
/**********************************************************
/* Error tests
Expand All @@ -601,7 +528,7 @@ public void testMapError() throws Exception
{
try {
Object result = MAPPER.readValue("[ 1, 2 ]",
new TypeReference<Map<String,String>>() { });
new TypeReference<Map<String,String>>() { });
fail("Expected an exception, but got result value: "+result);
} catch (JsonMappingException jex) {
verifyException(jex, "START_ARRAY");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.databind.deser;
package com.fasterxml.jackson.databind.deser.jdk;

import java.io.Serializable;
import java.math.BigDecimal;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.databind.deser;
package com.fasterxml.jackson.databind.deser.jdk;

import java.io.IOException;
import java.io.StringReader;
Expand Down
Loading

0 comments on commit 7ad6bae

Please sign in to comment.