Skip to content
This repository has been archived by the owner on Jan 22, 2019. It is now read-only.

Commit

Permalink
Fix #52
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jan 5, 2016
1 parent 8bb12b1 commit 5323635
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 20 deletions.
3 changes: 2 additions & 1 deletion release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Project: jackson-module-jaxb-annotations

2.7.0 (not yet released)

No changes since 2.6.
#52: Add a feature in `JaxbAnnotationIntrospector` to define meaning of
`nillable=false` as "JsonInclude.NON_EMPTY"

2.6.3 (12-Oct-2015)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
import javax.xml.bind.annotation.adapters.*;

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.annotation.SimpleObjectIdResolver;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
Expand Down Expand Up @@ -103,7 +99,18 @@ public class JaxbAnnotationIntrospector
protected String _xmlValueName = DEFAULT_NAME_FOR_XML_VALUE;

/**
* @deprecated Since 2.1, use the ctor that takes TypeFactory
* Inclusion value to return for properties annotated with
* {@link XmlElement} and {@link XmlElementWrapper}, in case <code>nillable</code>
* property is left as <code>false</false>. Default setting is
* <code>null</code>; this is typically changed to either
* {@link JsonInclude.Include#NON_NULL} or {@link JsonInclude.Include#NON_EMPTY}.
*
* @since 2.7
*/
protected JsonInclude.Include _nonNillableInclusion = null;

