Skip to content

Commit

Permalink
Use XML Transformer for xml serialization to fix missing default name…
Browse files Browse the repository at this point in the history
…space when serializing xml
  • Loading branch information
magott committed Jun 10, 2021
1 parent 71385d1 commit c50aa80
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fasterxml.jackson.databind.ext;

import java.io.IOException;
import java.io.StringWriter;

import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
Expand All @@ -15,29 +16,41 @@
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
@SuppressWarnings("serial")
public class DOMSerializer extends StdSerializer<Node>
{
protected final DOMImplementationLS _domImpl;

private final TransformerFactory transformerFactory;

public DOMSerializer() {
super(Node.class);
DOMImplementationRegistry registry;
try {
registry = DOMImplementationRegistry.newInstance();
transformerFactory = TransformerFactory.newInstance();
} catch (Exception e) {
throw new IllegalStateException("Could not instantiate DOMImplementationRegistry: "+e.getMessage(), e);
throw new IllegalStateException("Could not instantiate TransformerFactory: "+e.getMessage(), e);
}
_domImpl = (DOMImplementationLS)registry.getDOMImplementation("LS");
}

@Override
public void serialize(Node value, JsonGenerator jgen, SerializerProvider provider)
throws IOException
{
if (_domImpl == null) throw new IllegalStateException("Could not find DOM LS");
LSSerializer writer = _domImpl.createLSSerializer();
jgen.writeString(writer.writeToString(value));
try {
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(value);
transformer.transform(source, result);
jgen.writeString(result.getWriter().toString());
} catch (TransformerConfigurationException e) {
throw new IllegalStateException("Could not create XML Transformer: "+e.getMessage(), e);
} catch (TransformerException e) {
throw new IOException("XML Transformation failed: "+e.getMessage(), e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class DOMTypeReadWriteTest extends com.fasterxml.jackson.databind.BaseMap
"<root attr='3'><leaf>Rock &amp; Roll!</leaf><?proc instr?></root>";
final static String SIMPLE_XML_NS =
"<root ns:attr='abc' xmlns:ns='http://foo' />";
final static String SIMPLE_XML_DEFAULT_NS =
"<root xmlns='http://foo'/>";

private final ObjectMapper MAPPER = new ObjectMapper();

Expand All @@ -33,6 +35,22 @@ public void testSerializeSimpleNonNS() throws Exception
assertEquals(SIMPLE_XML, normalizeOutput(output));
}

public void testSerializeSimpleDefaultNS() throws Exception
{
// Let's just parse first, easiest
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse
(new InputSource(new StringReader(SIMPLE_XML_DEFAULT_NS)));
assertNotNull(doc);
// need to strip xml declaration, if any
String outputRaw = MAPPER.writeValueAsString(doc);
// And re-parse as String, since JSON has quotes...
String output = MAPPER.readValue(outputRaw, String.class);
/* ... and finally, normalize to (close to) canonical XML
* output (single vs double quotes, xml declaration etc)
*/
assertEquals(SIMPLE_XML_DEFAULT_NS, normalizeOutput(output));
}

public void testDeserializeNonNS() throws Exception
{
for (int i = 0; i < 2; ++i) {
Expand Down

0 comments on commit c50aa80

Please sign in to comment.