X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-codec-xml%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fcodec%2Fxml%2FXMLStreamNormalizedNodeStreamWriter.java;h=f0b688cd14c20abffa91b42629df9c5321c88e6f;hb=8f3afc2f8e13d71f7e79c5bbea5b21e1c191de70;hp=c290cda100cfcd7dfa19d3820cab7f30e67c6fa9;hpb=855f2c93400f6d288c109797180504e419e5e4f3;p=yangtools.git diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java index c290cda100..f0b688cd14 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamNormalizedNodeStreamWriter.java @@ -7,104 +7,147 @@ */ package org.opendaylight.yangtools.yang.data.codec.xml; -import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; -import com.google.common.base.Strings; +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.ImmutableClassToInstanceMap; +import com.google.common.collect.ImmutableMap; import java.io.IOException; -import java.io.StringWriter; -import java.net.URI; -import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stax.StAXResult; -import javax.xml.transform.stream.StreamResult; import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.YangConstants; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamAttributeWriter; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedAnydata; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriterExtension; +import org.opendaylight.yangtools.yang.data.util.NormalizedNodeInferenceStack; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; +import org.w3c.dom.Node; /** - * A {@link NormalizedNodeStreamWriter} which translates the events into an {@link XMLStreamWriter}, - * resulting in a RFC 6020 XML encoding. There are 2 versions of this class, one that takes a - * SchemaContext and encodes values appropriately according to the yang schema. The other is - * schema-less and merely outputs values using toString. The latter is intended for debugging - * where doesn't have a SchemaContext available and isn't meant for production use. + * A {@link NormalizedNodeStreamWriter} which translates the events into an {@link XMLStreamWriter}, resulting in an + * RFC6020 XML encoding. There are 2 versions of this class, one that takes a SchemaContext and encodes values + * appropriately according to the YANG schema. The other is schema-less and merely outputs values using toString. The + * latter is intended for debugging where doesn't have a SchemaContext available and isn't meant for production use. + * + *

+ * Due to backwards compatibility reasons this writer recognizes RFC7952 metadata include keys QNames with empty URI + * (as exposed via {@link XmlParserStream#LEGACY_ATTRIBUTE_NAMESPACE}) as their QNameModule. These indicate an + * unqualified XML attribute and their value can be assumed to be a String. Furthermore, this extends to qualified + * attributes, which uses the proper namespace, but will not bind to a proper module revision. This caveat will be + * removed in a future version. */ -public abstract class XMLStreamNormalizedNodeStreamWriter implements NormalizedNodeStreamAttributeWriter { +public abstract class XMLStreamNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter, + StreamWriterMetadataExtension { private static final Logger LOG = LoggerFactory.getLogger(XMLStreamNormalizedNodeStreamWriter.class); - private static final String COM_SUN_TRANSFORMER = - "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; - - static final TransformerFactory TRANSFORMER_FACTORY; - - static { - TransformerFactory fa = TransformerFactory.newInstance(); - if (!fa.getFeature(StAXResult.FEATURE)) { - LOG.warn("Platform-default TransformerFactory {} does not support StAXResult, attempting fallback to {}", - fa, COM_SUN_TRANSFORMER); - fa = TransformerFactory.newInstance(COM_SUN_TRANSFORMER, null); - if (!fa.getFeature(StAXResult.FEATURE)) { - throw new TransformerFactoryConfigurationError("No TransformerFactory supporting StAXResult found."); - } - } - - TRANSFORMER_FACTORY = fa; - } - - private static final Set BROKEN_NAMESPACES = ConcurrentHashMap.newKeySet(); + private static final Set BROKEN_ATTRIBUTES = ConcurrentHashMap.newKeySet(); - private final RandomPrefix prefixes; - final XMLStreamWriter writer; + private final @NonNull StreamWriterFacade facade; XMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer) { - this.writer = requireNonNull(writer); - this.prefixes = new RandomPrefix(writer.getNamespaceContext()); + facade = new StreamWriterFacade(writer); } /** * Create a new writer with the specified context as its root. * * @param writer Output {@link XMLStreamWriter} - * @param context Associated {@link SchemaContext}. + * @param context Associated {@link EffectiveModelContext}. * @return A new {@link NormalizedNodeStreamWriter} */ - public static NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context) { - return create(writer, context, SchemaPath.ROOT); + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, + final EffectiveModelContext context) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, + NormalizedNodeInferenceStack.of(context)); + } + + /** + * Create a new writer with the specified context and rooted at the specified node. + * + * @param writer Output {@link XMLStreamWriter} + * @param inference root node inference + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, + final EffectiveStatementInference inference) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, inference.getEffectiveModelContext(), + NormalizedNodeInferenceStack.of(inference)); } /** * Create a new writer with the specified context and rooted in the specified schema path. * * @param writer Output {@link XMLStreamWriter} - * @param context Associated {@link SchemaContext}. + * @param context Associated {@link EffectiveModelContext}. * @param path path + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, + final EffectiveModelContext context, final SchemaPath path) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, + NormalizedNodeInferenceStack.of(context, path)); + } + + /** + * Create a new writer with the specified context and rooted in the specified schema path. * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link EffectiveModelContext}. + * @param path path * @return A new {@link NormalizedNodeStreamWriter} */ - public static NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context, - final SchemaPath path) { - return SchemaAwareXMLStreamNormalizedNodeStreamWriter.newInstance(writer, context, path); + public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute path) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, + NormalizedNodeInferenceStack.of(context, path)); + } + + /** + * Create a new writer with the specified context and rooted in the specified operation's input. + * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link EffectiveModelContext}. + * @param operationPath Parent operation (RPC or action) path. + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter forInputOf(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute operationPath) { + return forOperation(writer, context, operationPath, + YangConstants.operationInputQName(operationPath.lastNodeIdentifier().getModule())); + } + + /** + * Create a new writer with the specified context and rooted in the specified operation's output. + * + * @param writer Output {@link XMLStreamWriter} + * @param context Associated {@link EffectiveModelContext}. + * @param operationPath Parent operation (RPC or action) path. + * @return A new {@link NormalizedNodeStreamWriter} + */ + public static @NonNull NormalizedNodeStreamWriter forOutputOf(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute operationPath) { + return forOperation(writer, context, operationPath, + YangConstants.operationOutputQName(operationPath.lastNodeIdentifier().getModule())); + } + + private static @NonNull NormalizedNodeStreamWriter forOperation(final XMLStreamWriter writer, + final EffectiveModelContext context, final Absolute operationPath, final QName qname) { + return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, + NormalizedNodeInferenceStack.ofOperation(context, operationPath, qname)); } /** @@ -115,125 +158,78 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz * * @return A new {@link NormalizedNodeStreamWriter} */ - public static NormalizedNodeStreamWriter createSchemaless(final XMLStreamWriter writer) { - return SchemalessXMLStreamNormalizedNodeStreamWriter.newInstance(writer); + public static @NonNull NormalizedNodeStreamWriter createSchemaless(final XMLStreamWriter writer) { + return new SchemalessXMLStreamNormalizedNodeStreamWriter(writer); } - abstract void writeValue(XMLStreamWriter xmlWriter, QName qname, @NonNull Object value, T context) - throws IOException, XMLStreamException; + @Override + public final ClassToInstanceMap getExtensions() { + return ImmutableClassToInstanceMap.of(StreamWriterMetadataExtension.class, this); + } + + abstract void startAnydata(NodeIdentifier name); abstract void startList(NodeIdentifier name); abstract void startListItem(PathArgument name) throws IOException; - private void writeAttributes(final @NonNull Map attributes) throws IOException { - for (final Entry entry : attributes.entrySet()) { - try { - final QName qname = entry.getKey(); - final String namespace = qname.getNamespace().toString(); - - if (!Strings.isNullOrEmpty(namespace)) { - final String prefix = getPrefix(qname.getNamespace(), namespace); - writer.writeAttribute(prefix, namespace, qname.getLocalName(), entry.getValue()); - } else { - writer.writeAttribute(qname.getLocalName(), entry.getValue()); - } - } catch (final XMLStreamException e) { - throw new IOException("Unable to emit attribute " + entry, e); - } - } - } + abstract String encodeAnnotationValue(@NonNull ValueWriter xmlWriter, @NonNull QName qname, @NonNull Object value) + throws XMLStreamException; - private String getPrefix(final URI uri, final String str) throws XMLStreamException { - final String prefix = writer.getPrefix(str); - if (prefix != null) { - return prefix; - } + abstract String encodeValue(@NonNull ValueWriter xmlWriter, @NonNull Object value, T context) + throws XMLStreamException; - // This is needed to recover from attributes emitted while the namespace was not declared. Ordinarily - // attribute namespaces would be bound in the writer, so the resulting XML is efficient, but we cannot rely - // on that having been done. - if (BROKEN_NAMESPACES.add(str)) { - LOG.info("Namespace {} was not bound, please fix the caller", str, new Throwable()); - } - - return prefixes.encodePrefix(uri); - } - - private void writeStartElement(final QName qname) throws XMLStreamException { - String ns = qname.getNamespace().toString(); - writer.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, qname.getLocalName(), ns); - if (writer.getNamespaceContext() != null) { - String parentNs = writer.getNamespaceContext().getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX); - if (!ns.equals(parentNs)) { - writer.writeDefaultNamespace(ns); - } + final void writeValue(final @NonNull Object value, final T context) throws IOException { + try { + facade.writeCharacters(encodeValue(facade, value, context)); + } catch (XMLStreamException e) { + throw new IOException("Failed to write value", e); } } - void writeElement(final QName qname, final Object value, final @Nullable Map attributes, - final T context) throws IOException { + final void startElement(final QName qname) throws IOException { try { - writeStartElement(qname); - if (attributes != null) { - writeAttributes(attributes); - } - if (value != null) { - writeValue(writer, qname, value, context); - } - writer.writeEndElement(); + facade.writeStartElement(qname); } catch (XMLStreamException e) { - throw new IOException("Failed to emit element", e); + throw new IOException("Failed to start element", e); } } - void startElement(final QName qname) throws IOException { + final void endElement() throws IOException { try { - writeStartElement(qname); + facade.writeEndElement(); } catch (XMLStreamException e) { - throw new IOException("Failed to start element", e); + throw new IOException("Failed to end element", e); } } - void anyxmlNode(final QName qname, final Object value) throws IOException { - if (value != null) { - checkArgument(value instanceof DOMSource, "AnyXML value must be DOMSource, not %s", value); - final DOMSource domSource = (DOMSource) value; - requireNonNull(domSource.getNode()); - checkArgument(domSource.getNode().getNodeName().equals(qname.getLocalName())); - checkArgument(domSource.getNode().getNamespaceURI().equals(qname.getNamespace().toString())); + final void anydataValue(final Object value) throws IOException { + if (value instanceof DOMSourceAnydata) { try { - // TODO can the transformer be a constant ? is it thread safe ? - final Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); - // Writer has to be wrapped in a wrapper that ignores endDocument event - // EndDocument event forbids any other modification to the writer so a nested anyXml breaks - // serialization - transformer.transform(domSource, new StAXResult(new DelegateWriterNoEndDoc(writer))); - } catch (final TransformerException e) { - throw new IOException("Unable to transform anyXml(" + qname + ") value: " + value, e); + facade.anydataWriteStreamReader(((DOMSourceAnydata) value).toStreamReader()); + } catch (XMLStreamException e) { + throw new IOException("Unable to transform anydata value: " + value, e); } + } else if (value instanceof NormalizedAnydata) { + try { + facade.emitNormalizedAnydata((NormalizedAnydata) value); + } catch (XMLStreamException e) { + throw new IOException("Unable to emit anydata value: " + value, e); + } + } else { + throw new IllegalStateException("Unexpected anydata value " + value); } } - @Override - public final void startContainerNode(final NodeIdentifier name, final int childSizeHint, - final Map attributes) throws IOException { - startContainerNode(name, childSizeHint); - writeAttributes(attributes); - } - - @Override - public final void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint, - final Map attributes) throws IOException { - startYangModeledAnyXmlNode(name, childSizeHint); - writeAttributes(attributes); - } - - @Override - public final void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint, - final Map attributes) throws IOException { - startUnkeyedListItem(name, childSizeHint); - writeAttributes(attributes); + final void anyxmlValue(final DOMSource domSource) throws IOException { + if (domSource != null) { + final Node domNode = requireNonNull(domSource.getNode()); + try { + facade.anyxmlWriteStreamReader(new DOMSourceXMLStreamReader(domSource)); + } catch (XMLStreamException e) { + throw new IOException("Unable to transform anyXml value: " + domNode, e); + } + } } @Override @@ -241,13 +237,6 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz startListItem(name); } - @Override - public final void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint, - final Map attributes) throws IOException { - startMapEntryNode(identifier, childSizeHint); - writeAttributes(attributes); - } - @Override public final void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) throws IOException { @@ -269,36 +258,10 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz startList(name); } - public static String toString(final Element xml) { - try { - final Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - - final StreamResult result = new StreamResult(new StringWriter()); - final DOMSource source = new DOMSource(xml); - transformer.transform(source, result); - - return result.getWriter().toString(); - } catch (IllegalArgumentException | TransformerException e) { - throw new IllegalStateException("Unable to serialize xml element " + xml, e); - } - } - - abstract void endNode(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException; - - @Override - public final void endNode() throws IOException { - try { - endNode(writer); - } catch (XMLStreamException e) { - throw new IOException("Failed to end element", e); - } - } - @Override public final void close() throws IOException { try { - writer.close(); + facade.close(); } catch (XMLStreamException e) { throw new IOException("Failed to close writer", e); } @@ -307,192 +270,55 @@ public abstract class XMLStreamNormalizedNodeStreamWriter implements Normaliz @Override public final void flush() throws IOException { try { - writer.flush(); + facade.flush(); } catch (XMLStreamException e) { throw new IOException("Failed to flush writer", e); } } - /** - * Delegate writer that ignores writeEndDocument event. Used for AnyXml serialization. - */ - private static final class DelegateWriterNoEndDoc implements XMLStreamWriter { - private final XMLStreamWriter writer; - - DelegateWriterNoEndDoc(final XMLStreamWriter writer) { - this.writer = writer; - } - - @Override - public void writeStartElement(final String localName) throws XMLStreamException { - writer.writeStartElement(localName); - } - - @Override - public void writeStartElement(final String namespaceURI, final String localName) throws XMLStreamException { - writer.writeStartElement(namespaceURI, localName); - } - - @Override - public void writeStartElement(final String prefix, final String localName, final String namespaceURI) - throws XMLStreamException { - writer.writeStartElement(prefix, localName, namespaceURI); - } - - @Override - public void writeEmptyElement(final String namespaceURI, final String localName) throws XMLStreamException { - writer.writeEmptyElement(namespaceURI, localName); - } - - @Override - public void writeEmptyElement(final String prefix, final String localName, final String namespaceURI) - throws XMLStreamException { - writer.writeEmptyElement(prefix, localName, namespaceURI); - } - - @Override - public void writeEmptyElement(final String localName) throws XMLStreamException { - writer.writeEmptyElement(localName); - } - - @Override - public void writeEndElement() throws XMLStreamException { - writer.writeEndElement(); - - } - - @Override - public void writeEndDocument() throws XMLStreamException { - // End document is disabled - } - - @Override - public void close() throws XMLStreamException { - writer.close(); - } - - @Override - public void flush() throws XMLStreamException { - writer.flush(); - } - - @Override - public void writeAttribute(final String localName, final String value) throws XMLStreamException { - writer.writeAttribute(localName, value); - } - - @Override - public void writeAttribute(final String prefix, final String namespaceURI, final String localName, - final String value) throws XMLStreamException { - writer.writeAttribute(prefix, namespaceURI, localName, value); - } - - @Override - public void writeAttribute(final String namespaceURI, final String localName, final String value) - throws XMLStreamException { - writer.writeAttribute(namespaceURI, localName, value); - } - - @Override - public void writeNamespace(final String prefix, final String namespaceURI) throws XMLStreamException { - // Workaround for default namespace - // If a namespace is not prefixed, it is is still treated as prefix namespace. - // This results in the NamespaceSupport class ignoring the namespace since xmlns is not a valid prefix - // Write the namespace at least as an attribute - // TODO this is a hotfix, the transformer itself should write namespaces passing the namespace - // in writeStartElement method - if (prefix.equals("xml") || prefix.equals("xmlns")) { - writer.writeAttribute(prefix, namespaceURI); - } else { - writer.writeNamespace(prefix, namespaceURI); + @Override + public final void metadata(final ImmutableMap attributes) throws IOException { + for (final Entry entry : attributes.entrySet()) { + final QName qname = entry.getKey(); + final String namespace = qname.getNamespace().toString(); + final String localName = qname.getLocalName(); + final Object value = entry.getValue(); + + // FIXME: remove this handling once we have complete mapping to metadata + try { + if (namespace.isEmpty()) { + // Legacy attribute, which is expected to be a String + StreamWriterFacade.warnLegacyAttribute(localName); + if (!(value instanceof String)) { + if (BROKEN_ATTRIBUTES.add(localName)) { + LOG.warn("Unbound annotation {} does not have a String value, ignoring it. Please fix the " + + "source of this annotation either by formatting it to a String or removing its " + + "use", localName, new Throwable("Call stack")); + } + LOG.debug("Ignoring annotation {} value {}", localName, value); + } else { + facade.writeAttribute(localName, (String) value); + continue; + } + } else { + final String prefix = facade.getPrefix(qname.getNamespace(), namespace); + final String attrValue = encodeAnnotationValue(facade, qname, value); + facade.writeAttribute(prefix, namespace, localName, attrValue); + } + } catch (final XMLStreamException e) { + throw new IOException("Unable to emit attribute " + qname, e); } } + } - @Override - public void writeDefaultNamespace(final String namespaceURI) throws XMLStreamException { - writer.writeDefaultNamespace(namespaceURI); - } - - @Override - public void writeComment(final String data) throws XMLStreamException { - writer.writeComment(data); - } - - @Override - public void writeProcessingInstruction(final String target) throws XMLStreamException { - writer.writeProcessingInstruction(target); - } - - @Override - public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException { - writer.writeProcessingInstruction(target, data); - } - - @Override - public void writeCData(final String data) throws XMLStreamException { - writer.writeCData(data); - } - - @Override - public void writeDTD(final String dtd) throws XMLStreamException { - writer.writeDTD(dtd); - } - - @Override - public void writeEntityRef(final String name) throws XMLStreamException { - writer.writeEntityRef(name); - } - - @Override - public void writeStartDocument() throws XMLStreamException { - } - - @Override - public void writeStartDocument(final String version) throws XMLStreamException { - } - - @Override - public void writeStartDocument(final String encoding, final String version) throws XMLStreamException { - } - - @Override - public void writeCharacters(final String text) throws XMLStreamException { - writer.writeCharacters(text); - } - - @Override - public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException { - writer.writeCharacters(text, start, len); - } - - @Override - public String getPrefix(final String uri) throws XMLStreamException { - return writer.getPrefix(uri); - } - - @Override - public void setPrefix(final String prefix, final String uri) throws XMLStreamException { - // Disabled since it causes exceptions in the underlying writer - } - - @Override - public void setDefaultNamespace(final String uri) throws XMLStreamException { - writer.setDefaultNamespace(uri); - } - - @Override - public void setNamespaceContext(final NamespaceContext context) throws XMLStreamException { - writer.setNamespaceContext(context); - } - - @Override - public NamespaceContext getNamespaceContext() { - return writer.getNamespaceContext(); - } - - @Override - public Object getProperty(final String name) { - return writer.getProperty(name); - } + @Override + public final boolean startAnydataNode(final NodeIdentifier name, final Class objectModel) throws IOException { + if (DOMSourceAnydata.class.isAssignableFrom(objectModel) + || NormalizedAnydata.class.isAssignableFrom(objectModel)) { + startAnydata(name); + startElement(name.getNodeType()); + return true; + } + return false; } }