/**
* @deprecated Since 2.1, use constructor that takes TypeFactory.
*/
@Deprecated
public JaxbAnnotationIntrospector() {
Expand Down Expand Up @@ -180,7 +187,26 @@ public void setNameUsedForXmlValue(String name) {
public String getNameUsedForXmlValue() {
return _xmlValueName;
}


/**
* Method to call to change inclusion criteria used for property annotated
* with {@link XmlElement} or {@link XmlElementWrapper}, with <code>nillable</code>
* set as <code>false</code>.
*
* @since 2.7
*/
public JaxbAnnotationIntrospector setNonNillableInclusion(JsonInclude.Include incl) {
_nonNillableInclusion = incl;
return this;
}

/**
* @since 2.7
*/
public JsonInclude.Include getNonNillableInclusion() {
return _nonNillableInclusion;
}

/*
/**********************************************************
/* Extended API (XmlAnnotationIntrospector)
Expand Down Expand Up @@ -707,27 +733,44 @@ public Class<?> findSerializationType(Annotated a)
* Jackson defaults (which are configurable), and only using JAXB explicit annotations.
*/
@Override
@Deprecated // since 2.7
@Deprecated // since 2.7; remove from 2.8
public JsonInclude.Include findSerializationInclusion(Annotated a, JsonInclude.Include defValue)
{
XmlElementWrapper w = a.getAnnotation(XmlElementWrapper.class);
if (w != null) {
if (w.nillable()) {
return JsonInclude.Include.ALWAYS;
}
// [jaxb-annotations#52]: Allow specifying inclusion for `nillable=false` too
if (_nonNillableInclusion != null) {
return _nonNillableInclusion;
}
}
XmlElement e = a.getAnnotation(XmlElement.class);
if (e != null) {
if (e.nillable()) {
return JsonInclude.Include.ALWAYS;
}
// [jaxb-annotations#52]: Allow specifying inclusion for `nillable=false` too
if (_nonNillableInclusion != null) {
return _nonNillableInclusion;
}
}
//better pass default value through, if no explicit direction indicating otherwise
return defValue;
}

// @since 2.7
@Override
@Override // @since 2.7
public JsonInclude.Value findPropertyInclusion(Annotated a)
{
JsonInclude.Include incl = findSerializationInclusion(a, null);
if (incl == null) {
return JsonInclude.Value.empty();
}
return JsonInclude.Value.construct(incl, null);
}

@Override // @since 2.7
public JavaType refineSerializationType(final MapperConfig<?> config,
final Annotated a, final JavaType baseType) throws JsonMappingException
{
Expand Down Expand Up @@ -888,9 +931,8 @@ public boolean hasAsValueAnnotation(AnnotatedMethod am) {

/**
*<p>
* !!! 12-Oct-2009, tatu: This is hideously slow implementation,
* called potentially for every single enum value being
* serialized. Should improve...
* This is very slow implementation, but as of Jackson 2.7, should not be called any more;
* instead, {@link #findEnumValues} should be called which has less overhead.
*/
@Override
public String findEnumValue(Enum<?> e)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.fasterxml.jackson.module.jaxb;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.Module;

Expand Down Expand Up @@ -39,14 +40,38 @@ public enum Priority {
*/
protected Priority _priority = Priority.PRIMARY;

/**
* If the introspector is explicitly set or passed, we'll hold on to that
* until registration.
*
* @since 2.7
*/
protected JaxbAnnotationIntrospector _introspector;

/**
* Value to pass to
* {@link JaxbAnnotationIntrospector#setNonNillableInclusion}
* if defined and non-null.
*
* @since 2.7
*/
protected JsonInclude.Include _nonNillableInclusion;

/*
/**********************************************************
/* Life cycle
/**********************************************************
*/

public JaxbAnnotationModule() { }

/**
* @since 2.7
*/
public JaxbAnnotationModule(JaxbAnnotationIntrospector intr) {
_introspector = intr;
}

@Override
public String getModuleName() {
return getClass().getSimpleName();
Expand All @@ -60,7 +85,13 @@ public Version version() {
@Override
public void setupModule(SetupContext context)
{
JaxbAnnotationIntrospector intr = new JaxbAnnotationIntrospector(context.getTypeFactory());
JaxbAnnotationIntrospector intr = _introspector;
if (intr == null) {
intr = new JaxbAnnotationIntrospector(context.getTypeFactory());
if (_nonNillableInclusion != null) {
intr.setNonNillableInclusion(_nonNillableInclusion);
}
}
switch (_priority) {
case PRIMARY:
context.insertAnnotationIntrospector(intr);
Expand Down Expand Up @@ -91,4 +122,22 @@ public JaxbAnnotationModule setPriority(Priority p) {
}

public Priority getPriority() { return _priority; }

/**
* @since 2.7
*/
public JaxbAnnotationModule setNonNillableInclusion(JsonInclude.Include incl) {
_nonNillableInclusion = incl;
if (_introspector != null) {
_introspector.setNonNillableInclusion(incl);
}
return this;
}

/**
* @since 2.7
*/
public JsonInclude.Include getNonNillableInclusion() {
return _nonNillableInclusion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jaxb.BaseJaxbTest;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;

/**
* Unit tests to ensure that handling of writing of null properties (or not)
Expand All @@ -28,8 +30,6 @@ public static class Bean
public String x = "y";
}

// Beans for [JACKSON-256]

@XmlRootElement
static class BeanWithNillable {
public Nillable X;
Expand All @@ -39,6 +39,22 @@ static class BeanWithNillable {
static class Nillable {
@XmlElement (name="Z", nillable=true)
Integer Z;

public Nillable() { }
public Nillable(int i) {
Z = Integer.valueOf(i);
}
}

@XmlRootElement
static class NonNillableZ {
@XmlElement(name="z", nillable=false)
public Integer z;

public NonNillableZ() { }
public NonNillableZ(int i) {
z = Integer.valueOf(i);
}
}

/*
Expand All @@ -49,19 +65,36 @@ static class Nillable {

private final ObjectMapper MAPPER = getJaxbMapper();

// Test for [JACKSON-256], thanks John.
public void testWriteNulls() throws Exception
{
BeanWithNillable bean = new BeanWithNillable();
bean.X = new Nillable();
assertEquals("{\"X\":{\"Z\":null}}", MAPPER.writeValueAsString(bean));
}

// Testing [JACKSON-309]
public void testNullProps() throws Exception
{
ObjectMapper mapper = getJaxbMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
assertEquals("{\"x\":\"y\"}", mapper.writeValueAsString(new Bean()));
}

public void testNillability() throws Exception
{
ObjectMapper mapper = getJaxbMapper();
// by default, something not marked as nillable will still be written if null
assertEquals("{\"z\":null}", mapper.writeValueAsString(new NonNillableZ()));
assertEquals("{\"z\":3}", mapper.writeValueAsString(new NonNillableZ(3)));

// but we can change that...
mapper = new ObjectMapper()
.registerModule(new JaxbAnnotationModule()
.setNonNillableInclusion(JsonInclude.Include.NON_NULL)
);
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory())
.setNonNillableInclusion(JsonInclude.Include.NON_NULL)
);
assertEquals("{}", mapper.writeValueAsString(new NonNillableZ()));
assertEquals("{\"z\":3}", mapper.writeValueAsString(new NonNillableZ(3)));
}
}

0 comments on commit 5323635

Please sign in to comment.