Skip to content

Commit

Permalink
Further work on issue #17
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Mar 15, 2012
1 parent 1ee417d commit e88829a
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 80 deletions.
Expand Up @@ -72,62 +72,63 @@ public QName findRootElement(Annotated ann)
@Override
public String findSerializationName(AnnotatedField af)
{
JacksonXmlProperty pann = af.getAnnotation(JacksonXmlProperty.class);
if (pann != null) {
return pann.localName();
String name = _findXmlName(af);
if (name != null) {
return name;
}
return super.findSerializationName(af);
}

@Override
public String findSerializationName(AnnotatedMethod am)
{
JacksonXmlProperty pann = am.getAnnotation(JacksonXmlProperty.class);
if (pann != null) {
return pann.localName();
String name = _findXmlName(am);
if (name != null) {
return name;
}
return super.findSerializationName(am);
}

@Override
public String findDeserializationName(AnnotatedField af)
{
// Slightly more complicated if we have a wrapper:
JacksonXmlElementWrapper wann = af.getAnnotation(JacksonXmlElementWrapper.class);
if (wann != null) {
return wann.localName();
}
// if not, use basic property name:
JacksonXmlProperty pann = af.getAnnotation(JacksonXmlProperty.class);
if (pann != null) {
return pann.localName();
String name = _findXmlName(af);
if (name != null) {
return name;
}
return super.findDeserializationName(af);
}

@Override
public String findDeserializationName(AnnotatedMethod am)
{
String name = _findXmlName(am);
if (name != null) {
return name;
}
return super.findDeserializationName(am);
}

@Override
public String findDeserializationName(AnnotatedParameter ap)
{
JacksonXmlElementWrapper wann = ap.getAnnotation(JacksonXmlElementWrapper.class);
if (wann != null) {
// empty name not acceptable...
String name = wann.localName();
if (name.length() > 0) {
return name;
}
}

JacksonXmlProperty pann = ap.getAnnotation(JacksonXmlProperty.class);
// can not return empty String here, so:
if (pann != null) {
String name = pann.localName();
if (name.length() > 0) {
return name;
}
String name = _findXmlName(ap);
// empty name not acceptable...
if (name != null && name.length() > 0) {
return name;
}
return super.findDeserializationName(ap);
}

protected String _findXmlName(Annotated a)
{
JacksonXmlProperty pann = a.getAnnotation(JacksonXmlProperty.class);
if (pann != null) {
return pann.localName();
}
return null;
}

/*
/**********************************************************************
/* Overrides for non-public helper methods
Expand Down
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.deser.XmlBeanDeserializerModifier;
import com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerModifier;


Expand All @@ -21,8 +22,10 @@ public JacksonXmlModule()
@Override
public void setupModule(SetupContext context)
{
// Need to modify BeanSerializer that is used
// Need to modify BeanDeserializer, BeanSerializer that are used
context.addBeanSerializerModifier(new XmlBeanSerializerModifier());
context.addBeanDeserializerModifier(new XmlBeanDeserializerModifier());

// as well as AnnotationIntrospector
context.insertAnnotationIntrospector(XML_ANNOTATION_INTROSPECTOR);
}
Expand Down
@@ -0,0 +1,53 @@
package com.fasterxml.jackson.dataformat.xml.deser;

import java.util.*;

import javax.xml.namespace.QName;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.dataformat.xml.util.AnnotationUtil;

/**
* The main reason for a modifier is to support handling of
* 'wrapped' Collection types.
*/
public class XmlBeanDeserializerModifier
extends BeanDeserializerModifier
{
@Override
public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config,
BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs)
{
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
int changed = 0;
for (int i = 0, len = propDefs.size(); i < len; ++i) {
BeanPropertyDefinition prop = propDefs.get(i);
AnnotatedMember acc = prop.getAccessor();
// should not be null, but just in case:
if (acc == null) {
continue;
}
QName wrapperName = AnnotationUtil.findWrapperName(intr, acc);
if (wrapperName == null) {
continue;
}
String localName = wrapperName.getLocalPart();
if ((localName == null || localName.length() == 0)
|| localName.equals(prop.getName())) {
continue;
}
// make copy-on-write as necessary
if (changed == 0) {
propDefs = new ArrayList<BeanPropertyDefinition>(propDefs);
}
++changed;
// Also, must do upcast unfortunately
propDefs.set(i, prop.withName(localName));
}
return propDefs;
}

}
Expand Up @@ -9,7 +9,7 @@
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
import com.fasterxml.jackson.dataformat.xml.XmlAnnotationIntrospector;
import com.fasterxml.jackson.dataformat.xml.util.AnnotationUtil;
import com.fasterxml.jackson.dataformat.xml.util.XmlInfo;


Expand All @@ -34,20 +34,22 @@ public class XmlBeanSerializerModifier extends BeanSerializerModifier
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties)
{
AnnotationIntrospector intr = config.getAnnotationIntrospector();
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
for (int i = 0, len = beanProperties.size(); i < len; ++i) {
BeanPropertyWriter bpw = beanProperties.get(i);
final AnnotatedMember member = bpw.getMember();
String ns = findNamespaceAnnotation(intr, member);
Boolean isAttribute = findIsAttributeAnnotation(intr, member);
String ns = AnnotationUtil.findNamespaceAnnotation(intr, member);
Boolean isAttribute = AnnotationUtil.findIsAttributeAnnotation(intr, member);
bpw.setInternalSetting(XmlBeanSerializer.KEY_XML_INFO, new XmlInfo(isAttribute, ns));

// Actually: if we have a Collection type, easiest place to add wrapping would be here...
// or: let's also allow wrapping of "untyped" (Object): assuming it is a dynamically
// typed Collection...
if (_isContainerType(bpw.getType())) {
String localName = null, wrapperNs = null;

QName wrappedName = new QName(ns, bpw.getName());
QName wrapperName = findWrapperName(intr, member);
QName wrapperName = AnnotationUtil.findWrapperName(intr, member);
if (wrapperName != null) {
localName = wrapperName.getLocalPart();
wrapperNs = wrapperName.getNamespaceURI();
Expand Down Expand Up @@ -106,45 +108,5 @@ private static boolean _isContainerType(JavaType type)
return true;
}
return false;
}

private static String findNamespaceAnnotation(AnnotationIntrospector ai, AnnotatedMember prop)
{
for (AnnotationIntrospector intr : ai.allIntrospectors()) {
if (intr instanceof XmlAnnotationIntrospector) {
String ns = ((XmlAnnotationIntrospector) intr).findNamespace(prop);
if (ns != null) {
return ns;
}
}
}
return null;
}

private static Boolean findIsAttributeAnnotation(AnnotationIntrospector ai, AnnotatedMember prop)
{
for (AnnotationIntrospector intr : ai.allIntrospectors()) {
if (intr instanceof XmlAnnotationIntrospector) {
Boolean b = ((XmlAnnotationIntrospector) intr).isOutputAsAttribute(prop);
if (b != null) {
return b;
}
}
}
return null;
}

private static QName findWrapperName(AnnotationIntrospector ai, AnnotatedMember prop)
{
for (AnnotationIntrospector intr : ai.allIntrospectors()) {
if (intr instanceof XmlAnnotationIntrospector) {
QName n = ((XmlAnnotationIntrospector) intr).findWrapperElement(prop);
if (n != null) {
return n;
}
}
}
return null;
}

}
}
@@ -0,0 +1,51 @@
package com.fasterxml.jackson.dataformat.xml.util;

import javax.xml.namespace.QName;

import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.dataformat.xml.XmlAnnotationIntrospector;

public class AnnotationUtil
{
public static String findNamespaceAnnotation(AnnotationIntrospector ai,
AnnotatedMember prop)
{
for (AnnotationIntrospector intr : ai.allIntrospectors()) {
if (intr instanceof XmlAnnotationIntrospector) {
String ns = ((XmlAnnotationIntrospector) intr).findNamespace(prop);
if (ns != null) {
return ns;
}
}
}
return null;
}

public static Boolean findIsAttributeAnnotation(AnnotationIntrospector ai,
AnnotatedMember prop)
{
for (AnnotationIntrospector intr : ai.allIntrospectors()) {
if (intr instanceof XmlAnnotationIntrospector) {
Boolean b = ((XmlAnnotationIntrospector) intr).isOutputAsAttribute(prop);
if (b != null) {
return b;
}
}
}
return null;
}

public static QName findWrapperName(AnnotationIntrospector ai, AnnotatedMember prop)
{
for (AnnotationIntrospector intr : ai.allIntrospectors()) {
if (intr instanceof XmlAnnotationIntrospector) {
QName n = ((XmlAnnotationIntrospector) intr).findWrapperElement(prop);
if (n != null) {
return n;
}
}
}
return null;
}
}
Expand Up @@ -22,7 +22,7 @@ public static class Person
public int age;

@JacksonXmlElementWrapper(localName = "notes")
@JacksonXmlProperty( localName = "note" )
@JacksonXmlProperty(localName = "note" )
public List<String> notes = new ArrayList<String>();

public Person() { }
Expand All @@ -31,7 +31,30 @@ public Person(String name, int age) {
this.age = age;
}
}


public static class PersonWithGetters
{
@JacksonXmlProperty( isAttribute = true )
public String id;

private List<String> _notes = new ArrayList<String>();

public PersonWithGetters() { }
public PersonWithGetters(String id) {
this.id = id;
}

@JacksonXmlElementWrapper(localName = "notes")
@JacksonXmlProperty( localName = "note" )
public List<String> getStuff() {
return _notes;
}

public void setStuff(List<String> n) {
_notes = n;
}
}

/*
/**********************************************************
/* Unit tests
Expand Down Expand Up @@ -62,4 +85,18 @@ public void testWrappedList() throws Exception
assertEquals("note 1", result.notes.get(0));
assertEquals("note 2", result.notes.get(1));
}

public void testWrappedListWithGetters() throws Exception
{
PersonWithGetters p = new PersonWithGetters("abc");
p._notes.add("note 1");
p._notes.add("note 2");
String xml = MAPPER.writeValueAsString( p );
PersonWithGetters result = MAPPER.readValue(xml, PersonWithGetters.class);
assertNotNull(result);
assertEquals("abc", result.id);
assertEquals(2, result._notes.size());
assertEquals("note 1", result._notes.get(0));
assertEquals("note 2", result._notes.get(1));
}
}

0 comments on commit e88829a

Please sign in to comment.