Created
November 30, 2017 10:05
-
-
Save mikaelhg/e65311fe7824ccd405c67a4f70a0559c to your computer and use it in GitHub Desktop.
Using Jackson to emulate GSON for JSON and xstream for XML.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.mikael.poc.ser; | |
import com.fasterxml.jackson.annotation.JsonInclude; | |
import com.fasterxml.jackson.core.JsonGenerator; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import com.fasterxml.jackson.databind.SerializationConfig; | |
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider; | |
import com.fasterxml.jackson.databind.ser.SerializerFactory; | |
import com.fasterxml.jackson.databind.type.TypeFactory; | |
import com.fasterxml.jackson.dataformat.xml.XmlMapper; | |
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; | |
import com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider; | |
import com.fasterxml.jackson.dataformat.xml.util.XmlRootNameLookup; | |
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Lists; | |
import org.assertj.core.api.Assertions; | |
import org.junit.Test; | |
import javax.xml.bind.annotation.XmlElement; | |
import javax.xml.bind.annotation.XmlElementWrapper; | |
import javax.xml.namespace.QName; | |
import java.io.IOException; | |
import java.io.StringWriter; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* How should we use Jackson to emulate GSON and xstream? | |
*/ | |
public class SerializationCompatibilityTest { | |
public static class NamedList<T> extends ArrayList<T> { | |
private final String listName; | |
private final String itemName; | |
public NamedList(final String listName, final String itemName, final List<T> items) { | |
this.listName = listName; | |
this.itemName = itemName; | |
this.addAll(items); | |
} | |
public static <T> NamedList<T> of(final String listName, final String itemName, final List<T> items) { | |
return new NamedList<>(listName, itemName, items); | |
} | |
} | |
@JsonInclude(JsonInclude.Include.NON_NULL) | |
public static class TestUnit1 { | |
public Integer id = 123; | |
@XmlElementWrapper(name = "word_ids") | |
@XmlElement(name = "int") | |
public List<Integer> word_ids; | |
public List<Integer> l2; | |
} | |
public static class SomethingElseEntirely { | |
public Integer id = 123; | |
} | |
/** | |
* If you fail to implement all constructors, copy() and createInstance(a, b), | |
* your subclassed provider will actually default back to XmlSerializerProvider. | |
*/ | |
public static class CustomXmlSerializerProvider extends XmlSerializerProvider { | |
public CustomXmlSerializerProvider(final CustomXmlSerializerProvider copyFrom, | |
final SerializationConfig serializationConfig, | |
final SerializerFactory serializerFactory) | |
{ | |
super(copyFrom, serializationConfig, serializerFactory); | |
} | |
public CustomXmlSerializerProvider(final XmlRootNameLookup xmlRootNameLookup) { | |
super(xmlRootNameLookup); | |
} | |
public CustomXmlSerializerProvider(final XmlSerializerProvider copyFrom) { | |
super(copyFrom); | |
} | |
@Override | |
public DefaultSerializerProvider copy() { | |
return new CustomXmlSerializerProvider(this); | |
} | |
@Override | |
public DefaultSerializerProvider createInstance( | |
final SerializationConfig config, final SerializerFactory jsf) | |
{ | |
return new CustomXmlSerializerProvider(this, config, jsf); | |
} | |
@Override | |
public void serializeValue(final JsonGenerator gen, final Object value) throws IOException { | |
final Class<?> cls = value.getClass(); | |
final ToXmlGenerator xgen = _asXmlGenerator(gen); | |
if (NamedList.class.isAssignableFrom(cls)) { | |
final NamedList<?> nl = (NamedList<?>) value; | |
_initWithRootName(xgen, new QName("", nl.listName)); | |
_startNamedRootArray(xgen, nl.itemName); | |
try { | |
findTypedValueSerializer(cls, true, null).serialize(value, gen, this); | |
} catch (Exception e) { | |
throw _wrapAsIOE(gen, e); | |
} | |
gen.writeEndObject(); | |
} else { | |
super.serializeValue(gen, value); | |
} | |
} | |
private void _startNamedRootArray(final ToXmlGenerator xgen, final String itemName) | |
throws IOException | |
{ | |
xgen.writeStartObject(); | |
xgen.writeFieldName(itemName); | |
} | |
} | |
public static class CustomXmlMapper extends XmlMapper { | |
public CustomXmlMapper() { | |
super(); | |
this._serializerProvider = new CustomXmlSerializerProvider(new XmlRootNameLookup()); | |
} | |
} | |
private XmlMapper createXmlMapper() { | |
final XmlMapper xmlMapper = new CustomXmlMapper(); | |
xmlMapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(TypeFactory.defaultInstance())); | |
return xmlMapper; | |
} | |
@Test | |
public void testListEmbedding() throws Exception { | |
final XmlMapper xmlMapper = createXmlMapper(); | |
final ObjectMapper objectMapper = new ObjectMapper(); | |
final TestUnit1 unit = new TestUnit1(); | |
unit.word_ids = ImmutableList.of(1, 2, 3); | |
final List<TestUnit1> units1 = Lists.newArrayList(unit); | |
final StringWriter s3 = new StringWriter(); | |
xmlMapper.writeValue(s3, NamedList.of("list", "unit", units1)); | |
Assertions.assertThat(s3.toString()) | |
.isEqualTo("<list><unit><id>123</id><l2/><word_ids><int>1</int><int>2</int><int>3</int></word_ids></unit></list>"); | |
final StringWriter s4 = new StringWriter(); | |
objectMapper.writeValue(s4, NamedList.of("list", "unit", units1)); | |
Assertions.assertThat(s4.toString()) | |
.isEqualTo("[{\"id\":123,\"word_ids\":[1,2,3]}]"); | |
final NamedList<SomethingElseEntirely> l2 = NamedList.of("a", "b", | |
Lists.newArrayList(new SomethingElseEntirely(), | |
new SomethingElseEntirely(), new SomethingElseEntirely())); | |
final StringWriter s5 = new StringWriter(); | |
xmlMapper.writeValue(s5, l2); | |
Assertions.assertThat(s5.toString()).isEqualTo("<a><b><id>123</id></b><b><id>123</id></b><b><id>123</id></b></a>"); | |
final StringWriter s6 = new StringWriter(); | |
objectMapper.writeValue(s6, l2); | |
Assertions.assertThat(s6.toString()).isEqualTo("[{\"id\":123},{\"id\":123},{\"id\":123}]"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment