Working on JAXB, @XmlElements to allow polymorphic type handling.
diff --git a/build.xml b/build.xml
index b385c00..334fd78 100644
--- a/build.xml
+++ b/build.xml
@@ -44,7 +44,7 @@
<property name="IMPL_TITLE_JAXRS" value="JAX-RS provider for Json content type, using Jackson data binding" />
<property name="IMPL_TITLE_XC" value="XML Compatibility extensions for Jackson data binding" />
- <property name="IMPL_VERSION" value="1.4.0" />
+ <property name="IMPL_VERSION" value="1.5.0" />
<property name="IMPL_VENDOR" value="http://fasterxml.com" />
<patternset id="dist-all-source-files">
diff --git a/src/mapper/java/org/codehaus/jackson/map/AnnotationIntrospector.java b/src/mapper/java/org/codehaus/jackson/map/AnnotationIntrospector.java
index bccac35..5e0a464 100644
--- a/src/mapper/java/org/codehaus/jackson/map/AnnotationIntrospector.java
+++ b/src/mapper/java/org/codehaus/jackson/map/AnnotationIntrospector.java
@@ -140,22 +140,42 @@
/**
* Method for checking if given class has annotations that indicate
- * that specific type resolver is to be used. This includes not only
+ * that specific type resolver is to be used for handling instances.
+ * This includes not only
* instantiating resolver builder, but also configuring it based on
* relevant annotations (not including ones checked with a call to
- * {@link #findAndAddSubtypes}
+ * {@link #findSubtypes}
*
- * @param a Annotated entity (class, field/method) to check for annotations
- * @param baseType Base java type of property for which resolver is to be found
+ * @param ac Annotated class to check for annotations
+ * @param baseType Base java type of value for which resolver is to be found
*
* @return Type resolver builder for given type, if one found; null if none
*
* @since 1.5
*/
- public abstract TypeResolverBuilder<?> findTypeResolver(Annotated a, JavaType baseType);
+ public abstract TypeResolverBuilder<?> findTypeResolver(AnnotatedClass ac, JavaType baseType);
/**
- * Method for locating annotation-specified subtypes of given class.
+ * Method for checking if given property entity (field or method) has annotations
+ * that indicate that specific type resolver is to be used for handling instances.
+ * This includes not only
+ * instantiating resolver builder, but also configuring it based on
+ * relevant annotations (not including ones checked with a call to
+ * {@link #findSubtypes}
+ *
+ * @param am Annotated member (field or method) to check for annotations
+ * @param baseType Base java type of property for which resolver is to be found
+ *
+ * @return Type resolver builder for properties of given entity, if one found;
+ * null if none
+ *
+ * @since 1.5
+ */
+ public abstract TypeResolverBuilder<?> findPropertyTypeResolver(AnnotatedMember am, JavaType baseType);
+
+ /**
+ * Method for locating annotation-specified subtypes related to annotated
+ * entity (class, method, field)
*
* @param a Annotated entity (class, field/method) to check for annotations
*
@@ -676,16 +696,26 @@
}
@Override
- public TypeResolverBuilder<?> findTypeResolver(Annotated a, JavaType baseType)
+ public TypeResolverBuilder<?> findTypeResolver(AnnotatedClass ac, JavaType baseType)
{
- TypeResolverBuilder<?> b = _primary.findTypeResolver(a, baseType);
+ TypeResolverBuilder<?> b = _primary.findTypeResolver(ac, baseType);
if (b == null) {
- b = _secondary.findTypeResolver(a, baseType);
+ b = _secondary.findTypeResolver(ac, baseType);
}
return b;
}
@Override
+ public TypeResolverBuilder<?> findPropertyTypeResolver(AnnotatedMember am, JavaType baseType)
+ {
+ TypeResolverBuilder<?> b = _primary.findPropertyTypeResolver(am, baseType);
+ if (b == null) {
+ b = _secondary.findPropertyTypeResolver(am, baseType);
+ }
+ return b;
+ }
+
+ @Override
public List<NamedType> findSubtypes(Annotated a)
{
List<NamedType> types1 = _primary.findSubtypes(a);
diff --git a/src/mapper/java/org/codehaus/jackson/map/DeserializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/DeserializerFactory.java
index 6b650bc..133b87d 100644
--- a/src/mapper/java/org/codehaus/jackson/map/DeserializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/DeserializerFactory.java
@@ -1,6 +1,7 @@
package org.codehaus.jackson.map;
import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.introspect.AnnotatedMember;
import org.codehaus.jackson.map.type.*;
import org.codehaus.jackson.type.JavaType;
@@ -84,6 +85,9 @@
* Method called to create a type information deserializer for given base type,
* if one is needed. If not needed (no polymorphic handling configured for type),
* should return null.
+ *<p>
+ * Note that this method is only called for values of container (Collection, array, Map)
+ * types and root values, but not for bean property values.
*
* @param baseType Declared base type of the value to deserializer (actual
* deserializer type will be this type or its subtype)
@@ -98,4 +102,28 @@
// Default implementation returns null for backwards compatibility reasons
return null;
}
+
+ /**
+ * Method called to create a type information deserializer for given property entity,
+ * if one is needed. If not needed (no polymorphic handling configured for property),
+ * should return null.
+ *<p>
+ * Note that this method is only called for bean properties, and not for values in
+ * container types or root values.
+ *
+ * @param baseType Declared base type of the value to deserializer (actual
+ * deserializer type will be this type or its subtype)
+ * @param deser Deserializer used for base type deserialization
+ *
+ * @return Type deserializer to use for given base type, if one is needed; null if not.
+ *
+ * @since 1.5
+ */
+ public TypeDeserializer createPropertyTypeDeserializer(DeserializationConfig config, JavaType baseType,
+ AnnotatedMember propertyEntity)
+ {
+ // Default implementation returns null for backwards compatibility reasons
+ return null;
+ }
+
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/SerializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/SerializerFactory.java
index 53338bd..c9d2c90 100644
--- a/src/mapper/java/org/codehaus/jackson/map/SerializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/SerializerFactory.java
@@ -1,5 +1,6 @@
package org.codehaus.jackson.map;
+import org.codehaus.jackson.map.introspect.AnnotatedMember;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType;
@@ -61,4 +62,12 @@
// Default implementation returns null for backwards compatibility reasons.
return null;
}
+
+ public TypeSerializer createPropertyTypeSerializer(JavaType baseType, SerializationConfig config,
+ AnnotatedMember property)
+ {
+ // Default implementation returns null for backwards compatibility reasons.
+ return null;
+ }
+
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java
index b0d2729..7c50c52 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java
@@ -10,6 +10,7 @@
import org.codehaus.jackson.map.introspect.Annotated;
import org.codehaus.jackson.map.introspect.AnnotatedClass;
import org.codehaus.jackson.map.introspect.AnnotatedConstructor;
+import org.codehaus.jackson.map.introspect.AnnotatedMember;
import org.codehaus.jackson.map.introspect.AnnotatedMethod;
import org.codehaus.jackson.map.introspect.AnnotatedParameter;
import org.codehaus.jackson.map.introspect.BasicBeanDescription;
@@ -328,6 +329,30 @@
return (b == null) ? null : b.buildTypeDeserializer(baseType, subtypes);
}
+
+ /**
+ * Method called to construct a type serializer for property values with given declared
+ * base type. This is only called for bean property values.
+ */
+ @Override
+ public TypeDeserializer createPropertyTypeDeserializer(DeserializationConfig config, JavaType baseType,
+ AnnotatedMember propertyEntity)
+ {
+ AnnotationIntrospector ai = config.getAnnotationIntrospector();
+ TypeResolverBuilder<?> b = ai.findPropertyTypeResolver(propertyEntity, baseType);
+ Collection<NamedType> subtypes = null;
+ // Defaulting: if no annotations on member, check value class
+ if (b == null) {
+ return createTypeDeserializer(config, baseType);
+ }
+ // but if annotations found, may need to resolve subtypes:
+ Collection<NamedType> st = ai.findSubtypes(propertyEntity);
+ if (st != null && st.size() > 0) {
+ subtypes = _collectAndResolveSubtypes(config, ai, st);
+ }
+ return b.buildTypeDeserializer(baseType, subtypes);
+ }
+
protected Collection<NamedType> _collectAndResolveSubtypes(MapperConfig<?> config,
AnnotationIntrospector ai, Collection<NamedType> subtypeList)
{
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java
index 9b0e426..1908e7c 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java
@@ -540,7 +540,7 @@
Method m = setter.getAnnotated();
type = modifyTypeByAnnotation(config, setter, type);
- TypeDeserializer typeDeser = createTypeDeserializer(config, type);
+ TypeDeserializer typeDeser = createPropertyTypeDeserializer(config, type, setter);
SettableBeanProperty prop = new SettableBeanProperty.MethodProperty(name, type, typeDeser, m);
if (propDeser != null) {
prop.setValueDeserializer(propDeser);
@@ -565,7 +565,7 @@
JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(config, field);
Field f = field.getAnnotated();
type = modifyTypeByAnnotation(config, field, type);
- TypeDeserializer typeDeser = createTypeDeserializer(config, type);
+ TypeDeserializer typeDeser = createPropertyTypeDeserializer(config, type, field);
SettableBeanProperty prop = new SettableBeanProperty.FieldProperty(name, type, typeDeser, f);
if (propDeser != null) {
prop.setValueDeserializer(propDeser);
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/Annotated.java b/src/mapper/java/org/codehaus/jackson/map/introspect/Annotated.java
index f9adf5a..c83cca4 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/Annotated.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/Annotated.java
@@ -14,6 +14,8 @@
*/
public abstract class Annotated
{
+ protected Annotated() { }
+
public abstract <A extends Annotation> A getAnnotation(Class<A> acls);
public final <A extends Annotation> boolean hasAnnotation(Class<A> acls)
@@ -31,19 +33,30 @@
public abstract String getName();
+ /**
+ * Full generic type of the annotated element; definition
+ * of what exactly this means depends on sub-class.
+ *
+ * @return
+ */
public JavaType getType() {
return TypeFactory.type(getGenericType());
}
/**
+ * Full generic type of the annotated element; definition
+ * of what exactly this means depends on sub-class.
+ *
* @since 1.5
*/
public abstract Type getGenericType();
/**
+ * "Raw" type (type-erased class) of the annotated element; definition
+ * of what exactly this means depends on sub-class.
+ *
* @since 1.5
*/
public abstract Class<?> getRawType();
-
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedConstructor.java b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedConstructor.java
index 2847365..9597087 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedConstructor.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedConstructor.java
@@ -91,7 +91,7 @@
public String toString()
{
- return "[constructor for "+getName()+", annotations: "+_classAnnotations+"]";
+ return "[constructor for "+getName()+", annotations: "+_annotations+"]";
}
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedField.java b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedField.java
index 693aa12..2d1e693 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedField.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedField.java
@@ -6,12 +6,18 @@
import org.codehaus.jackson.map.util.ClassUtil;
+/**
+ * Object that represents non-static (and usually non-transient/volatile)
+ * fields of a class.
+ *
+ * @author tatu
+ */
public final class AnnotatedField
- extends Annotated
+ extends AnnotatedMember
{
- final Field _field;
+ protected final Field _field;
- final AnnotationMap _annotations;
+ protected final AnnotationMap _annotations;
/*
//////////////////////////////////////////////////////
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMember.java b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMember.java
new file mode 100644
index 0000000..28b76a1
--- /dev/null
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMember.java
@@ -0,0 +1,15 @@
+package org.codehaus.jackson.map.introspect;
+
+/**
+ * Intermediate base class for annotated entities that are members of
+ * a class; fields, methods and constructors. This is a superset
+ * of things that can represent logical properties as it contains
+ * constructores in addition to fields and methods.
+ *
+ * @author tatu
+ * @since 1.5
+ */
+public abstract class AnnotatedMember extends Annotated
+{
+ protected AnnotatedMember() { super(); }
+}
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMethod.java b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMethod.java
index 10260da..b36616c 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMethod.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedMethod.java
@@ -120,7 +120,7 @@
public String toString()
{
- return "[method "+getName()+", annotations: "+_classAnnotations+"]";
+ return "[method "+getName()+", annotations: "+_annotations+"]";
}
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedWithParams.java b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedWithParams.java
index d970b30..1b47db3 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedWithParams.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/AnnotatedWithParams.java
@@ -8,10 +8,18 @@
* constructors and methods share.
*/
public abstract class AnnotatedWithParams
- extends Annotated
+ extends AnnotatedMember
{
- protected final AnnotationMap _classAnnotations;
+ /**
+ * Annotations directly associated with the annotated
+ * entity.
+ */
+ protected final AnnotationMap _annotations;
+ /**
+ * Annotations associated with parameters of the annotated
+ * entity (method or constructor parameters)
+ */
protected final AnnotationMap[] _paramAnnotations;
/*
@@ -22,7 +30,7 @@
protected AnnotatedWithParams(AnnotationMap classAnn, AnnotationMap[] paramAnn)
{
- _classAnnotations = classAnn;
+ _annotations = classAnn;
_paramAnnotations = paramAnn;
}
@@ -32,7 +40,7 @@
*/
public final void addOrOverride(Annotation a)
{
- _classAnnotations.add(a);
+ _annotations.add(a);
}
/**
@@ -58,7 +66,7 @@
*/
public final void addIfNotPresent(Annotation a)
{
- _classAnnotations.addIfNotPresent(a);
+ _annotations.addIfNotPresent(a);
}
/*
@@ -69,7 +77,7 @@
public final <A extends Annotation> A getAnnotation(Class<A> acls)
{
- return _classAnnotations.get(acls);
+ return _annotations.get(acls);
}
/*
@@ -96,5 +104,5 @@
public abstract Type getParameterType(int index);
- public final int getAnnotationCount() { return _classAnnotations.size(); }
+ public final int getAnnotationCount() { return _annotations.size(); }
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/JacksonAnnotationIntrospector.java b/src/mapper/java/org/codehaus/jackson/map/introspect/JacksonAnnotationIntrospector.java
index 8814f32..a8f3402 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/JacksonAnnotationIntrospector.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/JacksonAnnotationIntrospector.java
@@ -119,14 +119,19 @@
return (ignore == null) ? null : ignore.ignoreUnknown();
}
+ /*
+ /****************************************************
+ /* Class annotations for PM type handling (1.5+)
+ /****************************************************
+ */
@Override
- public TypeResolverBuilder<?> findTypeResolver(Annotated a, JavaType baseType)
+ public TypeResolverBuilder<?> findTypeResolver(AnnotatedClass ac, JavaType baseType)
{
// First: maybe we have explicit type resolver?
TypeResolverBuilder<?> b;
- JsonTypeInfo info = a.getAnnotation(JsonTypeInfo.class);
- JsonTypeResolver resAnn = a.getAnnotation(JsonTypeResolver.class);
+ JsonTypeInfo info = ac.getAnnotation(JsonTypeInfo.class);
+ JsonTypeResolver resAnn = ac.getAnnotation(JsonTypeResolver.class);
if (resAnn != null) {
/* let's not try to force access override (would need to pass
* settings through if we did, since that's not doable on some
@@ -140,7 +145,7 @@
b = new StdTypeResolverBuilder();
}
// Does it define a custom type id resolver?
- JsonTypeIdResolver idResInfo = a.getAnnotation(JsonTypeIdResolver.class);
+ JsonTypeIdResolver idResInfo = ac.getAnnotation(JsonTypeIdResolver.class);
TypeIdResolver idRes = (idResInfo == null) ? null
: ClassUtil.createInstance(idResInfo.value(), false);
b = b.init(info.use(), idRes);
@@ -150,6 +155,13 @@
}
@Override
+ public TypeResolverBuilder<?> findPropertyTypeResolver(AnnotatedMember am, JavaType baseType)
+ {
+ // No per-member type overrides (yet)
+ return null;
+ }
+
+ @Override
public List<NamedType> findSubtypes(Annotated a)
{
JsonSubTypes t = a.getAnnotation(JsonSubTypes.class);
diff --git a/src/mapper/java/org/codehaus/jackson/map/introspect/NopAnnotationIntrospector.java b/src/mapper/java/org/codehaus/jackson/map/introspect/NopAnnotationIntrospector.java
index a415f0a..6b97a44 100644
--- a/src/mapper/java/org/codehaus/jackson/map/introspect/NopAnnotationIntrospector.java
+++ b/src/mapper/java/org/codehaus/jackson/map/introspect/NopAnnotationIntrospector.java
@@ -85,8 +85,19 @@
return null;
}
+ /*
+ /****************************************************
+ /* Class annotations for PM type handling (1.5+)
+ /****************************************************
+ */
+
@Override
- public TypeResolverBuilder<?> findTypeResolver(Annotated a, JavaType baseType) {
+ public TypeResolverBuilder<?> findTypeResolver(AnnotatedClass ac, JavaType baseType) {
+ return null;
+ }
+
+ @Override
+ public TypeResolverBuilder<?> findPropertyTypeResolver(AnnotatedMember am, JavaType baseType) {
return null;
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/ser/BasicSerializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/ser/BasicSerializerFactory.java
index b44448e..abd0eee 100644
--- a/src/mapper/java/org/codehaus/jackson/map/ser/BasicSerializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/ser/BasicSerializerFactory.java
@@ -8,6 +8,7 @@
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.introspect.Annotated;
import org.codehaus.jackson.map.introspect.AnnotatedClass;
+import org.codehaus.jackson.map.introspect.AnnotatedMember;
import org.codehaus.jackson.map.introspect.BasicBeanDescription;
import org.codehaus.jackson.map.jsontype.NamedType;
import org.codehaus.jackson.map.jsontype.TypeResolverBuilder;
@@ -249,6 +250,11 @@
return (JsonSerializer<Object>)ser;
}
+ /**
+ * Method called to construct a type serializer for values with given declared
+ * base type. This is called for values other than those of bean property
+ * types.
+ */
@Override
public TypeSerializer createTypeSerializer(JavaType baseType, SerializationConfig config)
{
@@ -272,6 +278,29 @@
return (b == null) ? null : b.buildTypeSerializer(baseType, subtypes);
}
+ /**
+ * Method called to construct a type serializer for property values with given declared
+ * base type. This is only called for bean property values.
+ */
+ @Override
+ public TypeSerializer createPropertyTypeSerializer(JavaType baseType, SerializationConfig config,
+ AnnotatedMember propertyEntity)
+ {
+ AnnotationIntrospector ai = config.getAnnotationIntrospector();
+ TypeResolverBuilder<?> b = ai.findPropertyTypeResolver(propertyEntity, baseType);
+ Collection<NamedType> subtypes = null;
+ // Defaulting: if no annotations on member, check value class
+ if (b == null) {
+ return createTypeSerializer(baseType, config);
+ }
+ // but if annotations found, may need to resolve subtypes:
+ Collection<NamedType> st = ai.findSubtypes(propertyEntity);
+ if (st != null && st.size() > 0) {
+ subtypes = _collectAndResolveSubtypes(config, ai, st);
+ }
+ return b.buildTypeSerializer(baseType, subtypes);
+ }
+
protected Collection<NamedType> _collectAndResolveSubtypes(MapperConfig<?> config,
AnnotationIntrospector ai, Collection<NamedType> subtypeList)
{
diff --git a/src/mapper/java/org/codehaus/jackson/map/ser/BeanSerializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/ser/BeanSerializerFactory.java
index f879ff3..78aa0cf 100644
--- a/src/mapper/java/org/codehaus/jackson/map/ser/BeanSerializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/ser/BeanSerializerFactory.java
@@ -224,7 +224,7 @@
// Does Method specify a serializer? If so, let's use it.
JsonSerializer<Object> annotatedSerializer = findSerializerFromAnnotation(config, af);
// And how about polymorphic typing?
- TypeSerializer ts = createTypeSerializer(af.getType(), config);
+ TypeSerializer ts = createPropertyTypeSerializer(af.getType(), config, af);
BeanPropertyWriter pbw = pb.buildProperty(en.getKey(), annotatedSerializer, ts, af, staticTyping);
// how about views? (1.4+)
pbw.setViews(intr.findSerializationViews(af));
@@ -239,7 +239,7 @@
// Does Method specify a serializer? If so, let's use it.
JsonSerializer<Object> annotatedSerializer = findSerializerFromAnnotation(config, am);
// And how about polymorphic typing?
- TypeSerializer ts = createTypeSerializer(am.getType(), config);
+ TypeSerializer ts = createPropertyTypeSerializer(am.getType(), config, am);
BeanPropertyWriter pbw = pb.buildProperty(en.getKey(), annotatedSerializer, ts, am, staticTyping);
pbw.setViews(intr.findSerializationViews(am));
props.add(pbw);
diff --git a/src/mapper/java/org/codehaus/jackson/map/ser/ContainerSerializers.java b/src/mapper/java/org/codehaus/jackson/map/ser/ContainerSerializers.java
index 54448cd..3cc9a85 100644
--- a/src/mapper/java/org/codehaus/jackson/map/ser/ContainerSerializers.java
+++ b/src/mapper/java/org/codehaus/jackson/map/ser/ContainerSerializers.java
@@ -88,7 +88,7 @@
// typing with generics is messy... have to resort to this:
super(cls, false);
_elementType = et;
- // static if explicitly requested, or we got final type
+ // static if explicitly requested, or if element type is final
_staticTyping = staticTyping || (et != null && et.isFinal());
}
diff --git a/src/mapper/java/org/codehaus/jackson/map/ser/MapSerializer.java b/src/mapper/java/org/codehaus/jackson/map/ser/MapSerializer.java
index f8c9184..0517d53 100644
--- a/src/mapper/java/org/codehaus/jackson/map/ser/MapSerializer.java
+++ b/src/mapper/java/org/codehaus/jackson/map/ser/MapSerializer.java
@@ -110,7 +110,7 @@
}
@Override
- public final void serializeWithType(Map<?,?> value, JsonGenerator jgen, SerializerProvider provider,
+ public void serializeWithType(Map<?,?> value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException, JsonGenerationException
{
diff --git a/src/test/org/codehaus/jackson/jaxb/BaseJaxbTest.java b/src/test/org/codehaus/jackson/jaxb/BaseJaxbTest.java
new file mode 100644
index 0000000..8d2d2ca
--- /dev/null
+++ b/src/test/org/codehaus/jackson/jaxb/BaseJaxbTest.java
@@ -0,0 +1,25 @@
+package org.codehaus.jackson.jaxb;
+
+import org.codehaus.jackson.map.*;
+import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
+
+public class BaseJaxbTest
+ extends org.codehaus.jackson.map.BaseMapTest
+{
+ protected BaseJaxbTest() { }
+
+ /*
+ **************************************************************
+ * Helper methods
+ **************************************************************
+ */
+
+ protected ObjectMapper getJaxbMapper()
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ AnnotationIntrospector intr = new JaxbAnnotationIntrospector();
+ mapper.getDeserializationConfig().setAnnotationIntrospector(intr);
+ mapper.getSerializationConfig().setAnnotationIntrospector(intr);
+ return mapper;
+ }
+}
diff --git a/src/test/org/codehaus/jackson/map/introspect/TestIntrospectorPair.java b/src/test/org/codehaus/jackson/jaxb/TestIntrospectorPair.java
similarity index 98%
rename from src/test/org/codehaus/jackson/map/introspect/TestIntrospectorPair.java
rename to src/test/org/codehaus/jackson/jaxb/TestIntrospectorPair.java
index 7b1e328..e5667d7 100644
--- a/src/test/org/codehaus/jackson/map/introspect/TestIntrospectorPair.java
+++ b/src/test/org/codehaus/jackson/jaxb/TestIntrospectorPair.java
@@ -1,4 +1,4 @@
-package org.codehaus.jackson.map.introspect;
+package org.codehaus.jackson.jaxb;
import java.util.*;
@@ -6,6 +6,8 @@
import org.codehaus.jackson.annotate.*;
import org.codehaus.jackson.map.*;
+import org.codehaus.jackson.map.introspect.AnnotatedClass;
+import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
/**
diff --git a/src/test/org/codehaus/jackson/map/introspect/TestJaxbAnnotationIntrospector.java b/src/test/org/codehaus/jackson/jaxb/TestJaxbAnnotationIntrospector.java
similarity index 99%
rename from src/test/org/codehaus/jackson/map/introspect/TestJaxbAnnotationIntrospector.java
rename to src/test/org/codehaus/jackson/jaxb/TestJaxbAnnotationIntrospector.java
index ecaed53..3714cb9 100644
--- a/src/test/org/codehaus/jackson/map/introspect/TestJaxbAnnotationIntrospector.java
+++ b/src/test/org/codehaus/jackson/jaxb/TestJaxbAnnotationIntrospector.java
@@ -1,4 +1,4 @@
-package org.codehaus.jackson.map.introspect;
+package org.codehaus.jackson.jaxb;
import java.io.StringWriter;
import java.util.*;
diff --git a/src/test/org/codehaus/jackson/map/introspect/TestJaxbAutoDetect.java b/src/test/org/codehaus/jackson/jaxb/TestJaxbAutoDetect.java
similarity index 97%
rename from src/test/org/codehaus/jackson/map/introspect/TestJaxbAutoDetect.java
rename to src/test/org/codehaus/jackson/jaxb/TestJaxbAutoDetect.java
index e0f12b9..857ad13 100644
--- a/src/test/org/codehaus/jackson/map/introspect/TestJaxbAutoDetect.java
+++ b/src/test/org/codehaus/jackson/jaxb/TestJaxbAutoDetect.java
@@ -1,4 +1,4 @@
-package org.codehaus.jackson.map.introspect;
+package org.codehaus.jackson.jaxb;
import java.util.*;
import javax.xml.bind.annotation.*;
diff --git a/src/test/org/codehaus/jackson/map/introspect/TestJaxbFieldAccess.java b/src/test/org/codehaus/jackson/jaxb/TestJaxbFieldAccess.java
similarity index 96%
rename from src/test/org/codehaus/jackson/map/introspect/TestJaxbFieldAccess.java
rename to src/test/org/codehaus/jackson/jaxb/TestJaxbFieldAccess.java
index 91f423c..459baaa 100644
--- a/src/test/org/codehaus/jackson/map/introspect/TestJaxbFieldAccess.java
+++ b/src/test/org/codehaus/jackson/jaxb/TestJaxbFieldAccess.java
@@ -1,4 +1,4 @@
-package org.codehaus.jackson.map.introspect;
+package org.codehaus.jackson.jaxb;
import java.io.IOException;
diff --git a/src/test/org/codehaus/jackson/jaxb/TestJaxbPolymorphic.java b/src/test/org/codehaus/jackson/jaxb/TestJaxbPolymorphic.java
new file mode 100644
index 0000000..5a20db3
--- /dev/null
+++ b/src/test/org/codehaus/jackson/jaxb/TestJaxbPolymorphic.java
@@ -0,0 +1,92 @@
+package org.codehaus.jackson.jaxb;
+
+import java.util.*;
+import javax.xml.bind.annotation.*;
+
+import org.codehaus.jackson.map.ObjectMapper;
+
+/**
+ * Tests for handling of type-related JAXB annotations
+ */
+public class TestJaxbPolymorphic
+ extends BaseJaxbTest
+{
+ /*
+ **************************************************************
+ * Helper beans
+ **************************************************************
+ */
+
+ static class Bean
+ {
+ @XmlElements({
+ @XmlElement(type=Buffalo.class, name="beefalot"),
+ @XmlElement(type=Whale.class, name="whale")
+ })
+ public Animal animal;
+
+ public Bean() { }
+ public Bean(Animal a) { animal = a; }
+ }
+
+ static abstract class Animal {
+ public String nickname;
+
+ protected Animal() { }
+ protected Animal(String n) { nickname = n; }
+ }
+
+ static class Buffalo extends Animal {
+ public String hairColor;
+
+ public Buffalo() { }
+ public Buffalo(String name, String hc) {
+ super(name);
+ hairColor = hc;
+ }
+ }
+
+ static class Whale extends Animal {
+ int weightInTons;
+ public Whale() { }
+ public Whale(String n, int w) {
+ super(n);
+ weightInTons = w;
+ }
+ }
+
+ /*
+ **************************************************************
+ * Tests
+ **************************************************************
+ */
+
+ /**
+ * First a simple test with non-collection field
+ */
+ @SuppressWarnings("unchecked")
+ public void testXmlElementTypeDeser() throws Exception
+ {
+ ObjectMapper mapper = getJaxbMapper();
+ Bean input = new Bean(new Buffalo("Billy", "brown"));
+ String str = mapper.writeValueAsString(input);
+ // First: let's verify output looks like what we expect:
+ Map<String,Object> map = mapper.readValue(str, Map.class);
+ assertEquals(1, map.size());
+ Map<String,Object> map2 = (Map<String,Object>) map.get("animal");
+ assertNotNull(map2);
+ // second level, should have type info as WRAPPER_OBJECT
+ assertEquals(1, map2.size());
+ assertTrue(map2.containsKey("beefalot"));
+ Map<String,Object> map3 = (Map<String,Object>) map2.get("beefalot");
+ assertEquals(2, map3.size());
+ // good enough, let's deserialize
+
+ Bean result = mapper.readValue(str, Bean.class);
+ Animal a = result.animal;
+ assertNotNull(a);
+ assertEquals(Buffalo.class, a.getClass());
+ assertEquals("Billy", a.nickname);
+ assertEquals("brown", ((Buffalo) a).hairColor);
+ }
+}
diff --git a/src/test/org/codehaus/jackson/map/introspect/TestJaxbTypes.java b/src/test/org/codehaus/jackson/jaxb/TestJaxbTypes.java
similarity index 67%
rename from src/test/org/codehaus/jackson/map/introspect/TestJaxbTypes.java
rename to src/test/org/codehaus/jackson/jaxb/TestJaxbTypes.java
index b4b9ac4..0e944af 100644
--- a/src/test/org/codehaus/jackson/map/introspect/TestJaxbTypes.java
+++ b/src/test/org/codehaus/jackson/jaxb/TestJaxbTypes.java
@@ -1,15 +1,14 @@
-package org.codehaus.jackson.map.introspect;
+package org.codehaus.jackson.jaxb;
import javax.xml.bind.annotation.*;
import org.codehaus.jackson.map.*;
-import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
/**
* Tests for handling of type-related JAXB annotations
*/
public class TestJaxbTypes
- extends org.codehaus.jackson.map.BaseMapTest
+ extends BaseJaxbTest
{
/*
**************************************************************
@@ -53,19 +52,4 @@
assertEquals(13, bean.a);
assertEquals("...", bean.b);
}
-
- /*
- **************************************************************
- * Helper methods
- **************************************************************
- */
-
- public ObjectMapper getJaxbMapper()
- {
- ObjectMapper mapper = new ObjectMapper();
- AnnotationIntrospector intr = new JaxbAnnotationIntrospector();
- mapper.getDeserializationConfig().setAnnotationIntrospector(intr);
- mapper.getSerializationConfig().setAnnotationIntrospector(intr);
- return mapper;
- }
}
diff --git a/src/xc/java/org/codehaus/jackson/xc/JaxbAnnotationIntrospector.java b/src/xc/java/org/codehaus/jackson/xc/JaxbAnnotationIntrospector.java
index 5225668..b7442d4 100644
--- a/src/xc/java/org/codehaus/jackson/xc/JaxbAnnotationIntrospector.java
+++ b/src/xc/java/org/codehaus/jackson/xc/JaxbAnnotationIntrospector.java
@@ -228,13 +228,26 @@
return null;
}
+ /*
+ /****************************************************
+ /* Class annotations for PM type handling (1.5+)
+ /****************************************************
+ */
+
@Override
- public TypeResolverBuilder<?> findTypeResolver(Annotated a, JavaType baseType)
+ public TypeResolverBuilder<?> findTypeResolver(AnnotatedClass ac, JavaType baseType)
+ {
+ // no per-class type resolvers, right?
+ return null;
+ }
+
+ @Override
+ public TypeResolverBuilder<?> findPropertyTypeResolver(AnnotatedMember am, JavaType baseType)
{
/* Assumption: existence of @XmlElements implies need to add
* type information.
*/
- XmlElements elems = findAnnotation(XmlElements.class, a, false, false, false);
+ XmlElements elems = findAnnotation(XmlElements.class, am, false, false, false);
if (elems == null) {
return null;
}