First working version of prefix-for-unwrapped; may want to generalize to allow other kinds of name mangling strategies
diff --git a/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java
index 4fa9278..503c5c9 100644
--- a/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java
+++ b/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java
@@ -334,9 +334,12 @@
/**
* Method called to check whether given property is marked to be "unwrapped"
* when being serialized (and appropriately handled in reverse direction,
- * i.e. expect unwrapped representation during deserialization)
+ * i.e. expect unwrapped representation during deserialization).
+ * Return value is the prefix to use for properties (empty String
+ * meaning no prefix), if not null; or null to indicate that no
+ * unwrapping is expected.
*/
- public Boolean shouldUnwrapProperty(AnnotatedMember member) {
+ public String findUnwrapPrefix(AnnotatedMember member) {
return null;
}
@@ -347,8 +350,7 @@
* annotations from multiple accessors (getters, setters, fields,
* constructor parameters).
*/
- public boolean hasIgnoreMarker(AnnotatedMember m)
- {
+ public boolean hasIgnoreMarker(AnnotatedMember m) {
return false;
}
@@ -970,11 +972,11 @@
}
@Override
- public Boolean shouldUnwrapProperty(AnnotatedMember member)
+ public String findUnwrapPrefix(AnnotatedMember member)
{
- Boolean value = _primary.shouldUnwrapProperty(member);
+ String value = _primary.findUnwrapPrefix(member);
if (value == null) {
- value = _secondary.shouldUnwrapProperty(member);
+ value = _secondary.findUnwrapPrefix(member);
}
return value;
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java
index f770e14..9730676 100644
--- a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java
@@ -103,7 +103,7 @@
* Default implementation just returns 'this'
* indicating that no unwrapped variant exists
*/
- public JsonDeserializer<T> unwrappingDeserializer() {
+ public JsonDeserializer<T> unwrappingDeserializer(String prefix) {
return this;
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java b/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java
index 8e896a1..96df3ed 100644
--- a/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java
@@ -33,8 +33,10 @@
*<p>
* Default implementation just returns serializer as-is,
* indicating that no unwrapped variant exists
+ *
+ * @param prefix Prefix to use for embedded properties, if any
*/
- public JsonSerializer<T> unwrappingSerializer() {
+ public JsonSerializer<T> unwrappingSerializer(String prefix) {
return this;
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java
index 3103fc2..ddc2cf9 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java
@@ -215,6 +215,29 @@
protected BeanDeserializer(BeanDeserializer src, boolean ignoreAllUnknown)
{
super(src._beanType);
+
+ _forClass = src._forClass;
+ _beanType = src._beanType;
+ _property = src._property;
+
+ _valueInstantiator = src._valueInstantiator;
+ _delegateDeserializer = src._delegateDeserializer;
+ _propertyBasedCreator = src._propertyBasedCreator;
+
+ _beanProperties = src._beanProperties;
+ _backRefs = src._backRefs;
+ _ignorableProps = src._ignorableProps;
+ _ignoreAllUnknown = ignoreAllUnknown;
+ _anySetter = src._anySetter;
+ _injectables = src._injectables;
+
+ _nonStandardCreation = src._nonStandardCreation;
+ _unwrappedPropertyHandler = src._unwrappedPropertyHandler;
+ }
+
+ protected BeanDeserializer(BeanDeserializer src, String unwrapPrefix)
+ {
+ super(src._beanType);
_forClass = src._forClass;
_beanType = src._beanType;
@@ -224,10 +247,11 @@
_delegateDeserializer = src._delegateDeserializer;
_propertyBasedCreator = src._propertyBasedCreator;
- _beanProperties = src._beanProperties;
+ _beanProperties = src._beanProperties.withPrefix(unwrapPrefix);
+
_backRefs = src._backRefs;
_ignorableProps = src._ignorableProps;
- _ignoreAllUnknown = ignoreAllUnknown;
+ _ignoreAllUnknown = (unwrapPrefix != null) || src._ignoreAllUnknown;
_anySetter = src._anySetter;
_injectables = src._injectables;
@@ -236,7 +260,7 @@
}
@Override
- public JsonDeserializer<Object> unwrappingDeserializer()
+ public JsonDeserializer<Object> unwrappingDeserializer(String prefix)
{
/* bit kludgy but we don't want to accidentally change type;
* sub-classes MUST override this method to support unwrapped
@@ -249,7 +273,7 @@
* properties; since there may be multiple unwrapped values
* and properties for all may be interleaved...
*/
- return new BeanDeserializer(this, true);
+ return new BeanDeserializer(this, prefix);
}
/*
@@ -409,8 +433,6 @@
/**
* Helper method called to see if given property is part of 'managed' property
* pair (managed + back reference), and if so, handle resolution details.
- *
- * @since 1.9
*/
protected SettableBeanProperty _resolveManagedReferenceProperty(DeserializationConfig config,
SettableBeanProperty prop)
@@ -459,19 +481,20 @@
/**
* Helper method called to see if given property might be so-called unwrapped
* property: these require special handling.
- *
- * @since 1.9
*/
protected SettableBeanProperty _resolveUnwrappedProperty(DeserializationConfig config,
SettableBeanProperty prop)
{
AnnotatedMember am = prop.getMember();
- if (am != null && config.getAnnotationIntrospector().shouldUnwrapProperty(am) == Boolean.TRUE) {
- JsonDeserializer<Object> orig = prop.getValueDeserializer();
- JsonDeserializer<Object> unwrapping = orig.unwrappingDeserializer();
- if (unwrapping != orig && unwrapping != null) {
- // might be cleaner to create new instance; but difficult to do reliably, so:
- return prop.withValueDeserializer(unwrapping);
+ if (am != null) {
+ String prefix = config.getAnnotationIntrospector().findUnwrapPrefix(am);
+ if (prefix != null) {
+ JsonDeserializer<Object> orig = prop.getValueDeserializer();
+ JsonDeserializer<Object> unwrapping = orig.unwrappingDeserializer(prefix);
+ if (unwrapping != orig && unwrapping != null) {
+ // might be cleaner to create new instance; but difficult to do reliably, so:
+ return prop.withValueDeserializer(unwrapping);
+ }
}
}
return null;
@@ -480,8 +503,6 @@
/**
* Helper method that will handle gruesome details of dealing with properties
* that have non-static inner class as value...
- *
- * @since 1.9
*/
protected SettableBeanProperty _resolveInnerClassValuedProperty(DeserializationConfig config,
SettableBeanProperty prop)
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java b/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java
index c279e31..3ff06f0 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java
@@ -62,11 +62,22 @@
_injectableValueId = injectableValueId;
}
+ protected CreatorProperty(CreatorProperty src, String newName) {
+ super(src, newName);
+ _annotated = src._annotated;
+ _injectableValueId = src._injectableValueId;
+ }
+
protected CreatorProperty(CreatorProperty src, JsonDeserializer<Object> deser) {
super(src, deser);
_annotated = src._annotated;
_injectableValueId = src._injectableValueId;
}
+
+ @Override
+ public CreatorProperty withName(String newName) {
+ return new CreatorProperty(this, newName);
+ }
@Override
public CreatorProperty withValueDeserializer(JsonDeserializer<Object> deser) {
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/SettableBeanProperty.java b/src/main/java/com/fasterxml/jackson/databind/deser/SettableBeanProperty.java
index b6f1002..b3a73dd 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/SettableBeanProperty.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/SettableBeanProperty.java
@@ -58,8 +58,6 @@
* Object used to figure out value to be used when 'null' literal is encountered in JSON.
* For most types simply Java null, but for primitive types must
* be a non-null value (like Integer.valueOf(0) for int).
- *
- * @since 1.7
*/
protected NullProvider _nullProvider;
@@ -75,8 +73,6 @@
* when all properties have been collected. Order of entries
* is arbitrary, but once indexes are assigned they are not
* changed.
- *
- * @since 1.7
*/
protected int _propertyIndex = -1;
@@ -105,8 +101,6 @@
/**
* Basic copy-constructor for sub-classes to use.
- *
- * @since 1.9
*/
protected SettableBeanProperty(SettableBeanProperty src)
{
@@ -122,8 +116,6 @@
/**
* Copy-with-deserializer-change constructor for sub-classes to use.
- *
- * @since 1.9
*/
protected SettableBeanProperty(SettableBeanProperty src, JsonDeserializer<Object> deser)
{
@@ -143,7 +135,24 @@
}
}
+ /**
+ * Copy-with-deserializer-change constructor for sub-classes to use.
+ */
+ protected SettableBeanProperty(SettableBeanProperty src, String newName)
+ {
+ _propName = newName;
+ _type = src._type;
+ _contextAnnotations = src._contextAnnotations;
+ _valueDeserializer = src._valueDeserializer;
+ _valueTypeDeserializer = src._valueTypeDeserializer;
+ _nullProvider = src._nullProvider;
+ _managedReferenceName = src._managedReferenceName;
+ _propertyIndex = src._propertyIndex;
+ }
+
public abstract SettableBeanProperty withValueDeserializer(JsonDeserializer<Object> deser);
+
+ public abstract SettableBeanProperty withName(String newName);
public void setManagedReferenceName(String n) {
_managedReferenceName = n;
@@ -340,6 +349,17 @@
_annotated = src._annotated;
_setter = src._setter;
}
+
+ protected MethodProperty(MethodProperty src, String newName) {
+ super(src, newName);
+ _annotated = src._annotated;
+ _setter = src._setter;
+ }
+
+ @Override
+ public MethodProperty withName(String newName) {
+ return new MethodProperty(this, newName);
+ }
@Override
public MethodProperty withValueDeserializer(JsonDeserializer<Object> deser) {
@@ -413,6 +433,17 @@
_annotated = src._annotated;
_getter = src._getter;
}
+
+ protected SetterlessProperty(SetterlessProperty src, String newName) {
+ super(src, newName);
+ _annotated = src._annotated;
+ _getter = src._getter;
+ }
+
+ @Override
+ public SetterlessProperty withName(String newName) {
+ return new SetterlessProperty(this, newName);
+ }
@Override
public SetterlessProperty withValueDeserializer(JsonDeserializer<Object> deser) {
@@ -505,6 +536,17 @@
_annotated = src._annotated;
_field = src._field;
}
+
+ protected FieldProperty(FieldProperty src, String newName) {
+ super(src, newName);
+ _annotated = src._annotated;
+ _field = src._field;
+ }
+
+ @Override
+ public FieldProperty withName(String newName) {
+ return new FieldProperty(this, newName);
+ }
@Override
public FieldProperty withValueDeserializer(JsonDeserializer<Object> deser) {
@@ -593,6 +635,19 @@
_managedProperty = src._managedProperty;
_backProperty = src._backProperty;
}
+
+ protected ManagedReferenceProperty(ManagedReferenceProperty src, String newName) {
+ super(src, newName);
+ _referenceName = src._referenceName;
+ _isContainer = src._isContainer;
+ _managedProperty = src._managedProperty;
+ _backProperty = src._backProperty;
+ }
+
+ @Override
+ public ManagedReferenceProperty withName(String newName) {
+ return new ManagedReferenceProperty(this, newName);
+ }
@Override
public ManagedReferenceProperty withValueDeserializer(JsonDeserializer<Object> deser) {
@@ -670,8 +725,6 @@
* non-static inner class. If so, we will have to use a special
* alternative for default constructor; but otherwise can delegate
* to regular implementation.
- *
- * @since 1.9
*/
public final static class InnerClassProperty
extends SettableBeanProperty
@@ -700,7 +753,18 @@
_delegate = src._delegate.withValueDeserializer(deser);
_creator = src._creator;
}
-
+
+ protected InnerClassProperty(InnerClassProperty src, String newName) {
+ super(src, newName);
+ _delegate = src._delegate.withName(newName);
+ _creator = src._creator;
+ }
+
+ @Override
+ public InnerClassProperty withName(String newName) {
+ return new InnerClassProperty(this, newName);
+ }
+
@Override
public InnerClassProperty withValueDeserializer(JsonDeserializer<Object> deser) {
return new InnerClassProperty(this, deser);
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanPropertyMap.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanPropertyMap.java
index 8204ce6..e16a311 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanPropertyMap.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanPropertyMap.java
@@ -12,8 +12,6 @@
* is performance: although default implementation is very good for generic
* use cases, it can still be streamlined a bit for specific use case
* we have.
- *
- * @since 1.7
*/
public final class BeanPropertyMap
{
@@ -37,7 +35,26 @@
_buckets = buckets;
}
- public void assignIndexes()
+ /**
+ * Factory method for constructing a map where all entries use given
+ * prefix
+ */
+ public BeanPropertyMap withPrefix(String prefix)
+ {
+ if (prefix == null || prefix.length() == 0) {
+ return this;
+ }
+ Iterator<SettableBeanProperty> it = allProperties();
+ ArrayList<SettableBeanProperty> newProps = new ArrayList<SettableBeanProperty>();
+ while (it.hasNext()) {
+ SettableBeanProperty prop = it.next();
+ newProps.add(prop.withName(prefix + prop.getName()));
+ }
+ // should we try to re-index? Ordering probably changed but called probably doesn't want changes...
+ return new BeanPropertyMap(newProps);
+ }
+
+ public BeanPropertyMap assignIndexes()
{
// order is arbitrary, but stable:
int index = 0;
@@ -47,6 +64,7 @@
bucket = bucket.next;
}
}
+ return this;
}
private final static int findSize(int size)
@@ -134,8 +152,6 @@
/**
* Specialized method for removing specified existing entry.
* NOTE: entry MUST exist, otherwise an exception is thrown.
- *
- * @since 1.9
*/
public void remove(SettableBeanProperty property)
{
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/ThrowableDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/ThrowableDeserializer.java
index 0ad29ea..dddfffb 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/ThrowableDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/ThrowableDeserializer.java
@@ -34,13 +34,13 @@
/**
* Alternative constructor used when creating "unwrapping" deserializers
*/
- protected ThrowableDeserializer(BeanDeserializer src, boolean ignoreAllUnknown)
+ protected ThrowableDeserializer(BeanDeserializer src, String unwrapPrefix)
{
- super(src, ignoreAllUnknown);
+ super(src, unwrapPrefix);
}
@Override
- public JsonDeserializer<Object> unwrappingDeserializer()
+ public JsonDeserializer<Object> unwrappingDeserializer(String prefix)
{
if (getClass() != ThrowableDeserializer.class) {
return this;
@@ -49,7 +49,7 @@
* properties; since there may be multiple unwrapped values
* and properties for all may be interleaved...
*/
- return new ThrowableDeserializer(this, true);
+ return new ThrowableDeserializer(this, prefix);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java
index 9d1cb0f..e287ef3 100644
--- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java
+++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java
@@ -135,12 +135,15 @@
}
@Override
- public Boolean shouldUnwrapProperty(AnnotatedMember member)
+ public String findUnwrapPrefix(AnnotatedMember member)
{
JsonUnwrapped ann = member.getAnnotation(JsonUnwrapped.class);
// if not enabled, just means annotation is not enabled; not necessarily
// that unwrapping should not be done (relevant when using chained introspectors)
- return (ann != null && ann.enabled()) ? Boolean.TRUE : null;
+ if (ann != null && ann.enabled()) {
+ return ann.prefix();
+ }
+ return null;
}
@Override
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java
index ae92a4c..ba1a5aa 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java
@@ -194,8 +194,14 @@
/**
* "Copy constructor" to be used by filtering sub-classes
*/
- protected BeanPropertyWriter(BeanPropertyWriter base)
+ protected BeanPropertyWriter(BeanPropertyWriter base) {
+ this(base, base._name);
+ }
+
+ protected BeanPropertyWriter(BeanPropertyWriter base, SerializedString name)
{
+ _name = name;
+
_member = base._member;
_contextAnnotations = base._contextAnnotations;
_declaredType = base._declaredType;
@@ -207,7 +213,6 @@
if (base._internalSettings != null) {
_internalSettings = new HashMap<Object,Object>(base._internalSettings);
}
- _name = base._name;
_cfgSerializationType = base._cfgSerializationType;
_dynamicSerializers = base._dynamicSerializers;
_suppressNulls = base._suppressNulls;
@@ -216,7 +221,14 @@
_typeSerializer = base._typeSerializer;
_nonTrivialBaseType = base._nonTrivialBaseType;
}
-
+
+ public BeanPropertyWriter withName(String newName) {
+ if (newName.equals(_name.toString())) {
+ return this;
+ }
+ return new BeanPropertyWriter(this, new SerializedString(newName));
+ }
+
/**
* Method called to assign value serializer for property
*
@@ -249,8 +261,8 @@
* Method called create an instance that handles details of unwrapping
* contained value.
*/
- public BeanPropertyWriter unwrappingWriter() {
- return new UnwrappingBeanPropertyWriter(this);
+ public BeanPropertyWriter unwrappingWriter(String prefix) {
+ return new UnwrappingBeanPropertyWriter(this, prefix);
}
/**
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java
index 212b8d1..df13e00 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java
@@ -79,8 +79,8 @@
}
@Override
- public JsonSerializer<Object> unwrappingSerializer() {
- return new UnwrappingBeanSerializer(this);
+ public JsonSerializer<Object> unwrappingSerializer(String prefix) {
+ return new UnwrappingBeanSerializer(this, prefix);
}
/*
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/FilteredBeanPropertyWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/FilteredBeanPropertyWriter.java
index 2cbd21d..f58e2be 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/FilteredBeanPropertyWriter.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/FilteredBeanPropertyWriter.java
@@ -4,7 +4,6 @@
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
-
/**
* Decorated {@link BeanPropertyWriter} that will filter out properties
* that are not to be included in currently active JsonView.
@@ -40,6 +39,11 @@
}
@Override
+ public SingleView withName(String newName) {
+ return new SingleView(_delegate.withName(newName), _view);
+ }
+
+ @Override
public void assignSerializer(JsonSerializer<Object> ser) {
_delegate.assignSerializer(ser);
}
@@ -72,6 +76,11 @@
_delegate = delegate;
_views = views;
}
+
+ @Override
+ public MultiView withName(String newName) {
+ return new MultiView(_delegate.withName(newName), _views);
+ }
@Override
public void assignSerializer(JsonSerializer<Object> ser) {
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java
index eddb195..7a578a8 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java
@@ -136,9 +136,9 @@
ser, typeSer, serializationType, m, f, suppressNulls, valueToSuppress);
// [JACKSON-132]: Unwrapping
- Boolean unwrapped = _annotationIntrospector.shouldUnwrapProperty(am);
- if (unwrapped != null && unwrapped.booleanValue()) {
- bpw = bpw.unwrappingWriter();
+ String unwrapPrefix = _annotationIntrospector.findUnwrapPrefix(am);
+ if (unwrapPrefix != null) {
+ bpw = bpw.unwrappingWriter(unwrapPrefix);
}
return bpw;
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanPropertyWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanPropertyWriter.java
index dab06fa..feeb2b8 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanPropertyWriter.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanPropertyWriter.java
@@ -1,13 +1,13 @@
package com.fasterxml.jackson.databind.ser.impl;
import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.SerializedString;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.*;
-
/**
* Variant of {@link BeanPropertyWriter} which will handle unwrapping
* of JSON Object (including of properties of Object within surrounding
@@ -16,8 +16,24 @@
public class UnwrappingBeanPropertyWriter
extends BeanPropertyWriter
{
- public UnwrappingBeanPropertyWriter(BeanPropertyWriter base) {
+ protected final String _prefix;
+
+ public UnwrappingBeanPropertyWriter(BeanPropertyWriter base, String prefix) {
super(base);
+ _prefix = (prefix == null || prefix.length() == 0) ? null : prefix;
+ }
+
+ private UnwrappingBeanPropertyWriter(UnwrappingBeanPropertyWriter base, SerializedString name) {
+ super(base);
+ _prefix = base._prefix;
+ }
+
+ @Override
+ public UnwrappingBeanPropertyWriter withName(String newName) {
+ if (newName.equals(_name.toString())) {
+ return this;
+ }
+ return new UnwrappingBeanPropertyWriter(this, new SerializedString(newName));
}
@Override
@@ -78,7 +94,7 @@
serializer = provider.findValueSerializer(type, this);
}
if (!serializer.isUnwrappingSerializer()) {
- serializer = serializer.unwrappingSerializer();
+ serializer = serializer.unwrappingSerializer(_prefix);
}
_dynamicSerializers = _dynamicSerializers.newWith(type, serializer);
return serializer;
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java
index da4087b..7ab3c7d 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java
@@ -7,7 +7,6 @@
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
-
public class UnwrappingBeanSerializer
extends BeanSerializerBase
{
@@ -21,8 +20,8 @@
* Constructor used for creating unwrapping instance of a
* standard <code>BeanSerializer</code>
*/
- public UnwrappingBeanSerializer(BeanSerializerBase src) {
- super(src);
+ public UnwrappingBeanSerializer(BeanSerializerBase src, String prefix) {
+ super(src, prefix);
}
/*
@@ -32,8 +31,10 @@
*/
@Override
- public JsonSerializer<Object> unwrappingSerializer() {
- // already unwrapping, nothing more to do:
+ public JsonSerializer<Object> unwrappingSerializer(String prefix) {
+ /* !!! 13-Jan-2011, tatu: do we need to do something here?
+ * Would this affect multi-level unwrapping?
+ */
return this;
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
index b4cd876..19d258b 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
@@ -96,6 +96,34 @@
this(src._handledType,
src._props, src._filteredProps, src._anyGetterWriter, src._propertyFilterId);
}
+
+ /**
+ * Copy-constructor that will also rename properties with given prefix
+ * (if it's non-empty)
+ */
+ protected BeanSerializerBase(BeanSerializerBase src, String propertyPrefix) {
+ this(src._handledType,
+ appendPrefix(src._props, propertyPrefix),
+ appendPrefix(src._filteredProps, propertyPrefix),
+ src._anyGetterWriter, src._propertyFilterId);
+ }
+
+ private final static BeanPropertyWriter[] appendPrefix(BeanPropertyWriter[] props,
+ String prefix)
+ {
+ if (prefix == null || prefix.length() == 0 || props == null || props.length == 0) {
+ return props;
+ }
+ final int len = props.length;
+ BeanPropertyWriter[] result = new BeanPropertyWriter[len];
+ for (int i = 0; i < len; ++i) {
+ BeanPropertyWriter bpw = props[i];
+ if (bpw != null) {
+ result[i] = bpw.withName(prefix + bpw.getName());
+ }
+ }
+ return result;
+ }
/*
/**********************************************************
diff --git a/src/test/java/com/fasterxml/jackson/databind/struct/TestUnwrapping.java b/src/test/java/com/fasterxml/jackson/databind/struct/TestUnwrapping.java
index ff054cc..770bdb0 100644
--- a/src/test/java/com/fasterxml/jackson/databind/struct/TestUnwrapping.java
+++ b/src/test/java/com/fasterxml/jackson/databind/struct/TestUnwrapping.java
@@ -68,26 +68,67 @@
unwrapped = new Unwrapping(str, x, y);
}
}
+
+ // Class with unwrapping using prefixes
+ static class PrefixUnwrap
+ {
+ public String name;
+ @JsonUnwrapped(prefix="_")
+ public Location location;
+
+ public PrefixUnwrap() { }
+ public PrefixUnwrap(String str, int x, int y) {
+ name = str;
+ location = new Location(x, y);
+ }
+ }
+
+ /*
+ static class DeepPrefixUnwrap
+ {
+ @JsonUnwrapped(prefix="u")
+ public PrefixUnwrap unwrapped;
+
+ public DeepPrefixUnwrap() { }
+ public DeepPrefixUnwrap(String str, int x, int y) {
+ unwrapped = new PrefixUnwrap(str, x, y);
+ }
+ }*/
/*
/**********************************************************
/* Tests, serialization
/**********************************************************
*/
+
+ private final ObjectMapper mapper = new ObjectMapper();
public void testSimpleUnwrappingSerialize() throws Exception
{
- ObjectMapper m = new ObjectMapper();
assertEquals("{\"name\":\"Tatu\",\"x\":1,\"y\":2}",
- m.writeValueAsString(new Unwrapping("Tatu", 1, 2)));
+ mapper.writeValueAsString(new Unwrapping("Tatu", 1, 2)));
}
+ public void testPrefixedUnwrappingSerialize() throws Exception
+ {
+ assertEquals("{\"name\":\"Tatu\",\"_x\":1,\"_y\":2}",
+ mapper.writeValueAsString(new PrefixUnwrap("Tatu", 1, 2)));
+ }
+
public void testDeepUnwrappingSerialize() throws Exception
{
- ObjectMapper m = new ObjectMapper();
assertEquals("{\"name\":\"Tatu\",\"x\":1,\"y\":2}",
- m.writeValueAsString(new DeepUnwrapping("Tatu", 1, 2)));
+ mapper.writeValueAsString(new DeepUnwrapping("Tatu", 1, 2)));
}
+
+ // 13-Jan-2012, tatu: does not quite work yet -- should, need to investigate:
+ /*
+ public void testDeepPrefixedUnwrappingSerialize() throws Exception
+ {
+ assertEquals("{\"name\":\"Bubba\",\"u_x\":1,\"u_y\":1}",
+ mapper.writeValueAsString(new DeepPrefixUnwrap("Bubba", 1, 1)));
+ }
+ */
/*
/**********************************************************
@@ -97,8 +138,7 @@
public void testSimpleUnwrappedDeserialize() throws Exception
{
- ObjectMapper m = new ObjectMapper();
- Unwrapping bean = m.readValue("{\"name\":\"Tatu\",\"y\":7,\"x\":-13}",
+ Unwrapping bean = mapper.readValue("{\"name\":\"Tatu\",\"y\":7,\"x\":-13}",
Unwrapping.class);
assertEquals("Tatu", bean.name);
Location loc = bean.location;
@@ -106,11 +146,10 @@
assertEquals(-13, loc.x);
assertEquals(7, loc.y);
}
-
+
public void testDoubleUnwrapping() throws Exception
{
- ObjectMapper m = new ObjectMapper();
- TwoUnwrappedProperties bean = m.readValue("{\"first\":\"Joe\",\"y\":7,\"last\":\"Smith\",\"x\":-13}",
+ TwoUnwrappedProperties bean = mapper.readValue("{\"first\":\"Joe\",\"y\":7,\"last\":\"Smith\",\"x\":-13}",
TwoUnwrappedProperties.class);
Location loc = bean.location;
assertNotNull(loc);
@@ -121,11 +160,10 @@
assertEquals("Joe", name.first);
assertEquals("Smith", name.last);
}
-
+
public void testDeepUnwrapping() throws Exception
{
- ObjectMapper m = new ObjectMapper();
- DeepUnwrapping bean = m.readValue("{\"x\":3,\"name\":\"Bob\",\"y\":27}",
+ DeepUnwrapping bean = mapper.readValue("{\"x\":3,\"name\":\"Bob\",\"y\":27}",
DeepUnwrapping.class);
Unwrapping uw = bean.unwrapped;
assertNotNull(uw);
@@ -138,8 +176,7 @@
public void testUnwrappedDeserializeWithCreator() throws Exception
{
- ObjectMapper m = new ObjectMapper();
- UnwrappingWithCreator bean = m.readValue("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
+ UnwrappingWithCreator bean = mapper.readValue("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
UnwrappingWithCreator.class);
assertEquals("Tatu", bean.name);
Location loc = bean.location;
@@ -147,5 +184,14 @@
assertEquals(1, loc.x);
assertEquals(2, loc.y);
}
-
+
+ public void testPrefixedUnwrapping() throws Exception
+ {
+ PrefixUnwrap bean = mapper.readValue("{\"name\":\"Axel\",\"_x\":4,\"_y\":7}", PrefixUnwrap.class);
+ assertNotNull(bean);
+ assertEquals("Axel", bean.name);
+ assertNotNull(bean.location);
+ assertEquals(4, bean.location.x);
+ assertEquals(7, bean.location.y);
+ }
}