Skip to content

Instantly share code, notes, and snippets.

@mikaelhg
Created November 30, 2017 10:05
Show Gist options
  • Save mikaelhg/e65311fe7824ccd405c67a4f70a0559c to your computer and use it in GitHub Desktop.
Save mikaelhg/e65311fe7824ccd405c67a4f70a0559c to your computer and use it in GitHub Desktop.
Using Jackson to emulate GSON for JSON and xstream for XML.
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