Skip to content

Commit

Permalink
Fix #998
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Nov 7, 2015
1 parent 26b6251 commit 4950f44
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 37 deletions.
1 change: 1 addition & 0 deletions release-notes/VERSION
Expand Up @@ -30,6 +30,7 @@ Project: jackson-databind
#957: Merge `datatype-jdk7` stuff in (java.nio.file.Path handling)
#959: Schema generation: consider active view, discard non-included properties
#997: Add `MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS`
#998: Allow use of `NON_DEFAULT` for POJOs without default constructor
- Make `JsonValueFormat` (self-)serializable, deserializable, to/from valid external
value (as per JSON Schema spec)

Expand Down
Expand Up @@ -224,7 +224,7 @@ protected BeanDescription(JavaType type) {
*/

public abstract Map<Object, AnnotatedMember> findInjectables();

/**
* Method for checking if the POJO type has annotations to
* indicate that a builder is to be used for instantiating
Expand All @@ -237,7 +237,7 @@ protected BeanDescription(JavaType type) {
* Method for finding configuration for POJO Builder class.
*/
public abstract JsonPOJOBuilder.Value findPOJOBuilderConfig();

/**
* Method called to create a "default instance" of the bean, currently
* only needed for obtaining default field values which may be used for
Expand Down
Expand Up @@ -298,8 +298,7 @@ public List<AnnotatedConstructor> getConstructors() {
}

@Override
public Object instantiateBean(boolean fixAccess)
{
public Object instantiateBean(boolean fixAccess) {
AnnotatedConstructor ac = _classInfo.getDefaultConstructor();
if (ac == null) {
return null;
Expand Down
Expand Up @@ -14,6 +14,9 @@
*/
public class PropertyBuilder
{
// @since 2.7
private final static Object NO_DEFAULT_MARKER = Boolean.FALSE;

final protected SerializationConfig _config;
final protected BeanDescription _beanDesc;

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

protected Object getDefaultBean()
{
if (_defaultBean == null) {
Object def = _defaultBean;
if (def == null) {
/* If we can fix access rights, we should; otherwise non-public
* classes or default constructor will prevent instantiation
*/
_defaultBean = _beanDesc.instantiateBean(_config.canOverrideAccessModifiers());
if (_defaultBean == null) {
def = _beanDesc.instantiateBean(_config.canOverrideAccessModifiers());
if (def == null) {
// 06-Nov-2015, tatu: As per [databind#998], do not fail.
/*
Class<?> cls = _beanDesc.getClassInfo().getAnnotated();
throw new IllegalArgumentException("Class "+cls.getName()+" has no default constructor; can not instantiate default bean value to support 'properties=JsonSerialize.Inclusion.NON_DEFAULT' annotation");
*/

// And use a marker
def = NO_DEFAULT_MARKER;
}
_defaultBean = def;
}
return _defaultBean;
return (def == NO_DEFAULT_MARKER) ? null : _defaultBean;
}

protected Object getDefaultValue(String name, AnnotatedMember member)
{
Object defaultBean = getDefaultBean();
if (defaultBean == null) {
// 06-Nov-2015, tatu: Returning null is fine for Object types; but need special
// handling for primitives since they are never passed as nulls.
Class<?> cls = member.getRawType();
if (cls.isPrimitive()) {
return ClassUtil.defaultValue(cls);
}
return null;
}
try {
return member.getValue(defaultBean);
} catch (Exception e) {
Expand Down
@@ -1,9 +1,10 @@
package com.fasterxml.jackson.databind.ser;
package com.fasterxml.jackson.databind.filter;

import java.io.IOException;
import java.util.*;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

Expand All @@ -12,15 +13,9 @@
* {@link JsonSerialize#include} annotation property work
* as expected.
*/
public class TestNullProperties
public class JsonIncludeTest
extends BaseMapTest
{
/*
/**********************************************************
/* Helper beans
/**********************************************************
*/

static class SimpleBean
{
public String getA() { return "a"; }
Expand All @@ -47,6 +42,23 @@ static class NonDefaultBean
public String getB() { return _b; }
}

// [databind#998]: Do not require no-arg constructor; but if not, defaults check
// has weaker interpretation
@JsonPropertyOrder({ "x", "y", "z" })
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
static class NonDefaultBeanXYZ
{
public int x;
public int y = 3;
public int z = 7;

NonDefaultBeanXYZ(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}

static class MixedBean
{
String _a = "a", _b = "b";
Expand Down Expand Up @@ -76,11 +88,12 @@ static class ArrayBean {
/* Unit tests
/**********************************************************
*/


final private ObjectMapper MAPPER = new ObjectMapper();

public void testGlobal() throws IOException
{
ObjectMapper m = new ObjectMapper();
Map<String,Object> result = writeAndMap(m, new SimpleBean());
Map<String,Object> result = writeAndMap(MAPPER, new SimpleBean());
assertEquals(2, result.size());
assertEquals("a", result.get("a"));
assertNull(result.get("b"));
Expand All @@ -89,8 +102,7 @@ public void testGlobal() throws IOException

public void testNonNullByClass() throws IOException
{
ObjectMapper m = new ObjectMapper();
Map<String,Object> result = writeAndMap(m, new NoNullsBean());
Map<String,Object> result = writeAndMap(MAPPER, new NoNullsBean());
assertEquals(1, result.size());
assertFalse(result.containsKey("a"));
assertNull(result.get("a"));
Expand All @@ -100,48 +112,51 @@ public void testNonNullByClass() throws IOException

public void testNonDefaultByClass() throws IOException
{
ObjectMapper m = new ObjectMapper();
NonDefaultBean bean = new NonDefaultBean();
// need to change one of defaults
bean._a = "notA";
Map<String,Object> result = writeAndMap(m, bean);
Map<String,Object> result = writeAndMap(MAPPER, bean);
assertEquals(1, result.size());
assertTrue(result.containsKey("a"));
assertEquals("notA", result.get("a"));
assertFalse(result.containsKey("b"));
assertNull(result.get("b"));
}

// [databind#998]
public void testNonDefaultByClassNoCtor() throws IOException
{
NonDefaultBeanXYZ bean = new NonDefaultBeanXYZ(1, 2, 0);
String json = MAPPER.writeValueAsString(bean);
assertEquals(aposToQuotes("{'x':1,'y':2}"), json);
}

public void testMixedMethod() throws IOException
{
ObjectMapper m = new ObjectMapper();

MixedBean bean = new MixedBean();
bean._a = "xyz";
bean._b = null;
Map<String,Object> result = writeAndMap(m, bean);
Map<String,Object> result = writeAndMap(MAPPER, bean);
assertEquals(1, result.size());
assertEquals("xyz", result.get("a"));
assertFalse(result.containsKey("b"));

bean._a = "a";
bean._b = "b";
result = writeAndMap(m, bean);
result = writeAndMap(MAPPER, bean);
assertEquals(1, result.size());
assertEquals("b", result.get("b"));
assertFalse(result.containsKey("a"));
}

public void testDefaultForEmptyList() throws IOException
{
ObjectMapper m = new ObjectMapper();
assertEquals("{}", m.writeValueAsString(new ListBean()));
assertEquals("{}", MAPPER.writeValueAsString(new ListBean()));
}

// [JACKSON-531]: make NON_DEFAULT work for arrays too
// NON_DEFAULT shoud work for arrays too
public void testNonEmptyDefaultArray() throws IOException
{
ObjectMapper m = new ObjectMapper();
assertEquals("{}", m.writeValueAsString(new ArrayBean()));
assertEquals("{}", MAPPER.writeValueAsString(new ArrayBean()));
}
}
@@ -1,22 +1,24 @@
package com.fasterxml.jackson.databind.ser;
package com.fasterxml.jackson.databind.filter;

import java.io.*;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.ser.SerializerFactory;

public class TestNullSerialization
public class NullSerializationTest
extends BaseMapTest
{
static class NullSerializer extends JsonSerializer<Object>
{
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
jgen.writeString("foobar");
gen.writeString("foobar");
}
}

Expand Down

0 comments on commit 4950f44

Please sign in to comment.