Skip to content

Commit

Permalink
Implement #527
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Oct 20, 2014
1 parent 2705b17 commit 1397def
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 82 deletions.
1 change: 1 addition & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Project: jackson-databind
(reported by Lovro P, lpandzic@github)
#521: Keep bundle annotations, prevent problems with recursive annotation types
(reported by tea-dragon@github)
#527: Add support for `@JsonInclude(contents=Include.NON_NULL)` (and others) for Maps
#528: Add support for `JsonType.As.EXISTING_PROPERTY`
(reported by heapifyman@github; implemented by fleebytes@github)
#539: Problem with post-procesing of "empty bean" serializer; was not calling
Expand Down
240 changes: 160 additions & 80 deletions src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -442,21 +442,17 @@ public void serialize(Map<?,?> value, JsonGenerator jgen, SerializerProvider pro
if (!provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES)) {
suppressableValue = JsonInclude.Include.NON_NULL;
}

}
if (_filterId != null) {
serializeFilteredFields(value, jgen, provider,
findPropertyFilter(provider, _filterId, value), suppressableValue);
jgen.writeEndObject();
return;
} else if (suppressableValue == JsonInclude.Include.ALWAYS) {
suppressableValue = null;
}
if (_sortKeys || provider.isEnabled(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)) {
value = _orderEntries(value);
}
if (suppressableValue != null) {
// !!! TEST
serializeFields(value, jgen, provider);
// serializeOptionalFields(value, jgen, provider);
if (_filterId != null) {
serializeFilteredFields(value, jgen, provider,
findPropertyFilter(provider, _filterId, value), suppressableValue);
} else if (suppressableValue != null) {
serializeOptionalFields(value, jgen, provider, suppressableValue);
} else if (_valueSerializer != null) {
serializeFieldsUsing(value, jgen, provider, _valueSerializer);
} else {
Expand All @@ -478,14 +474,17 @@ public void serializeWithType(Map<?,?> value, JsonGenerator jgen, SerializerProv
if (!provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES)) {
suppressableValue = JsonInclude.Include.NON_NULL;
}

} else if (suppressableValue == JsonInclude.Include.ALWAYS) {
suppressableValue = null;
}
if (_sortKeys || provider.isEnabled(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)) {
value = _orderEntries(value);
}
if (suppressableValue != null) {
// !!! TEST
serializeFields(value, jgen, provider);
if (_filterId != null) {
serializeFilteredFields(value, jgen, provider,
findPropertyFilter(provider, _filterId, value), suppressableValue);
} else if (suppressableValue != null) {
serializeOptionalFields(value, jgen, provider, suppressableValue);
} else if (_valueSerializer != null) {
serializeFieldsUsing(value, jgen, provider, _valueSerializer);
} else {
Expand All @@ -502,20 +501,19 @@ public void serializeWithType(Map<?,?> value, JsonGenerator jgen, SerializerProv
*/

/**
* Method called to serialize fields, when the value type is not statically known.
* Method called to serialize fields, when the value type is not statically known;
* but we know that no value suppression is needed (which simplifies processing a bit)
*/
public void serializeFields(Map<?,?> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException
{
// If value type needs polymorphic type handling, some more work needed:
if (_valueTypeSerializer != null) {
serializeTypedFields(value, jgen, provider);
serializeTypedFields(value, jgen, provider, null);
return;
}
final JsonSerializer<Object> keySerializer = _keySerializer;

final HashSet<String> ignored = _ignoredEntries;
final boolean skipNulls = !provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES);

PropertySerializerMap serializers = _dynamicValueSerializers;

Expand All @@ -526,8 +524,6 @@ public void serializeFields(Map<?,?> value, JsonGenerator jgen, SerializerProvid
if (keyElem == null) {
provider.findNullKeySerializer(_keyType, _property).serialize(null, jgen, provider);
} else {
// [JACKSON-314] skip entries with null values?
if (skipNulls && valueElem == null) continue;
// One twist: is entry ignorable? If so, skip
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer.serialize(keyElem, jgen, provider);
Expand All @@ -551,14 +547,77 @@ public void serializeFields(Map<?,?> value, JsonGenerator jgen, SerializerProvid
try {
serializer.serialize(valueElem, jgen, provider);
} catch (Exception e) {
// [JACKSON-55] Need to add reference information
// Add reference information
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
}

public void serializeOptionalFields(Map<?,?> value, JsonGenerator jgen, SerializerProvider provider,
Object suppressableValue)
throws IOException
{
// If value type needs polymorphic type handling, some more work needed:
if (_valueTypeSerializer != null) {
serializeTypedFields(value, jgen, provider, suppressableValue);
return;
}
final HashSet<String> ignored = _ignoredEntries;
PropertySerializerMap serializers = _dynamicValueSerializers;

for (Map.Entry<?,?> entry : value.entrySet()) {
// First find key serializer
final Object keyElem = entry.getKey();
JsonSerializer<Object> keySerializer;
if (keyElem == null) {
keySerializer = provider.findNullKeySerializer(_keyType, _property);
} else {
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer = _keySerializer;
}

// Then value serializer
final Object valueElem = entry.getValue();
JsonSerializer<Object> valueSer;
if (valueElem == null) {
if (suppressableValue != null) { // all suppressions include null-suppression
continue;
}
valueSer = provider.getDefaultNullValueSerializer();
} else {
valueSer = _valueSerializer;
if (valueSer == null) {
Class<?> cc = valueElem.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
valueSer = _findAndAddDynamic(serializers, cc, provider);
}
serializers = _dynamicValueSerializers;
}
}
// also may need to skip non-empty values:
if ((suppressableValue == JsonInclude.Include.NON_EMPTY)
&& valueSer.isEmpty(valueElem)) {
continue;
}
}
// and then serialize, if all went well
try {
keySerializer.serialize(keyElem, jgen, provider);
valueSer.serialize(valueElem, jgen, provider);
} catch (Exception e) {
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}

/**
* Method called to serialize fields, when the value type is statically known,
* so that value serializer is passed and does not need to be fetched from
Expand All @@ -571,19 +630,17 @@ protected void serializeFieldsUsing(Map<?,?> value, JsonGenerator jgen, Serializ
final JsonSerializer<Object> keySerializer = _keySerializer;
final HashSet<String> ignored = _ignoredEntries;
final TypeSerializer typeSer = _valueTypeSerializer;
final boolean skipNulls = !provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES);

for (Map.Entry<?,?> entry : value.entrySet()) {
Object valueElem = entry.getValue();
Object keyElem = entry.getKey();
if (ignored != null && ignored.contains(keyElem)) continue;

if (keyElem == null) {
provider.findNullKeySerializer(_keyType, _property).serialize(null, jgen, provider);
} else {
// [JACKSON-314] also may need to skip entries with null values
if (skipNulls && valueElem == null) continue;
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer.serialize(keyElem, jgen, provider);
}
final Object valueElem = entry.getValue();
if (valueElem == null) {
provider.defaultSerializeNull(jgen);
} else {
Expand All @@ -594,7 +651,6 @@ protected void serializeFieldsUsing(Map<?,?> value, JsonGenerator jgen, Serializ
ser.serializeWithType(valueElem, jgen, provider, typeSer);
}
} catch (Exception e) {
// [JACKSON-55] Need to add reference information
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
Expand All @@ -605,58 +661,66 @@ protected void serializeFieldsUsing(Map<?,?> value, JsonGenerator jgen, Serializ
/**
* Helper method used when we have a JSON Filter to use for potentially
* filtering out Map entries.
*<p>
* NOTE: initially only called externally, by <code>AnyGetterWriter</code>
*
* @since 2.3
* @since 2.5
*/
public void serializeFilteredFields(Map<?,?> value, JsonGenerator jgen, SerializerProvider provider,
PropertyFilter filter,
Object suppressableValue) // since 2.5
throws IOException
{
final HashSet<String> ignored = _ignoredEntries;
final boolean skipNulls = !provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES);

PropertySerializerMap serializers = _dynamicValueSerializers;
final MapProperty prop = new MapProperty(_valueTypeSerializer, _property);

for (Map.Entry<?,?> entry : value.entrySet()) {
// First, serialize key
// First, serialize key; unless ignorable by key
final Object keyElem = entry.getKey();
final Object valueElem = entry.getValue();
JsonSerializer<Object> keySer;
if (ignored != null && ignored.contains(keyElem)) continue;

JsonSerializer<Object> keySerializer;
if (keyElem == null) {
keySer = provider.findNullKeySerializer(_keyType, _property);
keySerializer = provider.findNullKeySerializer(_keyType, _property);
} else {
// [JACKSON-314] skip entries with null values?
if (skipNulls && valueElem == null) continue;
// One twist: is entry ignorable? If so, skip
if (ignored != null && ignored.contains(keyElem)) continue;
keySer = _keySerializer;
keySerializer = _keySerializer;
}
// or by value; nulls often suppressed
final Object valueElem = entry.getValue();

JsonSerializer<Object> valueSer;
// And then value
if (valueElem == null) {
if (suppressableValue != null) { // all suppressions include null-suppression
continue;
}
valueSer = provider.getDefaultNullValueSerializer();
} else {
Class<?> cc = valueElem.getClass();
valueSer = serializers.serializerFor(cc);
valueSer = _valueSerializer;
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
valueSer = _findAndAddDynamic(serializers, cc, provider);
Class<?> cc = valueElem.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
valueSer = _findAndAddDynamic(serializers, cc, provider);
}
serializers = _dynamicValueSerializers;
}
serializers = _dynamicValueSerializers;
}
// also may need to skip non-empty values:
if ((suppressableValue == JsonInclude.Include.NON_EMPTY)
&& valueSer.isEmpty(valueElem)) {
continue;
}
}
prop.reset(keyElem, keySer, valueSer);
// and with that, ask filter to handle it
prop.reset(keyElem, keySerializer, valueSer);
try {
filter.serializeAsField(valueElem, jgen, provider, prop);
} catch (Exception e) {
// [JACKSON-55] Need to add reference information
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
Expand All @@ -665,62 +729,78 @@ public void serializeFilteredFields(Map<?,?> value, JsonGenerator jgen, Serializ

@Deprecated // since 2.5
public void serializeFilteredFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
PropertyFilter filter) throws IOException
{
serializeFilteredFields(value, gen, provider, filter, null);
PropertyFilter filter) throws IOException {
serializeFilteredFields(value, gen, provider, filter,
provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES) ? null : JsonInclude.Include.NON_NULL);
}

protected void serializeTypedFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider)
/**
* @since 2.5
*/
protected void serializeTypedFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
Object suppressableValue) // since 2.5
throws IOException
{
final JsonSerializer<Object> keySerializer = _keySerializer;
JsonSerializer<Object> prevValueSerializer = null;
Class<?> prevValueClass = null;
final HashSet<String> ignored = _ignoredEntries;
final boolean skipNulls = !provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES);
PropertySerializerMap serializers = _dynamicValueSerializers;

for (Map.Entry<?,?> entry : value.entrySet()) {
Object valueElem = entry.getValue();
// First, serialize key
Object keyElem = entry.getKey();
JsonSerializer<Object> keySerializer;
if (keyElem == null) {
provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
keySerializer = provider.findNullKeySerializer(_keyType, _property);
} else {
// [JACKSON-314] also may need to skip entries with null values
if (skipNulls && valueElem == null) continue;
// One twist: is entry ignorable? If so, skip
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer.serialize(keyElem, gen, provider);
keySerializer = _keySerializer;
}
final Object valueElem = entry.getValue();

// And then value
JsonSerializer<Object> valueSer;
if (valueElem == null) {
if (suppressableValue != null) { // all suppression include null suppression
continue;
}
valueSer = provider.getDefaultNullValueSerializer();
keySerializer.serialize(keyElem, gen, provider);
provider.defaultSerializeNull(gen);
} else {
valueSer = _valueSerializer;
Class<?> cc = valueElem.getClass();
JsonSerializer<Object> currSerializer;
if (cc == prevValueClass) {
currSerializer = prevValueSerializer;
} else {
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
currSerializer = provider.findValueSerializer(provider.constructSpecializedType(_valueType, cc), _property);
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
currSerializer = provider.findValueSerializer(cc, _property);
valueSer = _findAndAddDynamic(serializers, cc, provider);
}
prevValueSerializer = currSerializer;
prevValueClass = cc;
serializers = _dynamicValueSerializers;
}
try {
currSerializer.serializeWithType(valueElem, gen, provider, _valueTypeSerializer);
} catch (Exception e) {
// [JACKSON-55] Need to add reference information
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
// also may need to skip non-empty values:
if ((suppressableValue == JsonInclude.Include.NON_EMPTY)
&& valueSer.isEmpty(valueElem)) {
continue;
}
}
keySerializer.serialize(keyElem, gen, provider);
try {
valueSer.serializeWithType(valueElem, gen, provider, _valueTypeSerializer);
} catch (Exception e) {
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}

@Deprecated // since 2.5
protected void serializeTypedFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
serializeTypedFields(value, gen, provider,
provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES) ? null : JsonInclude.Include.NON_NULL);
}

/*
/**********************************************************
/* Schema related functionality
Expand Down
Loading

0 comments on commit 1397def

Please sign in to comment.