Skip to content

Commit

Permalink
Complete #638 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Dec 9, 2014
1 parent b797b94 commit 73a87db
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 19 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Project: jackson-databind
#634: Add `typeFromId(DatabindContext,String)` in `TypeIdDeserializer`
#636: `ClassNotFoundException` for classes not (yet) needed during serialization
(contributed by mspiegel@github)
#638: Add annotation-based method(s) for injecting properties during serialization
(using @JsonAppend, VirtualBeanPropertyWriter)
- Allow use of `Shape.ARRAY` for Enums, as an alias to 'use index'
- Start using `JsonGenerator.writeStartArray(int)` to help data formats
that benefit from knowing number of elements in arrays (and would otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,17 @@ public BeanPropertyWriter(BeanPropertyDefinition propDef,
{
_member = member;
_contextAnnotations = contextAnnotations;

_name = new SerializedString(propDef.getName());
_wrapperName = propDef.getWrapperName();
_metadata = propDef.getMetadata();
_includeInViews = propDef.findViews();

_declaredType = declaredType;
_serializer = (JsonSerializer<Object>) ser;
_dynamicSerializers = (ser == null) ? PropertySerializerMap.emptyMap() : null;
_typeSerializer = typeSer;
_cfgSerializationType = serType;
_metadata = propDef.getMetadata();

if (member instanceof AnnotatedField) {
_accessorMethod = null;
Expand All @@ -210,18 +213,47 @@ public BeanPropertyWriter(BeanPropertyDefinition propDef,
_accessorMethod = (Method) member.getMember();
_field = null;
} else {
// 01-Dec-2014, tatu: Used to be illegal, but now explicitly allowed
// 01-Dec-2014, tatu: Used to be illegal, but now explicitly allowed for virtual props
_accessorMethod = null;
_field = null;
}
_suppressNulls = suppressNulls;
_suppressableValue = suppressableValue;
_includeInViews = propDef.findViews();

// this will be resolved later on, unless nulls are to be suppressed
_nullSerializer = null;
}


/**
* Constructor that may be of use to virtual properties, when there is need for
* the zero-arg ("default") constructor, and actual initialization is done
* after constructor call.
*
* @since 2.5
*/
protected BeanPropertyWriter() {
_member = null;
_contextAnnotations = null;

_name = null;
_wrapperName = null;
_metadata = null;
_includeInViews = null;

_declaredType = null;
_serializer = null;
_dynamicSerializers = null;
_typeSerializer = null;
_cfgSerializationType = null;

_accessorMethod = null;
_field = null;
_suppressNulls = false;
_suppressableValue = null;

_nullSerializer = null;
}

/**
* "Copy constructor" to be used by filtering sub-classes
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,31 @@
* to add "virtual" properties in addition to regular ones.
*
* @since 2.5
*
* @see com.fasterxml.jackson.databind.ser.impl.AttributePropertyWriter
*/
public abstract class VirtualBeanPropertyWriter
extends BeanPropertyWriter
{
/**
* Constructor used by most sub-types.
*/
protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef,
Annotations contextAnnotations, JavaType declaredType,
JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType) {
this(propDef, contextAnnotations, declaredType, ser, typeSer, serType,
Annotations contextAnnotations, JavaType declaredType)
{
this(propDef, contextAnnotations, declaredType, null, null, null,
propDef.findInclusion());
}

/**
* Constructor that may be used by sub-classes for constructing a "blue-print" instance;
* one that will only become (or create) actual usable instance when its
* {@link #withConfig} method is called.
*/
protected VirtualBeanPropertyWriter() {
super();
}

/**
* Pass-through constructor that may be used by sub-classes that
* want full control over implementation.
Expand Down Expand Up @@ -61,7 +75,7 @@ protected static Object _suppressableValue(JsonInclude.Include inclusion) {
}
return null;
}

/*
/**********************************************************
/* Standard accessor overrides
Expand Down Expand Up @@ -98,13 +112,13 @@ public Type getGenericPropertyType() {

/**
* Contextualization method called on a newly constructed virtual bean property.
* If information is used to change behavior, it is recommended that a new instance
* is constructed with given information and returned; however, this is not mandatory
* and modifying (and returning) this instance is legal as well as calls are made
* in thread-safe manner.
* Usually a new intance needs to be created due to finality of some of configuration
* members; otherwise while recommended, creating a new instance is not strictly-speaking
* mandatory because calls are made in thread-safe manner, as part of initialization
* before use.
*
* @param config Currenct configuration; guaranteed to be {@link SerializationConfig}
* (but not typed since caller does not have full typing)
* (just not typed since caller does not have dependency to serialization-specific types)
* @param declaringClass Class that contains this property writer
* @param propDef Nominal property definition to use
* @param type Declared type for the property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import java.util.*;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;

import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.util.Annotations;

/**
* Tests for verifying that one can append virtual properties after regular ones.
Expand All @@ -26,10 +30,10 @@ static class SimpleBean
@JsonAppend(prepend=true, attrs={ @JsonAppend.Attr("id"),
@JsonAppend.Attr(value="internal", propName="extra")
})
static class SimpleBeanPrepend
{
public int value = 13;
}
static class SimpleBeanPrepend
{
public int value = 13;
}

enum ABC {
A, B, C;
Expand All @@ -40,6 +44,44 @@ static class OptionalsBean
{
public int value = 28;
}

static class CustomVProperty
extends VirtualBeanPropertyWriter
{
private CustomVProperty() { super(); }

private CustomVProperty(BeanPropertyDefinition propDef,
Annotations ctxtAnn, JavaType type) {
super(propDef, ctxtAnn, type);
}

@Override
protected Object value(Object bean, JsonGenerator jgen, SerializerProvider prov) {
if (_name.toString().equals("id")) {
return "abc123";
}
if (_name.toString().equals("extra")) {
return new int[] { 42 };
}
return "???";
}

@Override
public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config,
AnnotatedClass declaringClass, BeanPropertyDefinition propDef,
JavaType type)
{
return new CustomVProperty(propDef, declaringClass.getAnnotations(), type);
}
}

@JsonAppend(prepend=true, props={ @JsonAppend.Prop(value=CustomVProperty.class, name="id"),
@JsonAppend.Prop(value=CustomVProperty.class, name="extra")
})
static class CustomVBean
{
public int value = 72;
}

/*
/**********************************************************
Expand Down Expand Up @@ -82,4 +124,11 @@ public void testAttributePropInclusion() throws Exception
.writeValueAsString(new OptionalsBean());
assertEquals(aposToQuotes("{'value':28}"), json);
}

public void testCustomProperties() throws Exception
{
String json = WRITER.withAttribute("desc", "nice")
.writeValueAsString(new CustomVBean());
assertEquals(aposToQuotes("{'id':'abc123','extra':[42],'value':72}"), json);
}
}

0 comments on commit 73a87db

Please sign in to comment.