From 77fa4546260da94531bb947f747891127d843f50 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 25 Feb 2019 19:35:59 -0800 Subject: [PATCH] start work on #333 --- .../dataformat/xml/MapperCopyTest.java | 4 +- .../jackson/dataformat/xml/XmlTestBase.java | 19 +++-- .../xml/deser/CaseInsensitiveDeserTest.java | 2 +- .../xml/deser/Issue274PropertyNameTest.java | 2 +- .../failing/CaseInsensitiveDeser273Test.java | 2 +- .../xml/failing/DefaultTyping325Test.java | 3 +- .../xml/jaxb/BuilderWithJAXB291Test.java | 2 +- .../xml/lists/NestedUnwrappedListsTest.java | 2 +- .../xml/misc/StreamingDecoratorsTest.java | 68 +++++++++++++++ .../xml/testutil/PrefixInputDecorator.java | 84 +++++++++++++++++++ .../xml/testutil/PrefixOutputDecorator.java | 64 ++++++++++++++ 11 files changed, 236 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/dataformat/xml/misc/StreamingDecoratorsTest.java create mode 100644 src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixInputDecorator.java create mode 100644 src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixOutputDecorator.java diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/MapperCopyTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/MapperCopyTest.java index 04864c091..ad0e13508 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/MapperCopyTest.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/MapperCopyTest.java @@ -19,7 +19,7 @@ static class Pojo282 public void testMapperCopy() { - XmlMapper mapper1 = objectMapperBuilder() + XmlMapper mapper1 = mapperBuilder() .nameForTextElement("foo") .configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) @@ -55,7 +55,7 @@ public void testSerializerProviderCopy() { public void testMapperSerialization() throws Exception { - XmlMapper mapper1 = objectMapperBuilder() + XmlMapper mapper1 = mapperBuilder() .nameForTextElement("foo") .build(); assertEquals("foo", mapper1.getFactory().getXMLTextElementName()); diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestBase.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestBase.java index 09e2c4eb6..aabfe3c36 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestBase.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestBase.java @@ -1,6 +1,7 @@ package com.fasterxml.jackson.dataformat.xml; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import junit.framework.TestCase; @@ -208,14 +209,22 @@ protected XmlTestBase() { super(); } + protected XmlFactoryBuilder streamFactoryBuilder() { + return XmlFactory.builder(); + } + protected static XmlMapper newMapper() { return new XmlMapper(); } - protected static XmlMapper.Builder objectMapperBuilder() { + protected static XmlMapper.Builder mapperBuilder() { return XmlMapper.builder(); } - + + protected static XmlMapper.Builder mapperBuilder(XmlFactory f) { + return XmlMapper.builder(f); + } + protected XmlMapper xmlMapper(boolean useListWrapping) { JacksonXmlModule module = new JacksonXmlModule(); @@ -295,11 +304,7 @@ protected static String aposToQuotes(String json) { } protected byte[] utf8Bytes(String str) { - try { - return str.getBytes("UTF-8"); - } catch (IOException e) { - throw new IllegalArgumentException(e); - } + return str.getBytes(StandardCharsets.UTF_8); } /** diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java index e11f8db2f..87b7c1a2f 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java @@ -32,7 +32,7 @@ public InsensitiveCreator(@JsonProperty("value") int v0) { private final ObjectMapper MAPPER = newMapper(); - private final ObjectMapper INSENSITIVE_MAPPER = objectMapperBuilder() + private final ObjectMapper INSENSITIVE_MAPPER = mapperBuilder() .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) .build(); diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/Issue274PropertyNameTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/Issue274PropertyNameTest.java index 37130ece5..dfc28c799 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/Issue274PropertyNameTest.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/Issue274PropertyNameTest.java @@ -48,7 +48,7 @@ static class RootObject { // [dataformat-xml#274] public void testIssue274() throws Exception { - final ObjectMapper xm = objectMapperBuilder() + final ObjectMapper xm = mapperBuilder() // serialization features // xm.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/CaseInsensitiveDeser273Test.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/CaseInsensitiveDeser273Test.java index 3a77fcc25..e3103a917 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/CaseInsensitiveDeser273Test.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/CaseInsensitiveDeser273Test.java @@ -51,7 +51,7 @@ public void setName(String n) { /******************************************************** */ - private final ObjectMapper INSENSITIVE_MAPPER = objectMapperBuilder() + private final ObjectMapper INSENSITIVE_MAPPER = mapperBuilder() .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) .build(); diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/DefaultTyping325Test.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/DefaultTyping325Test.java index e38e33348..1957a99d9 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/DefaultTyping325Test.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/failing/DefaultTyping325Test.java @@ -19,7 +19,7 @@ static class Simple { public void testCanSerialize() throws IOException { - ObjectMapper mapper = objectMapperBuilder() + ObjectMapper mapper = mapperBuilder() .build(); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_OBJECT); @@ -28,7 +28,6 @@ public void testCanSerialize() throws IOException s.setList(Arrays.asList("foo", "bar")); String doc = mapper.writeValueAsString(s); -System.err.println("DOC: "+doc); Simple result = mapper.readValue(doc, Simple.class); assertNotNull(result.list); assertEquals(2, result.list.size()); diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/jaxb/BuilderWithJAXB291Test.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/jaxb/BuilderWithJAXB291Test.java index a4fcefd19..8adfb85f6 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/jaxb/BuilderWithJAXB291Test.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/jaxb/BuilderWithJAXB291Test.java @@ -121,7 +121,7 @@ public void testBuilder291() throws Exception XmlJaxbAnnotationIntrospector xmlIntr = new XmlJaxbAnnotationIntrospector(TypeFactory.defaultInstance()); AnnotationIntrospector intr = XmlAnnotationIntrospector.Pair.instance (xmlIntr, new JacksonAnnotationIntrospector()); - XmlMapper mapper = objectMapperBuilder() + XmlMapper mapper = mapperBuilder() .annotationIntrospector(intr) .build(); Address value = mapper.readValue(DOC, Address.class); diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/lists/NestedUnwrappedListsTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/lists/NestedUnwrappedListsTest.java index 6f4525b09..cf71382ea 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/lists/NestedUnwrappedListsTest.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/lists/NestedUnwrappedListsTest.java @@ -32,7 +32,7 @@ static class VehicleActivity { /********************************************************************** */ - protected XmlMapper _xmlMapper = objectMapperBuilder() + protected XmlMapper _xmlMapper = mapperBuilder() .propertyNamingStrategy(new PropertyNamingStrategy.UpperCamelCaseStrategy()) .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) .defaultUseWrapper(false) diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/misc/StreamingDecoratorsTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/misc/StreamingDecoratorsTest.java new file mode 100644 index 000000000..147453c4d --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/misc/StreamingDecoratorsTest.java @@ -0,0 +1,68 @@ +package com.fasterxml.jackson.dataformat.xml.misc; + +import java.io.*; +import java.util.*; + +import com.fasterxml.jackson.annotation.JsonRootName; +import com.fasterxml.jackson.dataformat.xml.*; +import com.fasterxml.jackson.dataformat.xml.testutil.PrefixInputDecorator; +import com.fasterxml.jackson.dataformat.xml.testutil.PrefixOutputDecorator; + +public class StreamingDecoratorsTest extends XmlTestBase +{ + @JsonRootName("wrapper") + static class Value { + public String value = "all"; + } + + @SuppressWarnings("unchecked") + public void testInputDecorators() throws IOException + { + final byte[] DOC = utf8Bytes(" value = mapper.readValue(utf8Bytes("value: foo\n"), Map.class); + assertEquals(2, value.size()); + assertEquals("foo", value.get("value")); + assertEquals("mum", value.get("secret")); + + // and then via Reader as well + value = mapper.readValue(new StringReader("value: xyz\n"), Map.class); + assertEquals(2, value.size()); + assertEquals("xyz", value.get("value")); + assertEquals("mum", value.get("secret")); + } + + public void testOutputDecorators() throws IOException + { + final String PREFIX = "///////"; + final byte[] DOC = utf8Bytes(PREFIX); + final XmlMapper mapper = mapperBuilder( + streamFactoryBuilder().outputDecorator(new PrefixOutputDecorator(DOC)) + .build()) + .build(); + final Value input = new Value(); + + // Gets bit tricky because writer will add doc prefix. So let's do simpler check here + + try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) { + mapper.writeValue(bytes, input); + + String raw = bytes.toString("UTF-8"); + if (!raw.startsWith(PREFIX)) { + fail("Should start with prefix, did not: ["+raw+"]"); + } + } + + // and same with char-backed too + try (StringWriter sw = new StringWriter()) { + mapper.writeValue(sw, input); + String raw = sw.toString(); + if (!raw.startsWith(PREFIX)) { + fail("Should start with prefix, did not: ["+raw+"]"); + } + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixInputDecorator.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixInputDecorator.java new file mode 100644 index 000000000..1f7d0a84a --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixInputDecorator.java @@ -0,0 +1,84 @@ +package com.fasterxml.jackson.dataformat.xml.testutil; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.SequenceInputStream; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; + +import com.fasterxml.jackson.core.io.IOContext; +import com.fasterxml.jackson.core.io.InputDecorator; + +@SuppressWarnings("serial") +public class PrefixInputDecorator extends InputDecorator +{ + protected final byte[] _prefix; + + public PrefixInputDecorator(byte[] p) { + _prefix = p; + } + + @Override + public InputStream decorate(IOContext ctxt, InputStream in) { + if (in instanceof MySequenceInputStream) { + throw new IllegalStateException("Trying to decorate MySequenceInputStream (double-decoration!)"); + } + return new MySequenceInputStream(new ByteArrayInputStream(_prefix), in); + } + + @Override + public InputStream decorate(IOContext ctxt, byte[] src, int offset, int length) { + return decorate(ctxt, new ByteArrayInputStream(src, offset, length)); + } + + @Override + public Reader decorate(IOContext ctxt, Reader r) throws IOException { + if (r instanceof SequenceReader) { + throw new IllegalStateException("Trying to decorate SequenceReader (double-decoration!)"); + } + String str = new String(_prefix, StandardCharsets.UTF_8); + return new SequenceReader(new StringReader(str), r); + } + + // sub-class only so we can check for "double decoration" + static class MySequenceInputStream extends SequenceInputStream { + public MySequenceInputStream(InputStream in1, InputStream in2) { + super(in1, in2); + } + } + + static class SequenceReader extends Reader { + protected Reader _reader1, _reader2; + + public SequenceReader(Reader r1, Reader r2) { + _reader1 = r1; + _reader2 = r2; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + if (_reader1 != null) { + int count = _reader1.read(cbuf, off, len); + if (count > 0) { + return count; + } + _reader1 = null; + } + if (_reader2 != null) { + int count = _reader2.read(cbuf, off, len); + if (count > 0) { + return count; + } + _reader2 = null; + } + return -1; + } + + @Override + public void close() throws IOException { + _reader1 = _reader2 = null; + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixOutputDecorator.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixOutputDecorator.java new file mode 100644 index 000000000..f0966af0a --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/testutil/PrefixOutputDecorator.java @@ -0,0 +1,64 @@ +package com.fasterxml.jackson.dataformat.xml.testutil; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +import com.fasterxml.jackson.core.io.IOContext; +import com.fasterxml.jackson.core.io.OutputDecorator; + +@SuppressWarnings("serial") +public class PrefixOutputDecorator extends OutputDecorator +{ + protected final byte[] _prefix; + + public PrefixOutputDecorator(byte[] p) { + _prefix = p; + } + + @Override + public OutputStream decorate(IOContext ctxt, OutputStream out) + throws IOException + { + if (out instanceof BufferedOut) { + throw new IllegalStateException("Trying to decorate `Buffered` (double-decoration!)"); + } + return new BufferedOut(out, _prefix); + } + + @Override + public Writer decorate(IOContext ctxt, Writer w) throws IOException { + for (byte b : _prefix) { + w.write((char) (b & 0xFF)); + } + return w; + } + + static class BufferedOut extends FilterOutputStream { + protected byte[] _prefix; + + public BufferedOut(OutputStream b, byte[] prefix) { + super(b); + _prefix = prefix; + } + + @Override + public void write(int b) throws IOException { + if (_prefix != null) { + out.write(_prefix); + _prefix = null; + } + super.write(b); + } + + @Override + public void write(byte[] b, int offset, int len) throws IOException { + if (_prefix != null) { + out.write(_prefix); + _prefix = null; + } + super.write(b, offset, len); + } + } +}