Skip to content

Commit 4950f44

Browse files
committed
1 parent 26b6251 commit 4950f44

File tree

6 files changed

+74
-37
lines changed

6 files changed

+74
-37
lines changed

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Project: jackson-databind
3030
#957: Merge `datatype-jdk7` stuff in (java.nio.file.Path handling)
3131
#959: Schema generation: consider active view, discard non-included properties
3232
#997: Add `MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS`
33+
#998: Allow use of `NON_DEFAULT` for POJOs without default constructor
3334
- Make `JsonValueFormat` (self-)serializable, deserializable, to/from valid external
3435
value (as per JSON Schema spec)
3536

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ protected BeanDescription(JavaType type) {
224224
*/
225225

226226
public abstract Map<Object, AnnotatedMember> findInjectables();
227-
227+
228228
/**
229229
* Method for checking if the POJO type has annotations to
230230
* indicate that a builder is to be used for instantiating
@@ -237,7 +237,7 @@ protected BeanDescription(JavaType type) {
237237
* Method for finding configuration for POJO Builder class.
238238
*/
239239
public abstract JsonPOJOBuilder.Value findPOJOBuilderConfig();
240-
240+
241241
/**
242242
* Method called to create a "default instance" of the bean, currently
243243
* only needed for obtaining default field values which may be used for

src/main/java/com/fasterxml/jackson/databind/introspect/BasicBeanDescription.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,7 @@ public List<AnnotatedConstructor> getConstructors() {
298298
}
299299

300300
@Override
301-
public Object instantiateBean(boolean fixAccess)
302-
{
301+
public Object instantiateBean(boolean fixAccess) {
303302
AnnotatedConstructor ac = _classInfo.getDefaultConstructor();
304303
if (ac == null) {
305304
return null;

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

+24-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
*/
1515
public class PropertyBuilder
1616
{
17+
// @since 2.7
18+
private final static Object NO_DEFAULT_MARKER = Boolean.FALSE;
19+
1720
final protected SerializationConfig _config;
1821
final protected BeanDescription _beanDesc;
1922

@@ -222,22 +225,39 @@ protected JavaType findSerializationType(Annotated a, boolean useStaticTyping, J
222225

223226
protected Object getDefaultBean()
224227
{
225-
if (_defaultBean == null) {
228+
Object def = _defaultBean;
229+
if (def == null) {
226230
/* If we can fix access rights, we should; otherwise non-public
227231
* classes or default constructor will prevent instantiation
228232
*/
229-
_defaultBean = _beanDesc.instantiateBean(_config.canOverrideAccessModifiers());
230-
if (_defaultBean == null) {
233+
def = _beanDesc.instantiateBean(_config.canOverrideAccessModifiers());
234+
if (def == null) {
235+
// 06-Nov-2015, tatu: As per [databind#998], do not fail.
236+
/*
231237
Class<?> cls = _beanDesc.getClassInfo().getAnnotated();
232238
throw new IllegalArgumentException("Class "+cls.getName()+" has no default constructor; can not instantiate default bean value to support 'properties=JsonSerialize.Inclusion.NON_DEFAULT' annotation");
239+
*/
240+
241+
// And use a marker
242+
def = NO_DEFAULT_MARKER;
233243
}
244+
_defaultBean = def;
234245
}
235-
return _defaultBean;
246+
return (def == NO_DEFAULT_MARKER) ? null : _defaultBean;
236247
}
237248

238249
protected Object getDefaultValue(String name, AnnotatedMember member)
239250
{
240251
Object defaultBean = getDefaultBean();
252+
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;
260+
}
241261
try {
242262
return member.getValue(defaultBean);
243263
} catch (Exception e) {

src/test/java/com/fasterxml/jackson/databind/ser/TestNullProperties.java renamed to src/test/java/com/fasterxml/jackson/databind/filter/JsonIncludeTest.java

+39-24
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
package com.fasterxml.jackson.databind.ser;
1+
package com.fasterxml.jackson.databind.filter;
22

33
import java.io.IOException;
44
import java.util.*;
55

66
import com.fasterxml.jackson.annotation.JsonInclude;
7+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
78
import com.fasterxml.jackson.databind.*;
89
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
910

@@ -12,15 +13,9 @@
1213
* {@link JsonSerialize#include} annotation property work
1314
* as expected.
1415
*/
15-
public class TestNullProperties
16+
public class JsonIncludeTest
1617
extends BaseMapTest
1718
{
18-
/*
19-
/**********************************************************
20-
/* Helper beans
21-
/**********************************************************
22-
*/
23-
2419
static class SimpleBean
2520
{
2621
public String getA() { return "a"; }
@@ -47,6 +42,23 @@ static class NonDefaultBean
4742
public String getB() { return _b; }
4843
}
4944

45+
// [databind#998]: Do not require no-arg constructor; but if not, defaults check
46+
// has weaker interpretation
47+
@JsonPropertyOrder({ "x", "y", "z" })
48+
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
49+
static class NonDefaultBeanXYZ
50+
{
51+
public int x;
52+
public int y = 3;
53+
public int z = 7;
54+
55+
NonDefaultBeanXYZ(int x, int y, int z) {
56+
this.x = x;
57+
this.y = y;
58+
this.z = z;
59+
}
60+
}
61+
5062
static class MixedBean
5163
{
5264
String _a = "a", _b = "b";
@@ -76,11 +88,12 @@ static class ArrayBean {
7688
/* Unit tests
7789
/**********************************************************
7890
*/
79-
91+
92+
final private ObjectMapper MAPPER = new ObjectMapper();
93+
8094
public void testGlobal() throws IOException
8195
{
82-
ObjectMapper m = new ObjectMapper();
83-
Map<String,Object> result = writeAndMap(m, new SimpleBean());
96+
Map<String,Object> result = writeAndMap(MAPPER, new SimpleBean());
8497
assertEquals(2, result.size());
8598
assertEquals("a", result.get("a"));
8699
assertNull(result.get("b"));
@@ -89,8 +102,7 @@ public void testGlobal() throws IOException
89102

90103
public void testNonNullByClass() throws IOException
91104
{
92-
ObjectMapper m = new ObjectMapper();
93-
Map<String,Object> result = writeAndMap(m, new NoNullsBean());
105+
Map<String,Object> result = writeAndMap(MAPPER, new NoNullsBean());
94106
assertEquals(1, result.size());
95107
assertFalse(result.containsKey("a"));
96108
assertNull(result.get("a"));
@@ -100,48 +112,51 @@ public void testNonNullByClass() throws IOException
100112

101113
public void testNonDefaultByClass() throws IOException
102114
{
103-
ObjectMapper m = new ObjectMapper();
104115
NonDefaultBean bean = new NonDefaultBean();
105116
// need to change one of defaults
106117
bean._a = "notA";
107-
Map<String,Object> result = writeAndMap(m, bean);
118+
Map<String,Object> result = writeAndMap(MAPPER, bean);
108119
assertEquals(1, result.size());
109120
assertTrue(result.containsKey("a"));
110121
assertEquals("notA", result.get("a"));
111122
assertFalse(result.containsKey("b"));
112123
assertNull(result.get("b"));
113124
}
114125

126+
// [databind#998]
127+
public void testNonDefaultByClassNoCtor() throws IOException
128+
{
129+
NonDefaultBeanXYZ bean = new NonDefaultBeanXYZ(1, 2, 0);
130+
String json = MAPPER.writeValueAsString(bean);
131+
assertEquals(aposToQuotes("{'x':1,'y':2}"), json);
132+
}
133+
115134
public void testMixedMethod() throws IOException
116135
{
117-
ObjectMapper m = new ObjectMapper();
118-
119136
MixedBean bean = new MixedBean();
120137
bean._a = "xyz";
121138
bean._b = null;
122-
Map<String,Object> result = writeAndMap(m, bean);
139+
Map<String,Object> result = writeAndMap(MAPPER, bean);
123140
assertEquals(1, result.size());
124141
assertEquals("xyz", result.get("a"));
125142
assertFalse(result.containsKey("b"));
126143

127144
bean._a = "a";
128145
bean._b = "b";
129-
result = writeAndMap(m, bean);
146+
result = writeAndMap(MAPPER, bean);
130147
assertEquals(1, result.size());
131148
assertEquals("b", result.get("b"));
132149
assertFalse(result.containsKey("a"));
133150
}
134151

135152
public void testDefaultForEmptyList() throws IOException
136153
{
137-
ObjectMapper m = new ObjectMapper();
138-
assertEquals("{}", m.writeValueAsString(new ListBean()));
154+
assertEquals("{}", MAPPER.writeValueAsString(new ListBean()));
139155
}
140156

141-
// [JACKSON-531]: make NON_DEFAULT work for arrays too
157+
// NON_DEFAULT shoud work for arrays too
142158
public void testNonEmptyDefaultArray() throws IOException
143159
{
144-
ObjectMapper m = new ObjectMapper();
145-
assertEquals("{}", m.writeValueAsString(new ArrayBean()));
160+
assertEquals("{}", MAPPER.writeValueAsString(new ArrayBean()));
146161
}
147162
}

src/test/java/com/fasterxml/jackson/databind/ser/TestNullSerialization.java renamed to src/test/java/com/fasterxml/jackson/databind/filter/NullSerializationTest.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1-
package com.fasterxml.jackson.databind.ser;
1+
package com.fasterxml.jackson.databind.filter;
22

33
import java.io.*;
44

55
import com.fasterxml.jackson.core.*;
66
import com.fasterxml.jackson.databind.*;
77
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
88
import com.fasterxml.jackson.databind.node.ObjectNode;
9+
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
10+
import com.fasterxml.jackson.databind.ser.SerializerFactory;
911

10-
public class TestNullSerialization
12+
public class NullSerializationTest
1113
extends BaseMapTest
1214
{
1315
static class NullSerializer extends JsonSerializer<Object>
1416
{
1517
@Override
16-
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
17-
throws IOException, JsonProcessingException
18+
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider)
19+
throws IOException
1820
{
19-
jgen.writeString("foobar");
21+
gen.writeString("foobar");
2022
}
2123
}
2224

0 commit comments

Comments
 (0)