1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.io.xml;
7
8 import com.ctc.wstx.api.WstxOutputProperties;
9 import com.ctc.wstx.stax.WstxOutputFactory;
10
11 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
12 import gov.nist.secauto.metaschema.core.model.IBoundObject;
13 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
14 import gov.nist.secauto.metaschema.databind.io.AbstractSerializer;
15 import gov.nist.secauto.metaschema.databind.io.SerializationFeature;
16 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
17
18 import org.codehaus.stax2.XMLOutputFactory2;
19 import org.codehaus.stax2.XMLStreamWriter2;
20
21 import java.io.IOException;
22 import java.io.Writer;
23
24 import javax.xml.stream.XMLOutputFactory;
25 import javax.xml.stream.XMLStreamException;
26
27 import edu.umd.cs.findbugs.annotations.NonNull;
28 import nl.talsmasoftware.lazy4j.Lazy;
29
30 public class DefaultXmlSerializer<CLASS extends IBoundObject>
31 extends AbstractSerializer<CLASS> {
32 private Lazy<XMLOutputFactory2> factory;
33
34
35
36
37
38
39
40
41
42 public DefaultXmlSerializer(@NonNull IBoundDefinitionModelAssembly definition) {
43 super(definition);
44 resetFactory();
45 }
46
47 protected final void resetFactory() {
48 this.factory = Lazy.lazy(this::newFactoryInstance);
49 }
50
51 @Override
52 protected void configurationChanged(IMutableConfiguration<SerializationFeature<?>> config) {
53 super.configurationChanged(config);
54 resetFactory();
55 }
56
57
58
59
60
61
62
63
64
65 @NonNull
66 protected XMLOutputFactory2 newFactoryInstance() {
67 XMLOutputFactory2 retval = (XMLOutputFactory2) XMLOutputFactory.newInstance();
68 assert retval instanceof WstxOutputFactory;
69 retval.configureForSpeed();
70 retval.setProperty(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
71 retval.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
72 return retval;
73 }
74
75
76
77
78
79
80
81 @NonNull
82 protected final XMLOutputFactory2 getXMLOutputFactory() {
83 return ObjectUtils.notNull(factory.get());
84 }
85
86
87
88
89
90
91
92
93
94
95 @NonNull
96 protected final XMLStreamWriter2 newXMLStreamWriter(@NonNull Writer writer) throws IOException {
97 try {
98 return ObjectUtils.notNull((XMLStreamWriter2) getXMLOutputFactory().createXMLStreamWriter(writer));
99 } catch (XMLStreamException ex) {
100 throw new IOException(ex);
101 }
102 }
103
104 @Override
105 public void serialize(IBoundObject data, Writer writer) throws IOException {
106 XMLStreamWriter2 streamWriter = newXMLStreamWriter(writer);
107 IOException caughtException = null;
108 IBoundDefinitionModelAssembly definition = getDefinition();
109
110 MetaschemaXmlWriter xmlGenerator = new MetaschemaXmlWriter(streamWriter);
111
112 boolean serializeRoot = get(SerializationFeature.SERIALIZE_ROOT);
113 try {
114 if (serializeRoot) {
115 streamWriter.writeStartDocument("UTF-8", "1.0");
116 xmlGenerator.writeRoot(definition, data);
117 } else {
118 xmlGenerator.write(definition, data);
119 }
120
121 streamWriter.flush();
122
123 if (serializeRoot) {
124 streamWriter.writeEndDocument();
125 }
126 } catch (XMLStreamException ex) {
127 caughtException = new IOException(ex);
128 throw caughtException;
129 } finally {
130 try {
131 streamWriter.close();
132 } catch (XMLStreamException ex) {
133 if (caughtException == null) {
134 throw new IOException(ex);
135 }
136 caughtException.addSuppressed(ex);
137 throw caughtException;
138 }
139 }
140 }
141 }