blob: 27869806fb1df978cef6935baa9037bc50f1f176 [file] [log] [blame]
package org.codehaus.jackson.jaxb;
import java.io.StringWriter;
import java.util.*;
import java.util.Map.Entry;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.introspect.AnnotatedClass;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
/**
* Tests for verifying that JAXB annotation based introspector
* implementation works as expected
*
* @author Ryan Heaton
* @author Tatu Saloranta
*/
public class TestJaxbAnnotationIntrospector
extends BaseJaxbTest
{
/*
/****************************************************
/* Helper beans
/****************************************************
*/
public static enum EnumExample {
@XmlEnumValue("Value One")
VALUE1
}
public static class JaxbExample
{
private String attributeProperty;
private String elementProperty;
private List<String> wrappedElementProperty;
private EnumExample enumProperty;
private QName qname;
private QName qname1;
private String propertyToIgnore;
@XmlJavaTypeAdapter(QNameAdapter.class)
public QName getQname()
{
return qname;
}
public void setQname(QName qname)
{
this.qname = qname;
}
public QName getQname1()
{
return qname1;
}
public void setQname1(QName qname1)
{
this.qname1 = qname1;
}
@XmlAttribute(name="myattribute")
public String getAttributeProperty()
{
return attributeProperty;
}
public void setAttributeProperty(String attributeProperty)
{
this.attributeProperty = attributeProperty;
}
@XmlElement(name="myelement")
public String getElementProperty()
{
return elementProperty;
}
public void setElementProperty(String elementProperty)
{
this.elementProperty = elementProperty;
}
@XmlElementWrapper(name="mywrapped")
public List<String> getWrappedElementProperty()
{
return wrappedElementProperty;
}
public void setWrappedElementProperty(List<String> wrappedElementProperty)
{
this.wrappedElementProperty = wrappedElementProperty;
}
public EnumExample getEnumProperty()
{
return enumProperty;
}
public void setEnumProperty(EnumExample enumProperty)
{
this.enumProperty = enumProperty;
}
@XmlTransient
public String getPropertyToIgnore()
{
return propertyToIgnore;
}
public void setPropertyToIgnore(String propertyToIgnore)
{
this.propertyToIgnore = propertyToIgnore;
}
}
public static class QNameAdapter extends XmlAdapter<String, QName> {
@Override
public QName unmarshal(String v) throws Exception
{
return QName.valueOf(v);
}
@Override
public String marshal(QName v) throws Exception
{
return (v == null) ? null : v.toString();
}
}
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public static class SimpleBean
{
@XmlElement
protected String jaxb = "1";
@XmlElement
protected String jaxb2 = "2";
@SuppressWarnings("unused")
@XmlElement(name="jaxb3")
private String oddName = "3";
public String notAGetter() { return "xyz"; }
@XmlTransient
public int foobar = 3;
}
@SuppressWarnings("unused")
@XmlAccessorType(XmlAccessType.FIELD)
public static class SimpleBean2 {
protected String jaxb = "1";
private String jaxb2 = "2";
@XmlElement(name="jaxb3")
private String oddName = "3";
}
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlRootElement(namespace="urn:class")
static class NamespaceBean
{
@XmlElement(namespace="urn:method")
public String string;
}
@XmlRootElement(name="test")
static class RootNameBean { }
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public static class AlphaBean
{
public int c = 3;
public int a = 1;
public int b = 2;
}
public static class KeyValuePair {
private String key;
private String value;
public KeyValuePair() {}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
};
}
public static class JAXBMapAdapter extends XmlAdapter<List<KeyValuePair>,Map<String, String>> {
@Override
public List<KeyValuePair> marshal(Map<String, String> arg0) throws Exception {
List<KeyValuePair> keyValueList = new ArrayList<KeyValuePair>();
for(Entry<String, String> entry : arg0.entrySet()) {
KeyValuePair keyValuePair = new KeyValuePair();
keyValuePair.setKey(entry.getKey());
keyValuePair.setValue(entry.getValue());
keyValueList.add(keyValuePair);
}
return keyValueList;
}
@Override
public Map<String, String> unmarshal(List<KeyValuePair> arg0) throws Exception
{
HashMap<String, String> hashMap = new HashMap<String, String>();
for (int i = 0; i < arg0.size(); i++) {
hashMap.put(arg0.get(i).getKey(), arg0.get(i).getValue());
}
return hashMap;
}
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class ParentJAXBBean
{
@XmlJavaTypeAdapter(JAXBMapAdapter.class)
private Map<String, String> params = new HashMap<String, String>();
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
}
// Beans for [JACKSON-256]
@XmlRootElement
static class BeanWithNillable {
public Nillable X;
}
@XmlRootElement
static class Nillable {
@XmlElement (name="Z", nillable=true)
Integer Z;
}
/*
/****************************************************
/* Unit tests
/****************************************************
*/
public void testDetection() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
Map<String,Object> result = writeAndMap(mapper, new SimpleBean());
assertEquals(3, result.size());
assertEquals("1", result.get("jaxb"));
assertEquals("2", result.get("jaxb2"));
assertEquals("3", result.get("jaxb3"));
result = writeAndMap(mapper, new SimpleBean2());
assertEquals(3, result.size());
assertEquals("1", result.get("jaxb"));
assertEquals("2", result.get("jaxb2"));
assertEquals("3", result.get("jaxb3"));
}
/**
* tests getting serializer/deserializer instances.
*/
public void testSerializeDeserializeWithJaxbAnnotations() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
JaxbExample ex = new JaxbExample();
QName qname = new QName("urn:hi", "hello");
ex.setQname(qname);
QName qname1 = new QName("urn:hi", "hello1");
ex.setQname1(qname1);
ex.setAttributeProperty("attributeValue");
ex.setElementProperty("elementValue");
ex.setWrappedElementProperty(Arrays.asList("wrappedElementValue"));
ex.setEnumProperty(EnumExample.VALUE1);
ex.setPropertyToIgnore("ignored");
StringWriter writer = new StringWriter();
mapper.writeValue(writer, ex);
writer.flush();
writer.close();
String json = writer.toString();
// uncomment to see what the json looks like.
// System.out.println(json);
//make sure the json is written out correctly.
JsonNode node = mapper.readValue(json, JsonNode.class);
assertEquals(qname.toString(), node.get("qname").asText());
JsonNode attr = node.get("myattribute");
assertNotNull(attr);
assertEquals("attributeValue", attr.asText());
assertEquals("elementValue", node.get("myelement").asText());
assertEquals(1, node.get("mywrapped").size());
assertEquals("wrappedElementValue", node.get("mywrapped").get(0).asText());
assertEquals("Value One", node.get("enumProperty").asText());
assertNull(node.get("propertyToIgnore"));
//now make sure it gets deserialized correctly.
JaxbExample readEx = mapper.readValue(json, JaxbExample.class);
assertEquals(ex.qname, readEx.qname);
assertEquals(ex.qname1, readEx.qname1);
assertEquals(ex.attributeProperty, readEx.attributeProperty);
assertEquals(ex.elementProperty, readEx.elementProperty);
assertEquals(ex.wrappedElementProperty, readEx.wrappedElementProperty);
assertEquals(ex.enumProperty, readEx.enumProperty);
assertNull(readEx.propertyToIgnore);
}
public void testRootNameAccess() throws Exception
{
AnnotationIntrospector ai = new JaxbAnnotationIntrospector();
// If no @XmlRootElement, should get null (unless pkg has etc)
assertNull(ai.findRootName(AnnotatedClass.construct(SimpleBean.class, ai, null)));
// With @XmlRootElement, but no name, empty String
assertEquals("", ai.findRootName(AnnotatedClass.construct(NamespaceBean.class, ai, null)));
// and otherwise explicit name
assertEquals("test", ai.findRootName(AnnotatedClass.construct(RootNameBean.class, ai, null)));
}
// JAXB can specify that properties are to be written in alphabetic order...
public void testSerializationAlphaOrdering() throws Exception
{
ObjectMapper mapper = getJaxbMapper();
assertEquals("{\"a\":1,\"b\":2,\"c\":3}", serializeAsString(mapper, new AlphaBean()));
}
// Test for [JACKSON-256], thanks John.
// @since 1.5
public void testWriteNulls() throws Exception
{
ObjectMapper mapper = getJaxbMapper();
BeanWithNillable bean = new BeanWithNillable();
bean.X = new Nillable();
assertEquals("{\"X\":{\"Z\":null}}", serializeAsString(mapper, bean));
}
public void testAdapter() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
ParentJAXBBean parentJaxbBean = new ParentJAXBBean();
HashMap<String, String> params = new HashMap<String, String>();
params.put("sampleKey", "sampleValue");
parentJaxbBean.setParams(params);
StringWriter writer = new StringWriter();
mapper.writeValue(writer, parentJaxbBean);
writer.flush();
writer.close();
String json = writer.toString();
// uncomment to see what the json looks like.
//System.out.println(json);
//now make sure it gets deserialized correctly.
ParentJAXBBean readEx = mapper.readValue(json, ParentJAXBBean.class);
assertEquals("sampleValue", readEx.getParams().get("sampleKey"));
}
}