From acb39201d112bd6afc65092fbbf55a3c5e7b3a63 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 30 Apr 2023 21:49:26 +0100 Subject: [PATCH 01/13] support setting char encoding on output XML --- .../jackson/dataformat/xml/XmlFactory.java | 23 ++++++++++++- .../jackson/dataformat/xml/XmlMapper.java | 32 +++++++++++++++++++ .../dataformat/xml/ser/ToXmlGenerator.java | 22 +++++++++++-- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java index ad97266e9..4d4cca644 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java @@ -517,6 +517,22 @@ public ToXmlGenerator createGenerator(OutputStream out, JsonEncoding enc) throws _generatorFeatures, _xmlGeneratorFeatures, _objectCodec, _createXmlWriter(ctxt, out), _nameProcessor); } + + /** + * @param out + * @param encoding + * @return + * @throws IOException + * @since 2.16 + */ + public ToXmlGenerator createGenerator(OutputStream out, String encoding) throws IOException + { + // false -> we won't manage the stream unless explicitly directed to + final IOContext ctxt = _createContext(_createContentReference(out), false); + return new ToXmlGenerator(ctxt, + _generatorFeatures, _xmlGeneratorFeatures, + _objectCodec, _createXmlWriter(ctxt, out, encoding), _nameProcessor, encoding); + } @Override public ToXmlGenerator createGenerator(Writer out) throws IOException @@ -689,10 +705,15 @@ protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOEx */ protected XMLStreamWriter _createXmlWriter(IOContext ctxt, OutputStream out) throws IOException + { + return _createXmlWriter(ctxt, out, "UTF-8"); + } + + protected XMLStreamWriter _createXmlWriter(IOContext ctxt, OutputStream out, String encoding) throws IOException { XMLStreamWriter sw; try { - sw = _xmlOutputFactory.createXMLStreamWriter(_decorate(ctxt, out), "UTF-8"); + sw = _xmlOutputFactory.createXMLStreamWriter(_decorate(ctxt, out), encoding); } catch (Exception e) { throw new JsonGenerationException(e.getMessage(), e, null); } diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index 09d2c4d97..1499dbef1 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -1,6 +1,7 @@ package com.fasterxml.jackson.dataformat.xml; import java.io.IOException; +import java.io.OutputStream; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; @@ -9,6 +10,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.cfg.CoercionAction; import com.fasterxml.jackson.databind.cfg.CoercionInputShape; @@ -392,4 +394,34 @@ public void writeValue(XMLStreamWriter w0, Object value) throws IOException { // NOTE: above call should do flush(); and we should NOT close here. // Finally, 'g' has no buffers to release. } + + /** + * Method that can be used to serialize any Java value as + * a byte array. + + * @param value value to write as XML bytes + * @param encoding character encoding for the XML output + * @return byte array representing the XML output + * @throws JsonProcessingException + * @since 2.16 + */ + public byte[] writeValueAsBytes(Object value, String encoding) throws JsonProcessingException { + try (ByteArrayBuilder bb = new ByteArrayBuilder(_jsonFactory._getBufferRecycler())) { + _writeValueAndClose(createGenerator(bb, encoding), value); + final byte[] result = bb.toByteArray(); + bb.release(); + return result; + } catch (JsonProcessingException e) { // to support [JACKSON-758] + throw e; + } catch (IOException e) { // shouldn't really happen, but is declared as possibility so: + throw JsonMappingException.fromUnexpectedIOE(e); + } + } + + private JsonGenerator createGenerator(OutputStream out, String encoding) throws IOException { + this._assertNotNull("out", out); + JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); + this._serializationConfig.initialize(g); + return g; + } } diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java index 2e5c8a552..28a690e96 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java @@ -3,6 +3,7 @@ import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.util.*; import javax.xml.XMLConstants; @@ -213,6 +214,13 @@ private Feature(boolean defaultState) { */ protected XmlNameProcessor.XmlName _nameToEncode = new XmlNameProcessor.XmlName(); + /** + * The character encoding for the XML output + * + * @since 2.16 + */ + protected final String _encoding; + /* /********************************************************** /* Life-cycle @@ -221,16 +229,24 @@ private Feature(boolean defaultState) { public ToXmlGenerator(IOContext ctxt, int stdFeatures, int xmlFeatures, ObjectCodec codec, XMLStreamWriter sw, XmlNameProcessor nameProcessor) + { + this(ctxt, stdFeatures, xmlFeatures, codec, sw, nameProcessor, StandardCharsets.UTF_8.name()); + } + + public ToXmlGenerator(IOContext ctxt, int stdFeatures, int xmlFeatures, + ObjectCodec codec, XMLStreamWriter sw, XmlNameProcessor nameProcessor, + String encoding) { super(stdFeatures, codec); _formatFeatures = xmlFeatures; _ioContext = ctxt; _originalXmlWriter = sw; + _encoding = encoding; _xmlWriter = Stax2WriterAdapter.wrapIfNecessary(sw); _stax2Emulation = (_xmlWriter != sw); _nameProcessor = nameProcessor; _xmlPrettyPrinter = (_cfgPrettyPrinter instanceof XmlPrettyPrinter) ? - (XmlPrettyPrinter) _cfgPrettyPrinter : null; + (XmlPrettyPrinter) _cfgPrettyPrinter : null; } /** @@ -245,9 +261,9 @@ public void initGenerator() throws IOException _initialized = true; try { if (Feature.WRITE_XML_1_1.enabledIn(_formatFeatures)) { - _xmlWriter.writeStartDocument("UTF-8", "1.1"); + _xmlWriter.writeStartDocument(_encoding, "1.1"); } else if (Feature.WRITE_XML_DECLARATION.enabledIn(_formatFeatures)) { - _xmlWriter.writeStartDocument("UTF-8", "1.0"); + _xmlWriter.writeStartDocument(_encoding, "1.0"); } else { return; } From 94f71c6b5148f0a21b362adf6627465e2e1ef2bb Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 30 Apr 2023 21:57:06 +0100 Subject: [PATCH 02/13] Update XmlMapper.java --- .../jackson/dataformat/xml/XmlMapper.java | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index 1499dbef1..4720f1e0f 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -1,5 +1,7 @@ package com.fasterxml.jackson.dataformat.xml; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -9,6 +11,7 @@ import javax.xml.stream.XMLStreamWriter; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.exc.StreamWriteException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.*; @@ -398,7 +401,7 @@ public void writeValue(XMLStreamWriter w0, Object value) throws IOException { /** * Method that can be used to serialize any Java value as * a byte array. - + * * @param value value to write as XML bytes * @param encoding character encoding for the XML output * @return byte array representing the XML output @@ -418,10 +421,36 @@ public byte[] writeValueAsBytes(Object value, String encoding) throws JsonProces } } + /** + * Method that can be used to serialize any Java value as + * XML output, written to File provided. + * + * @param resultFile + * @param value + * @param encoding + * @throws IOException + * @throws StreamWriteException + * @throws DatabindException + * @since 2.16 + */ + public void writeValue(File resultFile, Object value, String encoding) + throws IOException, StreamWriteException, DatabindException + { + _writeValueAndClose(createGenerator(resultFile, encoding), value); + } + private JsonGenerator createGenerator(OutputStream out, String encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); this._serializationConfig.initialize(g); return g; } + + private JsonGenerator createGenerator(File outputFile, String encoding) throws IOException { + _assertNotNull("outputFile", outputFile); + JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator( + new FileOutputStream(outputFile), encoding); + _serializationConfig.initialize(g); + return g; + } } From 5e722b7994dfb5e48c3b9398d6740872cde302b3 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 30 Apr 2023 21:58:58 +0100 Subject: [PATCH 03/13] Update XmlMapper.java --- .../jackson/dataformat/xml/XmlMapper.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index 4720f1e0f..1a15fa543 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -439,6 +439,25 @@ public void writeValue(File resultFile, Object value, String encoding) _writeValueAndClose(createGenerator(resultFile, encoding), value); } + /** + * Method that can be used to serialize any Java value as + * JSON output, using output stream provided (using encoding + * {@link JsonEncoding#UTF8}). + *

+ * Note: method does not close the underlying stream explicitly + * here; however, {@link JsonFactory} this mapper uses may choose + * to close the stream depending on its settings (by default, + * it will try to close it when {@link JsonGenerator} we construct + * is closed). + * + * @since 2.16 + */ + public void writeValue(OutputStream out, Object value, String encoding) + throws IOException, StreamWriteException, DatabindException + { + _writeValueAndClose(createGenerator(out, encoding), value); + } + private JsonGenerator createGenerator(OutputStream out, String encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); From 833deefc42c64c842237956caf542176de90c649 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 30 Apr 2023 23:11:27 +0100 Subject: [PATCH 04/13] Create TestCharset.java --- .../dataformat/xml/ser/TestCharset.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java new file mode 100644 index 000000000..7c4962348 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java @@ -0,0 +1,26 @@ +package com.fasterxml.jackson.dataformat.xml.ser; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.XmlTestBase; + +import java.io.IOException; + +public class TestCharset extends XmlTestBase +{ + static class StringBean { + public String 象形字; + } + + public void testBig5() throws IOException + { + StringBean stringBean = new StringBean(); + stringBean.象形字 = "pictogram"; + XmlMapper xmlMapper = new XmlMapper(); + xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_1_1, true); + byte[] xml = xmlMapper.writeValueAsBytes(stringBean, "Big5"); + String xmlText = new String(xml, "Big5"); + String expected = + "<象形字>pictogram"; + assertEquals(expected, xmlText); + } +} From b9480ecf27cd01d2194a2fc0a8ae82fdef77667e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 May 2023 10:08:34 +0100 Subject: [PATCH 05/13] Update XmlMapper.java Update XmlFactory.java Update XmlFactory.java --- .../jackson/dataformat/xml/XmlFactory.java | 18 +++++++++++++++--- .../jackson/dataformat/xml/XmlMapper.java | 12 ++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java index 4d4cca644..9c7444de3 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java @@ -519,9 +519,21 @@ public ToXmlGenerator createGenerator(OutputStream out, JsonEncoding enc) throws } /** - * @param out - * @param encoding - * @return + * Method for constructing a {@link ToXmlGenerator} for writing XML content + * using specified output stream. + * Encoding to use must be specified. + *

+ * Underlying stream is NOT owned by the generator constructed, + * so that generator will NOT close the output stream when + * {@link ToXmlGenerator#close} is called (unless auto-closing + * feature, + * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET} + * is enabled). + * Using application needs to close it explicitly if this is the case. + * + * @param out OutputStream to use for writing JSON content + * @param encoding Character encoding to use + * @return a {@link ToXmlGenerator} instance * @throws IOException * @since 2.16 */ diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index 1a15fa543..e6479f0a6 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -402,7 +402,7 @@ public void writeValue(XMLStreamWriter w0, Object value) throws IOException { * Method that can be used to serialize any Java value as * a byte array. * - * @param value value to write as XML bytes + * @param value value to serialize as XML bytes * @param encoding character encoding for the XML output * @return byte array representing the XML output * @throws JsonProcessingException @@ -425,9 +425,9 @@ public byte[] writeValueAsBytes(Object value, String encoding) throws JsonProces * Method that can be used to serialize any Java value as * XML output, written to File provided. * - * @param resultFile - * @param value - * @param encoding + * @param resultFile the file to write to + * @param value the value to serialize + * @param encoding character encoding for the XML output * @throws IOException * @throws StreamWriteException * @throws DatabindException @@ -458,14 +458,14 @@ public void writeValue(OutputStream out, Object value, String encoding) _writeValueAndClose(createGenerator(out, encoding), value); } - private JsonGenerator createGenerator(OutputStream out, String encoding) throws IOException { + protected final JsonGenerator createGenerator(OutputStream out, String encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); this._serializationConfig.initialize(g); return g; } - private JsonGenerator createGenerator(File outputFile, String encoding) throws IOException { + protected final JsonGenerator createGenerator(File outputFile, String encoding) throws IOException { _assertNotNull("outputFile", outputFile); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator( new FileOutputStream(outputFile), encoding); From cb7b84a8c776c8e95ad475f2c086c184ec1f5407 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 May 2023 11:48:47 +0100 Subject: [PATCH 06/13] use charset instances --- .../fasterxml/jackson/dataformat/xml/XmlFactory.java | 10 ++++++---- .../fasterxml/jackson/dataformat/xml/XmlMapper.java | 11 ++++++----- .../jackson/dataformat/xml/ser/ToXmlGenerator.java | 11 ++++++----- .../jackson/dataformat/xml/ser/TestCharset.java | 6 ++++-- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java index 9c7444de3..69bd2a4f1 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlFactory.java @@ -1,6 +1,8 @@ package com.fasterxml.jackson.dataformat.xml; import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import javax.xml.stream.*; @@ -537,7 +539,7 @@ public ToXmlGenerator createGenerator(OutputStream out, JsonEncoding enc) throws * @throws IOException * @since 2.16 */ - public ToXmlGenerator createGenerator(OutputStream out, String encoding) throws IOException + public ToXmlGenerator createGenerator(OutputStream out, Charset encoding) throws IOException { // false -> we won't manage the stream unless explicitly directed to final IOContext ctxt = _createContext(_createContentReference(out), false); @@ -718,14 +720,14 @@ protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOEx protected XMLStreamWriter _createXmlWriter(IOContext ctxt, OutputStream out) throws IOException { - return _createXmlWriter(ctxt, out, "UTF-8"); + return _createXmlWriter(ctxt, out, StandardCharsets.UTF_8); } - protected XMLStreamWriter _createXmlWriter(IOContext ctxt, OutputStream out, String encoding) throws IOException + protected final XMLStreamWriter _createXmlWriter(IOContext ctxt, OutputStream out, Charset encoding) throws IOException { XMLStreamWriter sw; try { - sw = _xmlOutputFactory.createXMLStreamWriter(_decorate(ctxt, out), encoding); + sw = _xmlOutputFactory.createXMLStreamWriter(_decorate(ctxt, out), encoding.name()); } catch (Exception e) { throw new JsonGenerationException(e.getMessage(), e, null); } diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index e6479f0a6..aa819f2f9 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -4,6 +4,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.Charset; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; @@ -408,7 +409,7 @@ public void writeValue(XMLStreamWriter w0, Object value) throws IOException { * @throws JsonProcessingException * @since 2.16 */ - public byte[] writeValueAsBytes(Object value, String encoding) throws JsonProcessingException { + public byte[] writeValueAsBytes(Object value, Charset encoding) throws JsonProcessingException { try (ByteArrayBuilder bb = new ByteArrayBuilder(_jsonFactory._getBufferRecycler())) { _writeValueAndClose(createGenerator(bb, encoding), value); final byte[] result = bb.toByteArray(); @@ -433,7 +434,7 @@ public byte[] writeValueAsBytes(Object value, String encoding) throws JsonProces * @throws DatabindException * @since 2.16 */ - public void writeValue(File resultFile, Object value, String encoding) + public void writeValue(File resultFile, Object value, Charset encoding) throws IOException, StreamWriteException, DatabindException { _writeValueAndClose(createGenerator(resultFile, encoding), value); @@ -452,20 +453,20 @@ public void writeValue(File resultFile, Object value, String encoding) * * @since 2.16 */ - public void writeValue(OutputStream out, Object value, String encoding) + public void writeValue(OutputStream out, Object value, Charset encoding) throws IOException, StreamWriteException, DatabindException { _writeValueAndClose(createGenerator(out, encoding), value); } - protected final JsonGenerator createGenerator(OutputStream out, String encoding) throws IOException { + protected final JsonGenerator createGenerator(OutputStream out, Charset encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); this._serializationConfig.initialize(g); return g; } - protected final JsonGenerator createGenerator(File outputFile, String encoding) throws IOException { + protected final JsonGenerator createGenerator(File outputFile, Charset encoding) throws IOException { _assertNotNull("outputFile", outputFile); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator( new FileOutputStream(outputFile), encoding); diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java index 28a690e96..6992ec25e 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java @@ -3,6 +3,7 @@ import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; @@ -219,7 +220,7 @@ private Feature(boolean defaultState) { * * @since 2.16 */ - protected final String _encoding; + protected final Charset _encoding; /* /********************************************************** @@ -230,12 +231,12 @@ private Feature(boolean defaultState) { public ToXmlGenerator(IOContext ctxt, int stdFeatures, int xmlFeatures, ObjectCodec codec, XMLStreamWriter sw, XmlNameProcessor nameProcessor) { - this(ctxt, stdFeatures, xmlFeatures, codec, sw, nameProcessor, StandardCharsets.UTF_8.name()); + this(ctxt, stdFeatures, xmlFeatures, codec, sw, nameProcessor, StandardCharsets.UTF_8); } public ToXmlGenerator(IOContext ctxt, int stdFeatures, int xmlFeatures, ObjectCodec codec, XMLStreamWriter sw, XmlNameProcessor nameProcessor, - String encoding) + Charset encoding) { super(stdFeatures, codec); _formatFeatures = xmlFeatures; @@ -261,9 +262,9 @@ public void initGenerator() throws IOException _initialized = true; try { if (Feature.WRITE_XML_1_1.enabledIn(_formatFeatures)) { - _xmlWriter.writeStartDocument(_encoding, "1.1"); + _xmlWriter.writeStartDocument(_encoding.name(), "1.1"); } else if (Feature.WRITE_XML_DECLARATION.enabledIn(_formatFeatures)) { - _xmlWriter.writeStartDocument(_encoding, "1.0"); + _xmlWriter.writeStartDocument(_encoding.name(), "1.0"); } else { return; } diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java index 7c4962348..ecc943657 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlTestBase; import java.io.IOException; +import java.nio.charset.Charset; public class TestCharset extends XmlTestBase { @@ -13,12 +14,13 @@ static class StringBean { public void testBig5() throws IOException { + Charset big5 = Charset.forName("Big5"); StringBean stringBean = new StringBean(); stringBean.象形字 = "pictogram"; XmlMapper xmlMapper = new XmlMapper(); xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_1_1, true); - byte[] xml = xmlMapper.writeValueAsBytes(stringBean, "Big5"); - String xmlText = new String(xml, "Big5"); + byte[] xml = xmlMapper.writeValueAsBytes(stringBean, big5); + String xmlText = new String(xml, big5); String expected = "<象形字>pictogram"; assertEquals(expected, xmlText); From a02bba3e9f38e8dbebed4e2629795b1b72d124d1 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 1 May 2023 13:25:30 +0100 Subject: [PATCH 07/13] DataOutput test --- .../jackson/dataformat/xml/XmlMapper.java | 15 +++++++++++++++ .../jackson/dataformat/xml/ser/TestCharset.java | 14 +++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index aa819f2f9..7256d379e 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -1,5 +1,6 @@ package com.fasterxml.jackson.dataformat.xml; +import java.io.DataOutput; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -13,6 +14,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.exc.StreamWriteException; +import com.fasterxml.jackson.core.io.DataOutputAsStream; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.*; @@ -459,6 +461,12 @@ public void writeValue(OutputStream out, Object value, Charset encoding) _writeValueAndClose(createGenerator(out, encoding), value); } + public void writeValue(DataOutput out, Object value, Charset encoding) + throws IOException, StreamWriteException, DatabindException + { + _writeValueAndClose(createGenerator(out, encoding), value); + } + protected final JsonGenerator createGenerator(OutputStream out, Charset encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); @@ -473,4 +481,11 @@ protected final JsonGenerator createGenerator(File outputFile, Charset encoding) _serializationConfig.initialize(g); return g; } + + protected final JsonGenerator createGenerator(DataOutput out, Charset encoding) throws IOException { + this._assertNotNull("out", out); + JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(new DataOutputAsStream(out), encoding); + this._serializationConfig.initialize(g); + return g; + } } diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java index ecc943657..8f5d46a38 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java @@ -12,7 +12,7 @@ static class StringBean { public String 象形字; } - public void testBig5() throws IOException + public void testBig5Bytes() throws IOException { Charset big5 = Charset.forName("Big5"); StringBean stringBean = new StringBean(); @@ -25,4 +25,16 @@ public void testBig5() throws IOException "<象形字>pictogram"; assertEquals(expected, xmlText); } + + public void testBig5RoundTrip() throws IOException + { + Charset big5 = Charset.forName("Big5"); + StringBean stringBean = new StringBean(); + stringBean.象形字 = "pictogram"; + XmlMapper xmlMapper = new XmlMapper(); + xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_1_1, true); + byte[] xml = xmlMapper.writeValueAsBytes(stringBean, big5); + StringBean stringBean1 = xmlMapper.readValue(xml, StringBean.class); + assertEquals(stringBean.象形字, stringBean1.象形字); + } } From 491ecb4e7a8147cd646fc4ad18dfaf6380edc09b Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 12 May 2023 01:08:21 +0100 Subject: [PATCH 08/13] wip --- .../jackson/dataformat/xml/XmlMapper.java | 102 +++- .../jackson/dataformat/xml/XmlWriter.java | 466 ++++++++++++++++++ .../dataformat/xml/ser/TestCharset.java | 12 + 3 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index 7256d379e..f5887f1ff 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; +import java.text.DateFormat; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; @@ -14,16 +15,19 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.exc.StreamWriteException; +import com.fasterxml.jackson.core.io.CharacterEscapes; import com.fasterxml.jackson.core.io.DataOutputAsStream; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.cfg.CoercionAction; import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.cfg.ContextAttributes; import com.fasterxml.jackson.databind.cfg.MapperBuilder; import com.fasterxml.jackson.databind.deser.BeanDeserializerFactory; import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; +import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.type.LogicalType; import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser; import com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext; @@ -313,7 +317,7 @@ public void setXmlNameProcessor(XmlNameProcessor processor) { public XmlFactory getFactory() { return (XmlFactory) _jsonFactory; } - + public ObjectMapper configure(ToXmlGenerator.Feature f, boolean state) { ((XmlFactory)_jsonFactory).configure(f, state); return this; @@ -467,6 +471,102 @@ public void writeValue(DataOutput out, Object value, Charset encoding) _writeValueAndClose(createGenerator(out, encoding), value); } + @Override + public ObjectWriter writer() { + return new XmlWriter(super.writer()); + } + + @Override + public ObjectWriter writer(SerializationFeature feature) { + return new XmlWriter(super.writer(feature)); + } + + @Override + public ObjectWriter writer(SerializationFeature first, SerializationFeature... other) { + return new XmlWriter(super.writer(first, other)); + } + + @Override + public ObjectWriter writer(DateFormat df) { + return new XmlWriter(super.writer(df)); + } + + @Override + public ObjectWriter writerWithView(Class serializationView) { + return new XmlWriter(super.writerWithView(serializationView)); + } + + @Override + public ObjectWriter writerFor(Class rootType) { + return new XmlWriter(super.writerFor(rootType)); + } + + @Override + public ObjectWriter writerFor(TypeReference rootType) { + return new XmlWriter(super.writerFor(rootType)); + } + + @Override + public ObjectWriter writerFor(JavaType rootType) { + return new XmlWriter(super.writerFor(rootType)); + } + + @Override + public ObjectWriter writer(PrettyPrinter pp) { + return new XmlWriter(super.writer(pp)); + } + + @Override + public ObjectWriter writerWithDefaultPrettyPrinter() { + return new XmlWriter(super.writerWithDefaultPrettyPrinter()); + } + + @Override + public ObjectWriter writer(FilterProvider filterProvider) { + return new XmlWriter(super.writer(filterProvider)); + } + + @Override + public ObjectWriter writer(FormatSchema schema) { + return new XmlWriter(super.writer(schema)); + } + + @Override + public ObjectWriter writer(Base64Variant defaultBase64) { + return new XmlWriter(super.writer(defaultBase64)); + } + + @Override + public ObjectWriter writer(CharacterEscapes escapes) { + return new XmlWriter(super.writer(escapes)); + } + + @Override + public ObjectWriter writer(ContextAttributes attrs) { + return new XmlWriter(super.writer(attrs)); + } + + /** @deprecated */ + @Override + @Deprecated + public ObjectWriter writerWithType(Class rootType) { + return new XmlWriter(super.writerWithType(rootType)); + } + + /** @deprecated */ + @Override + @Deprecated + public ObjectWriter writerWithType(TypeReference rootType) { + return new XmlWriter(super.writerWithType(rootType)); + } + + /** @deprecated */ + @Override + @Deprecated + public ObjectWriter writerWithType(JavaType rootType) { + return new XmlWriter(super.writerWithType(rootType)); + } + protected final JsonGenerator createGenerator(OutputStream out, Charset encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding); diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java new file mode 100644 index 000000000..09ee62c77 --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java @@ -0,0 +1,466 @@ +package com.fasterxml.jackson.dataformat.xml; + +import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.exc.StreamWriteException; +import com.fasterxml.jackson.core.io.CharacterEscapes; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DatabindException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.PropertyName; +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.cfg.ContextAttributes; +import com.fasterxml.jackson.databind.cfg.DatatypeFeature; +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; +import com.fasterxml.jackson.databind.ser.FilterProvider; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import java.io.DataOutput; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.text.DateFormat; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicReference; + +public final class XmlWriter extends ObjectWriter { + + private final ObjectWriter _objectWriter; + + public XmlWriter(final ObjectWriter objectWriter) { + super(objectWriter, objectWriter.getConfig()); + _objectWriter = objectWriter; + } + + @Override + public Version version() { + return PackageVersion.VERSION; + } + + @Override + public ObjectWriter with(SerializationFeature feature) { + return new XmlWriter(_objectWriter.with(feature)); + } + + @Override + public ObjectWriter with(SerializationFeature first, SerializationFeature... other) { + return new XmlWriter(_objectWriter.with(first, other)); + } + + @Override + public ObjectWriter withFeatures(SerializationFeature... features) { + return new XmlWriter(_objectWriter.withFeatures(features)); + } + + @Override + public ObjectWriter without(SerializationFeature feature) { + return new XmlWriter(_objectWriter.without(feature)); + } + + @Override + public ObjectWriter without(SerializationFeature first, SerializationFeature... other) { + return new XmlWriter(_objectWriter.without(first, other)); + } + + @Override + public ObjectWriter withoutFeatures(SerializationFeature... features) { + return new XmlWriter(_objectWriter.withoutFeatures(features)); + } + + @Override + public ObjectWriter with(DatatypeFeature feature) { + return new XmlWriter(_objectWriter.with(feature)); + } + + @Override + public ObjectWriter withFeatures(DatatypeFeature... features) { + return new XmlWriter(_objectWriter.withFeatures(features)); + } + + @Override + public ObjectWriter without(DatatypeFeature feature) { + return new XmlWriter(_objectWriter.without(feature)); + } + + @Override + public ObjectWriter withoutFeatures(DatatypeFeature... features) { + return new XmlWriter(_objectWriter.withoutFeatures(features)); + } + + @Override + public ObjectWriter with(JsonGenerator.Feature feature) { + return new XmlWriter(_objectWriter.with(feature)); + } + + @Override + public ObjectWriter withFeatures(JsonGenerator.Feature... features) { + return new XmlWriter(_objectWriter.withFeatures(features)); + } + + @Override + public ObjectWriter without(JsonGenerator.Feature feature) { + return new XmlWriter(_objectWriter.without(feature)); + } + + @Override + public ObjectWriter withoutFeatures(JsonGenerator.Feature... features) { + return new XmlWriter(_objectWriter.withoutFeatures(features)); + } + + @Override + public ObjectWriter with(StreamWriteFeature feature) { + return super.with(feature); + } + + @Override + public ObjectWriter without(StreamWriteFeature feature) { + return new XmlWriter(_objectWriter.without(feature)); + } + + @Override + public ObjectWriter with(FormatFeature feature) { + return new XmlWriter(_objectWriter.with(feature)); + } + + @Override + public ObjectWriter withFeatures(FormatFeature... features) { + return new XmlWriter(_objectWriter.withFeatures(features)); + } + + @Override + public ObjectWriter without(FormatFeature feature) { + return new XmlWriter(_objectWriter.without(feature)); + } + + @Override + public ObjectWriter withoutFeatures(FormatFeature... features) { + return new XmlWriter(_objectWriter.withoutFeatures(features)); + } + + @Override + public ObjectWriter forType(JavaType rootType) { + return new XmlWriter(_objectWriter.forType(rootType)); + } + + @Override + public ObjectWriter forType(Class rootType) { + return new XmlWriter(_objectWriter.forType(rootType)); + } + + @Override + public ObjectWriter forType(TypeReference rootType) { + return new XmlWriter(_objectWriter.forType(rootType)); + } + + @Override + public ObjectWriter withType(JavaType rootType) { + return new XmlWriter(_objectWriter.withType(rootType)); + } + + @Override + public ObjectWriter withType(Class rootType) { + return new XmlWriter(_objectWriter.withType(rootType)); + } + + @Override + public ObjectWriter withType(TypeReference rootType) { + return new XmlWriter(_objectWriter.withType(rootType)); + } + + @Override + public ObjectWriter with(DateFormat df) { + return new XmlWriter(_objectWriter.with(df)); + } + + @Override + public ObjectWriter withDefaultPrettyPrinter() { + return new XmlWriter(_objectWriter.withDefaultPrettyPrinter()); + } + + @Override + public ObjectWriter with(FilterProvider filterProvider) { + return new XmlWriter(_objectWriter.with(filterProvider)); + } + + @Override + public ObjectWriter with(PrettyPrinter pp) { + return new XmlWriter(_objectWriter.with(pp)); + } + + @Override + public ObjectWriter withRootName(String rootName) { + return new XmlWriter(_objectWriter.withRootName(rootName)); + } + + @Override + public ObjectWriter withRootName(PropertyName rootName) { + return new XmlWriter(_objectWriter.withRootName(rootName)); + } + + @Override + public ObjectWriter withoutRootName() { + return new XmlWriter(_objectWriter.withoutRootName()); + } + + @Override + public ObjectWriter with(FormatSchema schema) { + return new XmlWriter(_objectWriter.with(schema)); + } + + @Override + public ObjectWriter withSchema(FormatSchema schema) { + return new XmlWriter(_objectWriter.withSchema(schema)); + } + + @Override + public ObjectWriter withView(Class view) { + return new XmlWriter(_objectWriter.withView(view)); + } + + @Override + public ObjectWriter with(Locale l) { + return new XmlWriter(_objectWriter.with(l)); + } + + @Override + public ObjectWriter with(TimeZone tz) { + return new XmlWriter(_objectWriter.with(tz)); + } + + @Override + public ObjectWriter with(Base64Variant b64variant) { + return new XmlWriter(_objectWriter.with(b64variant)); + } + + @Override + public ObjectWriter with(CharacterEscapes escapes) { + return new XmlWriter(_objectWriter.with(escapes)); + } + + @Override + public ObjectWriter with(JsonFactory f) { + return new XmlWriter(_objectWriter.with(f)); + } + + @Override + public ObjectWriter with(ContextAttributes attrs) { + return new XmlWriter(_objectWriter.with(attrs)); + } + + @Override + public ObjectWriter withAttributes(Map attrs) { + return new XmlWriter(_objectWriter.withAttributes(attrs)); + } + + @Override + public ObjectWriter withAttribute(Object key, Object value) { + return new XmlWriter(_objectWriter.withAttribute(key, value)); + } + + @Override + public ObjectWriter withoutAttribute(Object key) { + return new XmlWriter(_objectWriter.withoutAttribute(key)); + } + + @Override + public ObjectWriter withRootValueSeparator(String sep) { + return new XmlWriter(_objectWriter.withRootValueSeparator(sep)); + } + + @Override + public ObjectWriter withRootValueSeparator(SerializableString sep) { + return new XmlWriter(_objectWriter.withRootValueSeparator(sep)); + } + + @Override + public JsonGenerator createGenerator(OutputStream out) throws IOException { + return _objectWriter.createGenerator(out); + } + + @Override + public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { + return _objectWriter.createGenerator(out, enc); + } + + @Override + public JsonGenerator createGenerator(Writer w) throws IOException { + return _objectWriter.createGenerator(w); + } + + @Override + public JsonGenerator createGenerator(File outputFile, JsonEncoding enc) throws IOException { + return _objectWriter.createGenerator(outputFile, enc); + } + + @Override + public JsonGenerator createGenerator(DataOutput out) throws IOException { + return _objectWriter.createGenerator(out); + } + + @Override + public SequenceWriter writeValues(File out) throws IOException { + return _objectWriter.writeValues(out); + } + + @Override + public SequenceWriter writeValues(JsonGenerator g) throws IOException { + return _objectWriter.writeValues(g); + } + + @Override + public SequenceWriter writeValues(Writer out) throws IOException { + return _objectWriter.writeValues(out); + } + + @Override + public SequenceWriter writeValues(OutputStream out) throws IOException { + return _objectWriter.writeValues(out); + } + + @Override + public SequenceWriter writeValues(DataOutput out) throws IOException { + return _objectWriter.writeValues(out); + } + + @Override + public SequenceWriter writeValuesAsArray(File out) throws IOException { + return _objectWriter.writeValuesAsArray(out); + } + + @Override + public SequenceWriter writeValuesAsArray(JsonGenerator gen) throws IOException { + return _objectWriter.writeValuesAsArray(gen); + } + + @Override + public SequenceWriter writeValuesAsArray(Writer out) throws IOException { + return _objectWriter.writeValuesAsArray(out); + } + + @Override + public SequenceWriter writeValuesAsArray(OutputStream out) throws IOException { + return _objectWriter.writeValuesAsArray(out); + } + + @Override + public SequenceWriter writeValuesAsArray(DataOutput out) throws IOException { + return _objectWriter.writeValuesAsArray(out); + } + + @Override + public boolean isEnabled(SerializationFeature f) { + return _objectWriter.isEnabled(f); + } + + @Override + public boolean isEnabled(MapperFeature f) { + return _objectWriter.isEnabled(f); + } + + @Override + public boolean isEnabled(DatatypeFeature f) { + return _objectWriter.isEnabled(f); + } + + @Override + public boolean isEnabled(JsonParser.Feature f) { + return _objectWriter.isEnabled(f); + } + + @Override + public boolean isEnabled(JsonGenerator.Feature f) { + return _objectWriter.isEnabled(f); + } + + @Override + public boolean isEnabled(StreamWriteFeature f) { + return _objectWriter.isEnabled(f); + } + + @Override + public SerializationConfig getConfig() { + return _objectWriter.getConfig(); + } + + @Override + public JsonFactory getFactory() { + return _objectWriter.getFactory(); + } + + @Override + public TypeFactory getTypeFactory() { + return _objectWriter.getTypeFactory(); + } + + @Override + public boolean hasPrefetchedSerializer() { + return _objectWriter.hasPrefetchedSerializer(); + } + + @Override + public ContextAttributes getAttributes() { + return _objectWriter.getAttributes(); + } + + @Override + public void writeValue(JsonGenerator g, Object value) throws IOException { + _objectWriter.writeValue(g, value); + } + + @Override + public void writeValue(File resultFile, Object value) throws IOException, StreamWriteException, DatabindException { + _objectWriter.writeValue(resultFile, value); + } + + @Override + public void writeValue(OutputStream out, Object value) throws IOException, StreamWriteException, DatabindException { + _objectWriter.writeValue(out, value); + } + + @Override + public void writeValue(Writer w, Object value) throws IOException, StreamWriteException, DatabindException { + _objectWriter.writeValue(w, value); + } + + @Override + public void writeValue(DataOutput out, Object value) throws IOException, StreamWriteException, DatabindException { + _objectWriter.writeValue(out, value); + } + + @Override + public String writeValueAsString(Object value) throws JsonProcessingException { + return _objectWriter.writeValueAsString(value); + } + + @Override + public byte[] writeValueAsBytes(Object value) throws JsonProcessingException { + return _objectWriter.writeValueAsBytes(value); + } + + @Override + public void acceptJsonFormatVisitor(JavaType type, JsonFormatVisitorWrapper visitor) throws JsonMappingException { + _objectWriter.acceptJsonFormatVisitor(type, visitor); + } + + @Override + public void acceptJsonFormatVisitor(Class type, JsonFormatVisitorWrapper visitor) throws JsonMappingException { + _objectWriter.acceptJsonFormatVisitor(type, visitor); + } + + @Override + public boolean canSerialize(Class type) { + return _objectWriter.canSerialize(type); + } + + @Override + public boolean canSerialize(Class type, AtomicReference cause) { + return _objectWriter.canSerialize(type, cause); + } +} diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java index 8f5d46a38..e77a8f82b 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java @@ -37,4 +37,16 @@ public void testBig5RoundTrip() throws IOException StringBean stringBean1 = xmlMapper.readValue(xml, StringBean.class); assertEquals(stringBean.象形字, stringBean1.象形字); } + + public void testBig5ObjectWriter() throws IOException + { + Charset big5 = Charset.forName("Big5"); + StringBean stringBean = new StringBean(); + stringBean.象形字 = "pictogram"; + XmlMapper xmlMapper = new XmlMapper(); + xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_1_1, true); + byte[] xml = xmlMapper.writer().writeValueAsBytes(stringBean); + System.out.write(xml); + System.out.println(); + } } From 8ca80992f35790ae65ddcda49195e6bd8ed7eaaa Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 12 May 2023 01:22:44 +0100 Subject: [PATCH 09/13] Update XmlWriter.java --- .../jackson/dataformat/xml/XmlWriter.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java index 09ee62c77..a4555ce67 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java @@ -3,7 +3,10 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.exc.StreamWriteException; import com.fasterxml.jackson.core.io.CharacterEscapes; +import com.fasterxml.jackson.core.io.DataOutputAsStream; +import com.fasterxml.jackson.core.io.SegmentedStringWriter; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.DatabindException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonMappingException; @@ -21,9 +24,11 @@ import java.io.DataOutput; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; +import java.nio.charset.Charset; import java.text.DateFormat; import java.util.Locale; import java.util.Map; @@ -419,11 +424,21 @@ public void writeValue(File resultFile, Object value) throws IOException, Stream _objectWriter.writeValue(resultFile, value); } + public void writeValue(File resultFile, Object value, Charset encoding) + throws IOException, StreamWriteException, DatabindException { + _writeValueAndClose(createGenerator(resultFile, encoding), value); + } + @Override public void writeValue(OutputStream out, Object value) throws IOException, StreamWriteException, DatabindException { _objectWriter.writeValue(out, value); } + public void writeValue(OutputStream out, Object value, Charset encoding) + throws IOException, StreamWriteException, DatabindException { + _writeValueAndClose(createGenerator(out, encoding), value); + } + @Override public void writeValue(Writer w, Object value) throws IOException, StreamWriteException, DatabindException { _objectWriter.writeValue(w, value); @@ -434,6 +449,11 @@ public void writeValue(DataOutput out, Object value) throws IOException, StreamW _objectWriter.writeValue(out, value); } + public void writeValue(DataOutput out, Object value, Charset encoding) + throws IOException, StreamWriteException, DatabindException { + _writeValueAndClose(createGenerator(out, encoding), value); + } + @Override public String writeValueAsString(Object value) throws JsonProcessingException { return _objectWriter.writeValueAsString(value); @@ -444,6 +464,33 @@ public byte[] writeValueAsBytes(Object value) throws JsonProcessingException { return _objectWriter.writeValueAsBytes(value); } + /** + * Method that can be used to serialize any Java value as + * a byte array. Functionally equivalent to calling + * {@link #writeValue(Writer,Object)} with {@link java.io.ByteArrayOutputStream} + * and getting bytes, but more efficient. + * + * @param value value to serialize as XML bytes + * @param encoding character encoding for the XML output + * @return byte array representing the XML output + * @throws JsonProcessingException + */ + public byte[] writeValueAsBytes(Object value, Charset encoding) + throws JsonProcessingException + { + // Although 'close()' is NOP, use auto-close to avoid lgtm complaints + try (ByteArrayBuilder bb = new ByteArrayBuilder(_generatorFactory._getBufferRecycler())) { + _writeValueAndClose(createGenerator(bb, encoding), value); + final byte[] result = bb.toByteArray(); + bb.release(); + return result; + } catch (JsonProcessingException e) { // to support [JACKSON-758] + throw e; + } catch (IOException e) { // shouldn't really happen, but is declared as possibility so: + throw JsonMappingException.fromUnexpectedIOE(e); + } + } + @Override public void acceptJsonFormatVisitor(JavaType type, JsonFormatVisitorWrapper visitor) throws JsonMappingException { _objectWriter.acceptJsonFormatVisitor(type, visitor); @@ -463,4 +510,21 @@ public boolean canSerialize(Class type) { public boolean canSerialize(Class type, AtomicReference cause) { return _objectWriter.canSerialize(type, cause); } + + private JsonGenerator createGenerator(OutputStream out, Charset charset) throws IOException { + _assertNotNull("out", out); + return _configureGenerator(((XmlFactory) _generatorFactory).createGenerator(out, charset)); + } + + private JsonGenerator createGenerator(DataOutput out, Charset charset) throws IOException { + _assertNotNull("out", out); + return _configureGenerator(((XmlFactory) _generatorFactory) + .createGenerator(new DataOutputAsStream(out), charset)); + } + + private JsonGenerator createGenerator(File out, Charset charset) throws IOException { + _assertNotNull("out", out); + return _configureGenerator(((XmlFactory) _generatorFactory) + .createGenerator(new FileOutputStream(out), charset)); + } } From 540be39dfae16e7069d122813f15d9799312dc67 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 12 May 2023 01:28:16 +0100 Subject: [PATCH 10/13] Update XmlWriter.java --- .../jackson/dataformat/xml/XmlWriter.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java index a4555ce67..6c72fa81b 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java @@ -314,6 +314,10 @@ public SequenceWriter writeValues(File out) throws IOException { return _objectWriter.writeValues(out); } + public SequenceWriter writeValues(File out, Charset charset) throws IOException { + return this._newSequenceWriter(false, this.createGenerator(out, charset), true); + } + @Override public SequenceWriter writeValues(JsonGenerator g) throws IOException { return _objectWriter.writeValues(g); @@ -329,16 +333,28 @@ public SequenceWriter writeValues(OutputStream out) throws IOException { return _objectWriter.writeValues(out); } + public SequenceWriter writeValues(OutputStream out, Charset charset) throws IOException { + return this._newSequenceWriter(false, this.createGenerator(out, charset), true); + } + @Override public SequenceWriter writeValues(DataOutput out) throws IOException { return _objectWriter.writeValues(out); } + public SequenceWriter writeValues(DataOutput out, Charset charset) throws IOException { + return this._newSequenceWriter(false, this.createGenerator(out, charset), true); + } + @Override public SequenceWriter writeValuesAsArray(File out) throws IOException { return _objectWriter.writeValuesAsArray(out); } + public SequenceWriter writeValuesAsArray(File out, Charset encoding) throws IOException { + return this._newSequenceWriter(true, createGenerator(out, encoding), true); + } + @Override public SequenceWriter writeValuesAsArray(JsonGenerator gen) throws IOException { return _objectWriter.writeValuesAsArray(gen); @@ -354,11 +370,19 @@ public SequenceWriter writeValuesAsArray(OutputStream out) throws IOException { return _objectWriter.writeValuesAsArray(out); } + public SequenceWriter writeValuesAsArray(OutputStream out, Charset encoding) throws IOException { + return this._newSequenceWriter(true, createGenerator(out, encoding), true); + } + @Override public SequenceWriter writeValuesAsArray(DataOutput out) throws IOException { return _objectWriter.writeValuesAsArray(out); } + public SequenceWriter writeValuesAsArray(DataOutput out, Charset encoding) throws IOException { + return this._newSequenceWriter(true, createGenerator(out, encoding), true); + } + @Override public boolean isEnabled(SerializationFeature f) { return _objectWriter.isEnabled(f); From 9a9414a73ab05a8092e75f742dab3c3518322b0e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 12 May 2023 01:30:26 +0100 Subject: [PATCH 11/13] Update TestCharset.java --- .../com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java index e77a8f82b..ddc2be230 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestCharset.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.XmlTestBase; +import com.fasterxml.jackson.dataformat.xml.XmlWriter; import java.io.IOException; import java.nio.charset.Charset; @@ -45,7 +46,8 @@ public void testBig5ObjectWriter() throws IOException stringBean.象形字 = "pictogram"; XmlMapper xmlMapper = new XmlMapper(); xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_1_1, true); - byte[] xml = xmlMapper.writer().writeValueAsBytes(stringBean); + XmlWriter writer = (XmlWriter) xmlMapper.writer(); + byte[] xml = writer.writeValueAsBytes(stringBean, big5); System.out.write(xml); System.out.println(); } From a4a94005ec5aa4c00724dca97f57cb6307b822dd Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 12 May 2023 01:31:48 +0100 Subject: [PATCH 12/13] Update XmlWriter.java --- .../java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java index 6c72fa81b..111173d9f 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlWriter.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.core.exc.StreamWriteException; import com.fasterxml.jackson.core.io.CharacterEscapes; import com.fasterxml.jackson.core.io.DataOutputAsStream; -import com.fasterxml.jackson.core.io.SegmentedStringWriter; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.DatabindException; From 602e544927ee0d0530d0e670539531256a206b51 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 17 May 2023 19:02:08 +0100 Subject: [PATCH 13/13] add toXmlWriter --- .../com/fasterxml/jackson/dataformat/xml/XmlMapper.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java index f5887f1ff..79d0e61cc 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/XmlMapper.java @@ -567,6 +567,13 @@ public ObjectWriter writerWithType(JavaType rootType) { return new XmlWriter(super.writerWithType(rootType)); } + public static XmlWriter toXmlWriter(final ObjectWriter objectWriter) { + if (objectWriter instanceof XmlWriter) { + return (XmlWriter) objectWriter; + } + return new XmlWriter(objectWriter); + } + protected final JsonGenerator createGenerator(OutputStream out, Charset encoding) throws IOException { this._assertNotNull("out", out); JsonGenerator g = ((XmlFactory) _jsonFactory).createGenerator(out, encoding);