Skip to content

Commit df7f407

Browse files
committed
Fixed #952
1 parent f807c8c commit df7f407

14 files changed

+270
-177
lines changed

release-notes/VERSION

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Project: jackson-databind
3434
(reported by adamjoeldavis@github)
3535
#948: Support leap seconds, any number of millisecond digits for ISO-8601 Dates.
3636
(contributed by Jesse W)
37+
#952: Revert non-empty handling of primitive numbers wrt `NON_EMPTY`; make
38+
`NON_DEFAULT` use extended criteria
3739
#957: Merge `datatype-jdk7` stuff in (java.nio.file.Path handling)
3840
#959: Schema generation: consider active view, discard non-included properties
3941
#963: Add PropertyNameStrategy `KEBAB_CASE`

src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
1010
import com.fasterxml.jackson.core.JsonGenerator;
11-
1211
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
1312
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
1413
import com.fasterxml.jackson.databind.introspect.Annotated;

src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,11 @@ protected Object findSuppressableContentValue(SerializationConfig config,
818818
return null;
819819
case NON_DEFAULT:
820820
// 19-Oct-2014, tatu: Not sure what this'd mean; so take it to mean "NON_EMPTY"...
821-
incl = JsonInclude.Include.NON_EMPTY;
821+
// 11-Nov-2015, tatu: With 2.6, we did indeed revert to "NON_EMPTY", but that did
822+
// not go well, so with 2.7, we'll do this instead...
823+
// But not 100% sure if we ought to call new `JsonSerializer.findDefaultValue()`;
824+
// to do that, would need to locate said serializer
825+
// incl = JsonInclude.Include.NON_EMPTY;
822826
break;
823827
default:
824828
// all other modes actually good as is, unless we'll find better ways

src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java

+63-10
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ public class PropertyBuilder
3232
/**
3333
* If a property has serialization inclusion value of
3434
* {@link com.fasterxml.jackson.annotation.JsonInclude.Include#NON_DEFAULT},
35-
* we need to know the default value of the bean, to know if property value
35+
* we may need to know the default value of the bean, to know if property value
3636
* equals default one.
37+
*<p>
38+
* NOTE: only used if enclosing class defines NON_DEFAULT, but NOT if it is the
39+
* global default OR per-property override.
3740
*/
3841
protected Object _defaultBean;
3942

@@ -110,14 +113,25 @@ protected BeanPropertyWriter buildWriter(SerializerProvider prov,
110113

111114
switch (inclusion) {
112115
case NON_DEFAULT:
113-
valueToSuppress = getDefaultValue(propDef.getName(), am);
116+
// 11-Nov-2015, tatu: This is tricky because semantics differ between cases,
117+
// so that if enclosing class has this, we may need to values of property,
118+
// whereas for global defaults OR per-property overrides, we have more
119+
// static definition. Sigh.
120+
// First: case of class specifying it; try to find POJO property defaults
121+
JavaType t = (serializationType == null) ? declaredType : serializationType;
122+
if (_defaultInclusion.getValueInclusion() == JsonInclude.Include.NON_DEFAULT) {
123+
valueToSuppress = getPropertyDefaultValue(propDef.getName(), am, t);
124+
} else {
125+
valueToSuppress = getDefaultValue(t);
126+
}
114127
if (valueToSuppress == null) {
115128
suppressNulls = true;
116129
} else {
117130
if (valueToSuppress.getClass().isArray()) {
118131
valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
119132
}
120133
}
134+
121135
break;
122136
case NON_ABSENT: // new with 2.6, to support Guava/JDK8 Optionals
123137
// always suppress nulls
@@ -246,17 +260,24 @@ protected Object getDefaultBean()
246260
return (def == NO_DEFAULT_MARKER) ? null : _defaultBean;
247261
}
248262

249-
protected Object getDefaultValue(String name, AnnotatedMember member)
263+
/**
264+
* Accessor used to find out "default value" for given property, to use for
265+
* comparing values to serialize, to determine whether to exclude value from serialization with
266+
* inclusion type of {@link com.fasterxml.jackson.annotation.JsonInclude.Include#NON_EMPTY}.
267+
* This method is called when we specifically want to know default value within context
268+
* of a POJO, when annotation is within containing class, and not for property or
269+
* defined as global baseline.
270+
*<p>
271+
* Note that returning of pseudo-type
272+
*
273+
* @since 2.7
274+
*/
275+
protected Object getPropertyDefaultValue(String name, AnnotatedMember member,
276+
JavaType type)
250277
{
251278
Object defaultBean = getDefaultBean();
252279
if (defaultBean == null) {
253-
// 06-Nov-2015, tatu: Returning null is fine for Object types; but need special
254-
// handling for primitives since they are never passed as nulls.
255-
Class<?> cls = member.getRawType();
256-
if (cls.isPrimitive()) {
257-
return ClassUtil.defaultValue(cls);
258-
}
259-
return null;
280+
return getDefaultValue(type);
260281
}
261282
try {
262283
return member.getValue(defaultBean);
@@ -265,6 +286,38 @@ protected Object getDefaultValue(String name, AnnotatedMember member)
265286
}
266287
}
267288

289+
/**
290+
* Accessor used to find out "default value" to use for comparing values to
291+
* serialize, to determine whether to exclude value from serialization with
292+
* inclusion type of {@link com.fasterxml.jackson.annotation.JsonInclude.Include#NON_DEFAULT}.
293+
*<p>
294+
* Default logic is such that for primitives and wrapper types for primitives, expected
295+
* defaults (0 for `int` and `java.lang.Integer`) are returned; for Strings, empty String,
296+
* and for structured (Maps, Collections, arrays) and reference types, criteria
297+
* {@link com.fasterxml.jackson.annotation.JsonInclude.Include#NON_DEFAULT}
298+
* is used.
299+
*
300+
* @since 2.7
301+
*/
302+
protected Object getDefaultValue(JavaType type)
303+
{
304+
// 06-Nov-2015, tatu: Returning null is fine for Object types; but need special
305+
// handling for primitives since they are never passed as nulls.
306+
Class<?> cls = type.getRawClass();
307+
308+
Class<?> prim = ClassUtil.primitiveType(cls);
309+
if (prim != null) {
310+
return ClassUtil.defaultValue(prim);
311+
}
312+
if (type.isContainerType() || type.isReferenceType()) {
313+
return JsonInclude.Include.NON_EMPTY;
314+
}
315+
if (cls == String.class) {
316+
return "";
317+
}
318+
return null;
319+
}
320+
268321
/*
269322
/**********************************************************
270323
/* Helper methods for exception handling

src/main/java/com/fasterxml/jackson/databind/ser/std/CollectionSerializer.java

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Iterator;
66

77
import com.fasterxml.jackson.core.*;
8+
89
import com.fasterxml.jackson.databind.BeanProperty;
910
import com.fasterxml.jackson.databind.JavaType;
1011
import com.fasterxml.jackson.databind.JsonSerializer;

src/main/java/com/fasterxml/jackson/databind/ser/std/NonTypedScalarSerializerBase.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ protected NonTypedScalarSerializerBase(Class<?> t, boolean bogus) {
2626
}
2727

2828
@Override
29-
public final void serializeWithType(T value, JsonGenerator jgen, SerializerProvider provider,
29+
public final void serializeWithType(T value, JsonGenerator gen, SerializerProvider provider,
3030
TypeSerializer typeSer) throws IOException
3131
{
3232
// no type info, just regular serialization
33-
serialize(value, jgen, provider);
33+
serialize(value, gen, provider);
3434
}
3535
}

0 commit comments

Comments
 (0)