diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index 6cc95f5ff643..a8d752c26707 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -461,6 +461,8 @@ com.azure.tools:azure-sdk-build-tool;1.0.0;1.1.0-beta.1 # In the pom, the version update tag after the version should name the unreleased package and the dependency version: # +unreleased_com.azure:azure-xml;1.0.0-beta.4 +unreleased_com.azure:azure-core;1.48.0-beta.1 # Released Beta dependencies: Copy the entry from above, prepend "beta_", remove the current # version and set the version to the released beta. Released beta dependencies are only valid diff --git a/sdk/core/azure-core-experimental/pom.xml b/sdk/core/azure-core-experimental/pom.xml index 63d4366496fe..b6167dc5caad 100644 --- a/sdk/core/azure-core-experimental/pom.xml +++ b/sdk/core/azure-core-experimental/pom.xml @@ -91,7 +91,7 @@ com.azure azure-xml - 1.0.0-beta.3 + 1.0.0-beta.4 test diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ReflectionSerializable.java b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ReflectionSerializable.java index fb08375e0630..850161f2a87e 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ReflectionSerializable.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ReflectionSerializable.java @@ -58,17 +58,23 @@ public final class ReflectionSerializable { try { xmlSerializable = Class.forName("com.azure.xml.XmlSerializable"); xmlReader = Class.forName("com.azure.xml.XmlReader"); - - Class xmlProviders = Class.forName("com.azure.xml.XmlProviders"); - - xmlReaderCreator = ReflectionUtils.getMethodInvoker(xmlProviders, - xmlProviders.getDeclaredMethod("createReader", byte[].class)); - - xmlWriterCreator = ReflectionUtils.getMethodInvoker(xmlProviders, - xmlProviders.getDeclaredMethod("createWriter", OutputStream.class)); - Class xmlWriter = Class.forName("com.azure.xml.XmlWriter"); + try { + Class xmlProviders = Class.forName("com.azure.xml.XmlProviders"); + + xmlReaderCreator = ReflectionUtils.getMethodInvoker(xmlProviders, + xmlProviders.getDeclaredMethod("createReader", byte[].class)); + + xmlWriterCreator = ReflectionUtils.getMethodInvoker(xmlProviders, + xmlProviders.getDeclaredMethod("createWriter", OutputStream.class)); + } catch (LinkageError | ReflectiveOperationException ex) { + xmlReaderCreator = ReflectionUtils.getMethodInvoker(xmlReader, + xmlReader.getDeclaredMethod("fromBytes", byte[].class)); + xmlWriterCreator = ReflectionUtils.getMethodInvoker(xmlWriter, + xmlWriter.getDeclaredMethod("toStream", OutputStream.class)); + } + xmlWriterWriteStartDocument = ReflectionUtils.getMethodInvoker(xmlWriter, xmlWriter.getDeclaredMethod("writeStartDocument")); diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonProvider.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonProvider.java index db5a115fbccb..42043ef667df 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonProvider.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonProvider.java @@ -19,10 +19,10 @@ */ public final class DefaultJsonProvider implements JsonProvider { private static final String JSON_READER_EXCEPTION - = "Both 'json' and 'options' must be passed as non-null to " + "create an instance of JsonReader."; + = "Both 'json' and 'options' must be passed as non-null to create an instance of JsonReader."; private static final String JSON_WRITER_EXCEPTION - = "Both 'json' and 'options' must be passed as non-null to " + "create an instance of JsonWriter."; + = "Both 'json' and 'options' must be passed as non-null to create an instance of JsonWriter."; @Override public JsonReader createReader(byte[] json, JsonOptions options) throws IOException { diff --git a/sdk/serialization/azure-xml/spotbugs-exclude.xml b/sdk/serialization/azure-xml/spotbugs-exclude.xml index da8e297c72ef..e6c43c2c787e 100644 --- a/sdk/serialization/azure-xml/spotbugs-exclude.xml +++ b/sdk/serialization/azure-xml/spotbugs-exclude.xml @@ -4,6 +4,6 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd"> - + diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlProvider.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlProvider.java deleted file mode 100644 index 2ac963aba598..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlProvider.java +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.xml; - -import javax.xml.stream.XMLStreamException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; - -/** - * An interface to be implemented by any azure-xml plugin that wishes to provide an alternate {@link XmlReader} or - * {@link XmlWriter} implementation. - */ -public interface XmlProvider { - /** - * Creates an instance of {@link XmlReader} that reads a {@code byte[]}. - * - * @param json The JSON represented as a {@code byte[]}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code json} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - XmlReader createReader(byte[] json) throws XMLStreamException; - - /** - * Creates an instance of {@link XmlReader} that reads a {@link String}. - * - * @param json The JSON represented as a {@link String}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code json} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - XmlReader createReader(String json) throws XMLStreamException; - - /** - * Creates an instance of {@link XmlReader} that reads a {@link InputStream}. - * - * @param json The JSON represented as a {@link InputStream}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code json} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - XmlReader createReader(InputStream json) throws XMLStreamException; - - /** - * Creates an instance of {@link XmlReader} that reads a {@link Reader}. - * - * @param json The JSON represented as a {@link Reader}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code json} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - XmlReader createReader(Reader json) throws XMLStreamException; - - /** - * Creates an instance of {@link XmlWriter} that writes to an {@link OutputStream}. - * - * @param json The JSON represented as an {@link OutputStream}. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code json} is null. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - XmlWriter createWriter(OutputStream json) throws XMLStreamException; - - /** - * Creates an instance of {@link XmlWriter} that writes to an {@link Writer}. - * - * @param json The JSON represented as an {@link Writer}. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code json} is null. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - XmlWriter createWriter(Writer json) throws XMLStreamException; -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlProviders.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlProviders.java deleted file mode 100644 index 29c98ed58bc1..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlProviders.java +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.xml; - -import com.azure.xml.implementation.DefaultXmlReader; -import com.azure.xml.implementation.DefaultXmlWriter; - -import javax.xml.stream.XMLStreamException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Handles loading an instance of {@link XmlProvider} found on the classpath. - */ -public final class XmlProviders { - private static final String CANNOT_FIND_XML = "A request was made to load an XmlReader and XmlWriter provider " - + "but one could not be found on the classpath. If you are using a dependency manager, consider including a " - + "dependency that supplies a provider for XmlProvider or indicate to the loader to fallback to the default " - + "implementation. Additionally, refer to https://aka.ms/azsdk/java/docs/custom-xml to learn about writing " - + "your own implementation."; - - private static XmlProvider defaultProvider; - - static { - // Use as classloader to load provider-configuration files and provider classes the classloader - // that loaded this class. In most cases this will be the System classloader. - // But this choice here provides additional flexibility in managed environments that control - // classloading differently (OSGi, Spring and others) and don't depend on the - // System classloader to load HttpClientProvider classes. - ServiceLoader serviceLoader - = ServiceLoader.load(XmlProvider.class, XmlProvider.class.getClassLoader()); - // Use the first provider found in the service loader iterator. - Iterator it = serviceLoader.iterator(); - if (it.hasNext()) { - defaultProvider = it.next(); - } - - while (it.hasNext()) { - it.next(); - } - } - - private XmlProviders() { - // no-op - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@code byte[]}. - *

- * If a provider could not be found on the classpath this will use the default implementation, effectively the - * equivalent to {@link #createReader(byte[], boolean) createReader(xml, true)}. - * - * @param xml The XML represented as a {@code byte[]}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(byte[] xml) throws XMLStreamException { - return createReader(xml, true); - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@code byte[]}. - * - * @param xml The XML represented as a {@code byte[]}. - * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(byte[] xml, boolean useDefault) throws XMLStreamException { - if (defaultProvider == null) { - if (useDefault) { - return DefaultXmlReader.fromBytes(xml); - } else { - throw new IllegalStateException(CANNOT_FIND_XML); - } - } else { - return defaultProvider.createReader(xml); - } - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@link String}. - *

- * If a provider could not be found on the classpath this will use the default implementation, effectively the - * equivalent to {@link #createReader(String, boolean) createReader(xml, true)}. - * - * @param xml The XML represented as a {@link String}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(String xml) throws XMLStreamException { - return createReader(xml, true); - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@link String}. - * - * @param xml The XML represented as a {@link String}. - * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(String xml, boolean useDefault) throws XMLStreamException { - if (defaultProvider == null) { - if (useDefault) { - return DefaultXmlReader.fromString(xml); - } else { - throw new IllegalStateException(CANNOT_FIND_XML); - } - } else { - return defaultProvider.createReader(xml); - } - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@link InputStream}. - *

- * If a provider could not be found on the classpath this will use the default implementation, effectively the - * equivalent to {@link #createReader(InputStream, boolean) createReader(xml, true)}. - * - * @param xml The XML represented as a {@link InputStream}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(InputStream xml) throws XMLStreamException { - return createReader(xml, true); - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@link InputStream}. - * - * @param xml The XML represented as a {@link InputStream}. - * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(InputStream xml, boolean useDefault) throws XMLStreamException { - if (defaultProvider == null) { - if (useDefault) { - return DefaultXmlReader.fromStream(xml); - } else { - throw new IllegalStateException(CANNOT_FIND_XML); - } - } else { - return defaultProvider.createReader(xml); - } - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@link Reader}. - *

- * If a provider could not be found on the classpath this will use the default implementation, effectively the - * equivalent to {@link #createReader(Reader, boolean) createReader(xml, true)}. - * - * @param xml The XML represented as a {@link Reader}. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(Reader xml) throws XMLStreamException { - return createReader(xml, true); - } - - /** - * Creates an instance of {@link XmlReader} that reads a {@link Reader}. - * - * @param xml The XML represented as a {@link Reader}. - * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. - * @return A new instance of {@link XmlReader}. - * @throws NullPointerException If {@code xml} is null. - * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader createReader(Reader xml, boolean useDefault) throws XMLStreamException { - if (defaultProvider == null) { - if (useDefault) { - return DefaultXmlReader.fromReader(xml); - } else { - throw new IllegalStateException(CANNOT_FIND_XML); - } - } else { - return defaultProvider.createReader(xml); - } - } - - /** - * Creates an instance of {@link XmlWriter} that writes to an {@link OutputStream}. - *

- * If a provider could not be found on the classpath this will use the default implementation, effectively the - * equivalent to {@link #createWriter(OutputStream, boolean) createWriter(xml, true)}. - * - * @param xml The XML represented as an {@link OutputStream}. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - public static XmlWriter createWriter(OutputStream xml) throws XMLStreamException { - return createWriter(xml, true); - } - - /** - * Creates an instance of {@link XmlWriter} that writes to an {@link OutputStream}. - * - * @param xml The XML represented as an {@link OutputStream}. - * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code xml} is null. - * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - public static XmlWriter createWriter(OutputStream xml, boolean useDefault) throws XMLStreamException { - if (defaultProvider == null) { - if (useDefault) { - return DefaultXmlWriter.toStream(xml); - } else { - throw new IllegalStateException(CANNOT_FIND_XML); - } - } else { - return defaultProvider.createWriter(xml); - } - } - - /** - * Creates an instance of {@link XmlWriter} that writes to an {@link Writer}. - *

- * If a provider could not be found on the classpath this will use the default implementation, effectively the - * equivalent to {@link #createWriter(Writer, boolean) createWriter(xml, true)}. - * - * @param xml The XML represented as an {@link Writer}. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - public static XmlWriter createWriter(Writer xml) throws XMLStreamException { - return createWriter(xml, true); - } - - /** - * Creates an instance of {@link XmlWriter} that writes to an {@link Writer}. - * - * @param xml The XML represented as an {@link Writer}. - * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code xml} is null. - * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - public static XmlWriter createWriter(Writer xml, boolean useDefault) throws XMLStreamException { - if (defaultProvider == null) { - if (useDefault) { - return DefaultXmlWriter.toWriter(xml); - } else { - throw new IllegalStateException(CANNOT_FIND_XML); - } - } else { - return defaultProvider.createWriter(xml); - } - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlReader.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlReader.java index 929e00266ec0..247bd898577d 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlReader.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlReader.java @@ -4,19 +4,121 @@ package com.azure.xml; import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; import java.util.Base64; import java.util.Objects; /** * Reads an XML encoded value as a stream of tokens. */ -public abstract class XmlReader implements AutoCloseable { +public final class XmlReader implements AutoCloseable { + private static final XMLInputFactory XML_INPUT_FACTORY; + + static { + XML_INPUT_FACTORY = XMLInputFactory.newInstance(); + XML_INPUT_FACTORY.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); + XML_INPUT_FACTORY.setProperty(XMLInputFactory.SUPPORT_DTD, false); + } + + private final XMLStreamReader reader; + + private XmlToken currentToken; + + /** + * Creates an {@link XMLStreamReader}-based {@link XmlReader} that parses the passed {@code xml}. + *

+ * This uses the {@link XMLStreamReader} implementation provided by the default + * {@link XMLInputFactory#newInstance()}. If you need to provide a custom implementation of + * {@link XMLStreamReader} use {@link #fromXmlStreamReader(XMLStreamReader)}. + * + * @param xml The XML to parse. + * @return A new {@link XmlReader} instance. + * @throws NullPointerException If {@code xml} is null. + * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. + */ + public static XmlReader fromBytes(byte[] xml) throws XMLStreamException { + Objects.requireNonNull(xml, "'xml' cannot be null."); + return fromStream(new ByteArrayInputStream(xml)); + } + + /** + * Creates an {@link XmlReader} that parses the passed {@code xml}. + *

+ * This uses the {@link XMLStreamReader} implementation provided by the default + * {@link XMLInputFactory#newInstance()}. If you need to provide a custom implementation of + * {@link XMLStreamReader} use {@link #fromXmlStreamReader(XMLStreamReader)}. + * + * @param xml The XML to parse. + * @return A new {@link XmlReader} instance. + * @throws NullPointerException If {@code xml} is null. + * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. + */ + public static XmlReader fromString(String xml) throws XMLStreamException { + Objects.requireNonNull(xml, "'xml' cannot be null."); + return fromReader(new StringReader(xml)); + } + + /** + * Creates an {@link XmlReader} that parses the passed {@code xml}. + *

+ * This uses the {@link XMLStreamReader} implementation provided by the default + * {@link XMLInputFactory#newInstance()}. If you need to provide a custom implementation of + * {@link XMLStreamReader} use {@link #fromXmlStreamReader(XMLStreamReader)}. + * + * @param xml The XML to parse. + * @return A new {@link XmlReader} instance. + * @throws NullPointerException If {@code xml} is null. + * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. + */ + public static XmlReader fromStream(InputStream xml) throws XMLStreamException { + Objects.requireNonNull(xml, "'xml' cannot be null."); + return new XmlReader(XML_INPUT_FACTORY.createXMLStreamReader(xml)); + } + + /** + * Creates an {@link XmlReader} that parses the passed {@code xml}. + *

+ * This uses the {@link XMLStreamReader} implementation provided by the default + * {@link XMLInputFactory#newInstance()}. If you need to provide a custom implementation of + * {@link XMLStreamReader} use {@link #fromXmlStreamReader(XMLStreamReader)}. + * + * @param xml The XML to parse. + * @return A new {@link XmlReader} instance. + * @throws NullPointerException If {@code xml} is null. + * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. + */ + public static XmlReader fromReader(Reader xml) throws XMLStreamException { + Objects.requireNonNull(xml, "'xml' cannot be null."); + return new XmlReader(XML_INPUT_FACTORY.createXMLStreamReader(xml)); + } + + /** + * Creates an {@link XmlReader} that parses the passed {@code xml}. + *

+ * This uses the provided {@link XMLStreamReader} implementation to parse the XML. + * + * @param reader The {@link XMLStreamReader} to parse the XML. + * @return A new {@link XmlReader} instance. + * @throws NullPointerException If {@code reader} is null. + */ + public static XmlReader fromXmlStreamReader(XMLStreamReader reader) { + return new XmlReader(reader); + } + /** * Creates an instance of {@link XmlReader}. */ - public XmlReader() { + private XmlReader(XMLStreamReader reader) { + this.reader = Objects.requireNonNull(reader, "'reader' cannot be null."); + this.currentToken = convertEventToToken(reader.getEventType()); } /** @@ -27,7 +129,9 @@ public XmlReader() { * * @return The {@link XmlToken} that the reader points to currently. */ - public abstract XmlToken currentToken(); + public XmlToken currentToken() { + return currentToken; + } /** * Iterates to and returns the next {@link XmlToken#START_ELEMENT} or {@link XmlToken#END_ELEMENT} in the XML @@ -40,7 +144,17 @@ public XmlReader() { * {@link XmlToken#END_DOCUMENT} if reading completes. * @throws XMLStreamException If the next element cannot be determined. */ - public abstract XmlToken nextElement() throws XMLStreamException; + public XmlToken nextElement() throws XMLStreamException { + int next = reader.next(); + while (next != XMLStreamConstants.START_ELEMENT + && next != XMLStreamConstants.END_ELEMENT + && next != XMLStreamConstants.END_DOCUMENT) { + next = reader.next(); + } + + currentToken = convertEventToToken(next); + return currentToken; + } /** * Closes the XML stream. @@ -48,7 +162,9 @@ public XmlReader() { * @throws XMLStreamException If the underlying content store fails to close. */ @Override - public abstract void close() throws XMLStreamException; + public void close() throws XMLStreamException { + reader.close(); + } /** * Gets the {@link QName} for the current XML element. @@ -57,7 +173,9 @@ public XmlReader() { * @throws IllegalStateException If the {@link #currentToken()} {@link XmlToken#START_ELEMENT} or * {@link XmlToken#END_ELEMENT}. */ - public abstract QName getElementName(); + public QName getElementName() { + return reader.getName(); + } /** * Gets the string value for the attribute in the XML element. @@ -69,7 +187,12 @@ public XmlReader() { * @return The string value for the attribute in the XML element, or null if the attribute doesn't exist. * @throws IllegalStateException If {@link #currentToken()} isn't {@link XmlToken#START_ELEMENT}. */ - public abstract String getStringAttribute(String namespaceUri, String localName); + public String getStringAttribute(String namespaceUri, String localName) { + String value = reader.getAttributeValue(namespaceUri, localName); + + // Treat empty string as null. + return "".equals(value) ? null : value; + } /** * Gets the binary value for the attribute in the XML element. @@ -78,7 +201,7 @@ public XmlReader() { * @param localName Attribute local name. * @return The binary value for the attribute in the XML element. */ - public final byte[] getBinaryAttribute(String namespaceUri, String localName) { + public byte[] getBinaryAttribute(String namespaceUri, String localName) { String value = getStringAttribute(namespaceUri, localName); return (value == null || value.isEmpty()) ? null : Base64.getDecoder().decode(value); } @@ -90,7 +213,7 @@ public final byte[] getBinaryAttribute(String namespaceUri, String localName) { * @param localName Attribute local name. * @return The boolean value for the attribute in the XML element. */ - public final boolean getBooleanAttribute(String namespaceUri, String localName) { + public boolean getBooleanAttribute(String namespaceUri, String localName) { return Boolean.parseBoolean(getStringAttribute(namespaceUri, localName)); } @@ -101,7 +224,7 @@ public final boolean getBooleanAttribute(String namespaceUri, String localName) * @param localName Attribute local name. * @return The double value for the attribute in the XML element. */ - public final double getDoubleAttribute(String namespaceUri, String localName) { + public double getDoubleAttribute(String namespaceUri, String localName) { return Double.parseDouble(getStringAttribute(namespaceUri, localName)); } @@ -112,7 +235,7 @@ public final double getDoubleAttribute(String namespaceUri, String localName) { * @param localName Attribute local name. * @return The float value for the attribute in the XML element. */ - public final float getFloatAttribute(String namespaceUri, String localName) { + public float getFloatAttribute(String namespaceUri, String localName) { return Float.parseFloat(getStringAttribute(namespaceUri, localName)); } @@ -123,7 +246,7 @@ public final float getFloatAttribute(String namespaceUri, String localName) { * @param localName Attribute local name. * @return The int value for the attribute in the XML element. */ - public final int getIntAttribute(String namespaceUri, String localName) { + public int getIntAttribute(String namespaceUri, String localName) { return Integer.parseInt(getStringAttribute(namespaceUri, localName)); } @@ -134,7 +257,7 @@ public final int getIntAttribute(String namespaceUri, String localName) { * @param localName Attribute local name. * @return The long value for the attribute in the XML element. */ - public final long getLongAttribute(String namespaceUri, String localName) { + public long getLongAttribute(String namespaceUri, String localName) { return Long.parseLong(getStringAttribute(namespaceUri, localName)); } @@ -151,8 +274,8 @@ public final long getLongAttribute(String namespaceUri, String localName) { * @return The converted text value, or null if the attribute didn't have a value. * @throws XMLStreamException If the nullable attribute cannot be read. */ - public final T getNullableAttribute(String namespaceUri, String localName, - ReadValueCallback converter) throws XMLStreamException { + public T getNullableAttribute(String namespaceUri, String localName, ReadValueCallback converter) + throws XMLStreamException { String textValue = getStringAttribute(namespaceUri, localName); if (textValue == null) { @@ -172,7 +295,72 @@ public final T getNullableAttribute(String namespaceUri, String localName, * @return The string value for the current element. * @throws XMLStreamException If the String element cannot be read. */ - public abstract String getStringElement() throws XMLStreamException; + public String getStringElement() throws XMLStreamException { + // The default getElementText implementation in the JDK uses an internal buffer as the API handles merging + // multiple text states, characters, CDATA, space, and entity reference, into a single String. This + // generally results in overhead as most cases will only have a single read performed but that read will + // be buffered into the buffer and then returned as-is. So instead, a custom implementation will be used + // where a small String buffer will be used to contain the intermediate reads and when the terminal state + // is reached if only a single read was performed the String can be return, and if the unlikely multiple + // read scenario is triggered those Strings can be concatenated. + // + // This logic continues to work even if the underlying XMLStreamReader implementation, such as the one + // used in Jackson XML through Woodstox, handles this already. + + int readCount = 0; + String firstRead = null; + String[] buffer = null; + int stringBufferSize = 0; + int nextEvent = reader.next(); + + // Continue reading until the next event is the end of the element or an exception state. + while (nextEvent != XMLStreamConstants.END_ELEMENT) { + if (nextEvent == XMLStreamConstants.CHARACTERS + || nextEvent == XMLStreamConstants.CDATA + || nextEvent == XMLStreamConstants.SPACE + || nextEvent == XMLStreamConstants.ENTITY_REFERENCE) { + readCount++; + if (readCount == 1) { + firstRead = reader.getText(); + stringBufferSize = firstRead.length(); + } else { + if (readCount == 2) { + buffer = new String[4]; + buffer[0] = firstRead; + } + + if (readCount > buffer.length - 1) { + String[] newBuffer = new String[buffer.length * 2]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + + String readText = reader.getText(); + buffer[readCount - 1] = readText; + stringBufferSize += readText.length(); + } + } else if (nextEvent != XMLStreamConstants.PROCESSING_INSTRUCTION + && nextEvent != XMLStreamConstants.COMMENT) { + // Processing instructions and comments are ignored but anything else is unexpected. + throw new XMLStreamException("Unexpected event type while reading element value " + nextEvent); + } + + nextEvent = reader.next(); + } + + if (readCount == 0) { + return null; + } else if (readCount == 1) { + return firstRead; + } else { + StringBuilder finalText = new StringBuilder(stringBufferSize); + for (int i = 0; i < readCount; i++) { + finalText.append(buffer[i]); + } + + return finalText.toString(); + } + } /** * Gets the binary value for the current element. @@ -180,7 +368,7 @@ public final T getNullableAttribute(String namespaceUri, String localName, * @return The binary value for the current element. * @throws XMLStreamException If the binary element cannot be read. */ - public final byte[] getBinaryElement() throws XMLStreamException { + public byte[] getBinaryElement() throws XMLStreamException { String value = getStringElement(); return (value == null || value.isEmpty()) ? null : Base64.getDecoder().decode(value); } @@ -191,7 +379,7 @@ public final byte[] getBinaryElement() throws XMLStreamException { * @return The boolean value for the current element. * @throws XMLStreamException If the boolean element cannot be read. */ - public final boolean getBooleanElement() throws XMLStreamException { + public boolean getBooleanElement() throws XMLStreamException { return Boolean.parseBoolean(getStringElement()); } @@ -201,7 +389,7 @@ public final boolean getBooleanElement() throws XMLStreamException { * @return The double value for the current element. * @throws XMLStreamException If the double element cannot be read. */ - public final double getDoubleElement() throws XMLStreamException { + public double getDoubleElement() throws XMLStreamException { return Double.parseDouble(getStringElement()); } @@ -211,7 +399,7 @@ public final double getDoubleElement() throws XMLStreamException { * @return The float value for the current element. * @throws XMLStreamException If the float element cannot be read. */ - public final float getFloatElement() throws XMLStreamException { + public float getFloatElement() throws XMLStreamException { return Float.parseFloat(getStringElement()); } @@ -221,7 +409,7 @@ public final float getFloatElement() throws XMLStreamException { * @return The int value for the current element. * @throws XMLStreamException If the int element cannot be read. */ - public final int getIntElement() throws XMLStreamException { + public int getIntElement() throws XMLStreamException { return Integer.parseInt(getStringElement()); } @@ -231,7 +419,7 @@ public final int getIntElement() throws XMLStreamException { * @return The long value for the current element. * @throws XMLStreamException If the long element cannot be read. */ - public final long getLongElement() throws XMLStreamException { + public long getLongElement() throws XMLStreamException { return Long.parseLong(getStringElement()); } @@ -246,7 +434,7 @@ public final long getLongElement() throws XMLStreamException { * @return The converted text value, or null if the element didn't have a value. * @throws XMLStreamException If the nullable element cannot be read. */ - public final T getNullableElement(ReadValueCallback converter) throws XMLStreamException { + public T getNullableElement(ReadValueCallback converter) throws XMLStreamException { String textValue = getStringElement(); if (textValue == null) { @@ -274,8 +462,7 @@ public final T getNullableElement(ReadValueCallback converter) th * the expected {@code startTagName} * @throws XMLStreamException If the object cannot be read. */ - public final T readObject(String localName, ReadValueCallback converter) - throws XMLStreamException { + public T readObject(String localName, ReadValueCallback converter) throws XMLStreamException { return readObject(null, localName, converter); } @@ -294,7 +481,7 @@ public final T readObject(String localName, ReadValueCallback * the expected {@code startTagName} * @throws XMLStreamException If the object cannot be read. */ - public final T readObject(String namespaceUri, String localName, ReadValueCallback converter) + public T readObject(String namespaceUri, String localName, ReadValueCallback converter) throws XMLStreamException { return readObject(new QName(namespaceUri, localName), converter); } @@ -331,7 +518,7 @@ private T readObject(QName startTagName, ReadValueCallback con * {@link XmlToken#START_ELEMENT}. * @throws XMLStreamException If skipping the element fails. */ - public final void skipElement() throws XMLStreamException { + public void skipElement() throws XMLStreamException { XmlToken currentToken = currentToken(); if (currentToken != XmlToken.START_ELEMENT) { return; @@ -352,4 +539,23 @@ public final void skipElement() throws XMLStreamException { } } } + + private static XmlToken convertEventToToken(int event) { + switch (event) { + case 1: + return XmlToken.START_ELEMENT; + + case 2: + return XmlToken.END_ELEMENT; + + case 7: + return XmlToken.START_DOCUMENT; + + case 8: + return XmlToken.END_DOCUMENT; + + default: + throw new IllegalStateException("Unknown/unsupported XMLStreamConstants: " + event); + } + } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlSerializable.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlSerializable.java index 6e80d8e8b51a..aeeb4c48ee17 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlSerializable.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlSerializable.java @@ -9,10 +9,19 @@ * Indicates that the implementing class can be serialized to and deserialized from XML. *

* Since deserialization needs to work without an instance of the class, implementing this interface it's assumed the - * class has a static method {@code fromXml(XmlReader)} that deserializes an instance of that class. The contract for - * reading XML... TODO (alzimmer): finish this javadoc + * class has static methods {@link #fromXml(XmlReader)} and {@link #fromXml(XmlReader, String)} that deserializes an + * instance of that class. The contract for reading XML from {@link XmlReader} is that the initial state of the reader + * on call will either be a null {@link XmlToken} or be {@link XmlToken#START_ELEMENT} for the object. So, for objects + * calling out to other {@link XmlSerializable} objects for deserialization, they'll pass the reader pointing to the + * token after the {@link XmlToken#START_ELEMENT}. This way objects reading XML will be self-encapsulated for reading + * properly formatted XML. And, if an error occurs during deserialization an {@link IllegalStateException} should be + * thrown. * * @param The type of the object that is XML serializable. + * + * @see com.azure.xml + * @see XmlReader + * @see XmlWriter */ public interface XmlSerializable> { /** @@ -24,7 +33,7 @@ public interface XmlSerializable> { * writing XML will be self-encapsulated for writing properly formatted XML. * * @param xmlWriter The {@link XmlWriter} being written to. - * @return The {@link XmlWriter} where the JSON was written for chaining. + * @return The {@link XmlWriter} where the XML was written for chaining. * @throws XMLStreamException If the object fails to be written to the {@code xmlWriter}. */ XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException; @@ -40,7 +49,7 @@ public interface XmlSerializable> { * @param xmlWriter The {@link XmlWriter} being written to. * @param rootElementName Optional root element name to override the default defined by the model. Used to support * cases where the model can serialize using different root element names. - * @return The {@link XmlWriter} where the JSON was written for chaining. + * @return The {@link XmlWriter} where the XML was written for chaining. * @throws XMLStreamException If the object fails to be written to the {@code xmlWriter}. */ XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlWriter.java index 345f8f1d591e..039d053e886e 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlWriter.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/XmlWriter.java @@ -3,18 +3,80 @@ package com.azure.xml; +import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.util.Base64; +import java.util.Objects; + +import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX; /** * Writes an XML encoded value to a stream. */ @SuppressWarnings("resource") -public abstract class XmlWriter implements AutoCloseable { +public final class XmlWriter implements AutoCloseable { + private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance(); + + private final XMLStreamWriter writer; + + /** + * Creates an instance of {@link XmlWriter} that writes to the provided {@link OutputStream}. + *

+ * This uses the {@link XMLStreamWriter} implementation provided by the default + * {@link XMLOutputFactory#newInstance()}. If you need to provide a custom implementation of + * {@link XMLStreamWriter} use {@link #fromXmlStreamWriter(XMLStreamWriter)}. + * + * @param xml The {@link OutputStream} where content will be written. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code xml} is null. + * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. + */ + public static XmlWriter toStream(OutputStream xml) throws XMLStreamException { + Objects.requireNonNull(xml, "'xml' cannot be null."); + return new XmlWriter( + XML_OUTPUT_FACTORY.createXMLStreamWriter(new OutputStreamWriter(xml, StandardCharsets.UTF_8))); + } + + /** + * Creates an instance of {@link XmlWriter} that writes to the provided {@link Writer}. + *

+ * This uses the {@link XMLStreamWriter} implementation provided by the default + * {@link XMLOutputFactory#newInstance()}. If you need to provide a custom implementation of + * {@link XMLStreamWriter} use {@link #fromXmlStreamWriter(XMLStreamWriter)}. + * + * @param xml The {@link Writer} where content will be written. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code xml} is null. + * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. + */ + public static XmlWriter toWriter(Writer xml) throws XMLStreamException { + Objects.requireNonNull(xml, "'xml' cannot be null."); + return new XmlWriter(XML_OUTPUT_FACTORY.createXMLStreamWriter(xml)); + } + + /** + * Creates an instance of {@link XmlWriter} that writes to the provided {@link XMLStreamWriter}. + * + * @param writer The {@link XMLStreamWriter} where content will be written. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code writer} is null. + */ + public static XmlWriter fromXmlStreamWriter(XMLStreamWriter writer) { + return new XmlWriter(writer); + } + /** * Creates an instance of {@link XmlWriter}. + * + * @param writer The {@link XMLStreamWriter} where content will be written. */ - public XmlWriter() { + private XmlWriter(XMLStreamWriter writer) { + this.writer = Objects.requireNonNull(writer, "'writer' cannot be null."); } /** @@ -27,7 +89,7 @@ public XmlWriter() { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML start document cannot be written. */ - public final XmlWriter writeStartDocument() throws XMLStreamException { + public XmlWriter writeStartDocument() throws XMLStreamException { return writeStartDocument("1.0", "UTF-8"); } @@ -42,7 +104,10 @@ public final XmlWriter writeStartDocument() throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML start document cannot be written. */ - public abstract XmlWriter writeStartDocument(String version, String encoding) throws XMLStreamException; + public XmlWriter writeStartDocument(String version, String encoding) throws XMLStreamException { + writer.writeStartDocument(encoding, version); + return this; + } /** * Begins an XML element start ({@code }). @@ -92,7 +164,7 @@ public final XmlWriter writeStartElement(String localName) throws XMLStreamExcep * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element start cannot be written. */ - public final XmlWriter writeStartSelfClosingElement(String localName) throws XMLStreamException { + public XmlWriter writeStartSelfClosingElement(String localName) throws XMLStreamException { return writeStartSelfClosingElement(null, localName); } @@ -112,8 +184,14 @@ public final XmlWriter writeStartSelfClosingElement(String localName) throws XML * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element start cannot be written. */ - public abstract XmlWriter writeStartSelfClosingElement(String namespaceUri, String localName) - throws XMLStreamException; + public XmlWriter writeStartSelfClosingElement(String namespaceUri, String localName) throws XMLStreamException { + if (namespaceUri == null) { + writer.writeEmptyElement(localName); + } else { + writer.writeEmptyElement(namespaceUri, localName); + } + return this; + } /** * Ends the current XML element by writing the closing tag ({@code }). @@ -124,7 +202,10 @@ public abstract XmlWriter writeStartSelfClosingElement(String namespaceUri, Stri * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element end cannot be written. */ - public abstract XmlWriter writeEndElement() throws XMLStreamException; + public XmlWriter writeEndElement() throws XMLStreamException { + writer.writeEndElement(); + return this; + } /** * Writes a default XML namespace. @@ -133,7 +214,15 @@ public abstract XmlWriter writeStartSelfClosingElement(String namespaceUri, Stri * @return The updated XmlWriter object. * @throws XMLStreamException If the XML namespace cannot be written. */ - public abstract XmlWriter writeNamespace(String namespaceUri) throws XMLStreamException; + public XmlWriter writeNamespace(String namespaceUri) throws XMLStreamException { + if (Objects.equals(writer.getNamespaceContext().getNamespaceURI(DEFAULT_NS_PREFIX), namespaceUri)) { + return this; + } + + writer.setDefaultNamespace(namespaceUri); + writer.writeDefaultNamespace(namespaceUri); + return this; + } /** * Writes an XML namespace with a specified prefix. @@ -146,7 +235,18 @@ public abstract XmlWriter writeStartSelfClosingElement(String namespaceUri, Stri * @return The updated XmlWriter object. * @throws XMLStreamException If the XML namespace cannot be written. */ - public abstract XmlWriter writeNamespace(String namespacePrefix, String namespaceUri) throws XMLStreamException; + public XmlWriter writeNamespace(String namespacePrefix, String namespaceUri) throws XMLStreamException { + if (namespacePrefix == null || "xmlns".equals(namespacePrefix)) { + return writeNamespace(namespacePrefix); + } + + if (Objects.equals(writer.getNamespaceContext().getNamespaceURI(namespacePrefix), namespaceUri)) { + return this; + } + + writer.writeNamespace(namespacePrefix, namespaceUri); + return this; + } /** * Writes a String attribute ({@code attribute="value"}). @@ -156,7 +256,7 @@ public abstract XmlWriter writeStartSelfClosingElement(String namespaceUri, Stri * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeStringAttribute(String localName, String value) throws XMLStreamException { + public XmlWriter writeStringAttribute(String localName, String value) throws XMLStreamException { return writeStringAttribute(null, localName, value); } @@ -169,8 +269,19 @@ public final XmlWriter writeStringAttribute(String localName, String value) thro * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public abstract XmlWriter writeStringAttribute(String namespaceUri, String localName, String value) - throws XMLStreamException; + public XmlWriter writeStringAttribute(String namespaceUri, String localName, String value) + throws XMLStreamException { + if (value == null) { + return this; + } + + if (namespaceUri == null) { + writer.writeAttribute(localName, value); + } else { + writer.writeAttribute(namespaceUri, localName, value); + } + return this; + } /** * Writes a binary attribute as a base64 string ({@code attribute="value"}). @@ -182,7 +293,7 @@ public abstract XmlWriter writeStringAttribute(String namespaceUri, String local * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeBinaryAttribute(String localName, byte[] value) throws XMLStreamException { + public XmlWriter writeBinaryAttribute(String localName, byte[] value) throws XMLStreamException { return writeBinaryAttribute(null, localName, value); } @@ -197,7 +308,7 @@ public final XmlWriter writeBinaryAttribute(String localName, byte[] value) thro * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeBinaryAttribute(String namespaceUri, String localName, byte[] value) + public XmlWriter writeBinaryAttribute(String namespaceUri, String localName, byte[] value) throws XMLStreamException { if (value == null) { return this; @@ -214,7 +325,7 @@ public final XmlWriter writeBinaryAttribute(String namespaceUri, String localNam * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeBooleanAttribute(String localName, boolean value) throws XMLStreamException { + public XmlWriter writeBooleanAttribute(String localName, boolean value) throws XMLStreamException { return writeStringAttribute(localName, String.valueOf(value)); } @@ -227,7 +338,7 @@ public final XmlWriter writeBooleanAttribute(String localName, boolean value) th * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeBooleanAttribute(String namespaceUri, String localName, boolean value) + public XmlWriter writeBooleanAttribute(String namespaceUri, String localName, boolean value) throws XMLStreamException { return writeStringAttribute(namespaceUri, localName, String.valueOf(value)); } @@ -242,7 +353,7 @@ public final XmlWriter writeBooleanAttribute(String namespaceUri, String localNa * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeBooleanAttribute(String localName, Boolean value) throws XMLStreamException { + public XmlWriter writeBooleanAttribute(String localName, Boolean value) throws XMLStreamException { return writeBooleanAttribute(null, localName, value); } @@ -257,7 +368,7 @@ public final XmlWriter writeBooleanAttribute(String localName, Boolean value) th * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeBooleanAttribute(String namespaceUri, String localName, Boolean value) + public XmlWriter writeBooleanAttribute(String namespaceUri, String localName, Boolean value) throws XMLStreamException { if (value == null) { return this; @@ -274,7 +385,7 @@ public final XmlWriter writeBooleanAttribute(String namespaceUri, String localNa * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeDoubleAttribute(String localName, double value) throws XMLStreamException { + public XmlWriter writeDoubleAttribute(String localName, double value) throws XMLStreamException { return writeStringAttribute(localName, String.valueOf(value)); } @@ -287,7 +398,7 @@ public final XmlWriter writeDoubleAttribute(String localName, double value) thro * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeDoubleAttribute(String namespaceUri, String localName, double value) + public XmlWriter writeDoubleAttribute(String namespaceUri, String localName, double value) throws XMLStreamException { return writeStringAttribute(namespaceUri, localName, String.valueOf(value)); } @@ -300,7 +411,7 @@ public final XmlWriter writeDoubleAttribute(String namespaceUri, String localNam * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeFloatAttribute(String localName, float value) throws XMLStreamException { + public XmlWriter writeFloatAttribute(String localName, float value) throws XMLStreamException { return writeStringAttribute(localName, String.valueOf(value)); } @@ -313,8 +424,7 @@ public final XmlWriter writeFloatAttribute(String localName, float value) throws * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeFloatAttribute(String namespaceUri, String localName, float value) - throws XMLStreamException { + public XmlWriter writeFloatAttribute(String namespaceUri, String localName, float value) throws XMLStreamException { return writeStringAttribute(namespaceUri, localName, String.valueOf(value)); } @@ -326,7 +436,7 @@ public final XmlWriter writeFloatAttribute(String namespaceUri, String localName * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeIntAttribute(String localName, int value) throws XMLStreamException { + public XmlWriter writeIntAttribute(String localName, int value) throws XMLStreamException { return writeStringAttribute(localName, String.valueOf(value)); } @@ -339,8 +449,7 @@ public final XmlWriter writeIntAttribute(String localName, int value) throws XML * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeIntAttribute(String namespaceUri, String localName, int value) - throws XMLStreamException { + public XmlWriter writeIntAttribute(String namespaceUri, String localName, int value) throws XMLStreamException { return writeStringAttribute(namespaceUri, localName, String.valueOf(value)); } @@ -352,7 +461,7 @@ public final XmlWriter writeIntAttribute(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeLongAttribute(String localName, long value) throws XMLStreamException { + public XmlWriter writeLongAttribute(String localName, long value) throws XMLStreamException { return writeStringAttribute(localName, String.valueOf(value)); } @@ -365,8 +474,7 @@ public final XmlWriter writeLongAttribute(String localName, long value) throws X * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeLongAttribute(String namespaceUri, String localName, long value) - throws XMLStreamException { + public XmlWriter writeLongAttribute(String namespaceUri, String localName, long value) throws XMLStreamException { return writeStringAttribute(namespaceUri, localName, String.valueOf(value)); } @@ -378,7 +486,7 @@ public final XmlWriter writeLongAttribute(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeNumberAttribute(String localName, Number value) throws XMLStreamException { + public XmlWriter writeNumberAttribute(String localName, Number value) throws XMLStreamException { return writeNumberAttribute(null, localName, value); } @@ -391,7 +499,7 @@ public final XmlWriter writeNumberAttribute(String localName, Number value) thro * @return The updated XmlWriter object. * @throws XMLStreamException If the XML attribute cannot be written. */ - public final XmlWriter writeNumberAttribute(String namespaceUri, String localName, Number value) + public XmlWriter writeNumberAttribute(String namespaceUri, String localName, Number value) throws XMLStreamException { if (value == null) { return this; @@ -410,7 +518,7 @@ public final XmlWriter writeNumberAttribute(String namespaceUri, String localNam * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeBinaryElement(String localName, byte[] value) throws XMLStreamException { + public XmlWriter writeBinaryElement(String localName, byte[] value) throws XMLStreamException { return writeBinaryElement(null, localName, value); } @@ -425,8 +533,7 @@ public final XmlWriter writeBinaryElement(String localName, byte[] value) throws * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeBinaryElement(String namespaceUri, String localName, byte[] value) - throws XMLStreamException { + public XmlWriter writeBinaryElement(String namespaceUri, String localName, byte[] value) throws XMLStreamException { if (value == null) { return this; } @@ -442,7 +549,7 @@ public final XmlWriter writeBinaryElement(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeBooleanElement(String localName, boolean value) throws XMLStreamException { + public XmlWriter writeBooleanElement(String localName, boolean value) throws XMLStreamException { return writeBooleanElement(null, localName, value); } @@ -455,7 +562,7 @@ public final XmlWriter writeBooleanElement(String localName, boolean value) thro * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeBooleanElement(String namespaceUri, String localName, boolean value) + public XmlWriter writeBooleanElement(String namespaceUri, String localName, boolean value) throws XMLStreamException { return writeStartElement(namespaceUri, localName).writeBoolean(value).writeEndElement(); } @@ -470,7 +577,7 @@ public final XmlWriter writeBooleanElement(String namespaceUri, String localName * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeBooleanElement(String localName, Boolean value) throws XMLStreamException { + public XmlWriter writeBooleanElement(String localName, Boolean value) throws XMLStreamException { return writeBooleanElement(null, localName, value); } @@ -485,7 +592,7 @@ public final XmlWriter writeBooleanElement(String localName, Boolean value) thro * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeBooleanElement(String namespaceUri, String localName, Boolean value) + public XmlWriter writeBooleanElement(String namespaceUri, String localName, Boolean value) throws XMLStreamException { if (value == null) { return this; @@ -502,7 +609,7 @@ public final XmlWriter writeBooleanElement(String namespaceUri, String localName * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeDoubleElement(String localName, double value) throws XMLStreamException { + public XmlWriter writeDoubleElement(String localName, double value) throws XMLStreamException { return writeDoubleElement(null, localName, value); } @@ -515,8 +622,7 @@ public final XmlWriter writeDoubleElement(String localName, double value) throws * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeDoubleElement(String namespaceUri, String localName, double value) - throws XMLStreamException { + public XmlWriter writeDoubleElement(String namespaceUri, String localName, double value) throws XMLStreamException { return writeStartElement(namespaceUri, localName).writeDouble(value).writeEndElement(); } @@ -528,7 +634,7 @@ public final XmlWriter writeDoubleElement(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeFloatElement(String localName, float value) throws XMLStreamException { + public XmlWriter writeFloatElement(String localName, float value) throws XMLStreamException { return writeFloatElement(null, localName, value); } @@ -541,8 +647,7 @@ public final XmlWriter writeFloatElement(String localName, float value) throws X * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeFloatElement(String namespaceUri, String localName, float value) - throws XMLStreamException { + public XmlWriter writeFloatElement(String namespaceUri, String localName, float value) throws XMLStreamException { return writeStartElement(namespaceUri, localName).writeFloat(value).writeEndElement(); } @@ -554,7 +659,7 @@ public final XmlWriter writeFloatElement(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeIntElement(String localName, int value) throws XMLStreamException { + public XmlWriter writeIntElement(String localName, int value) throws XMLStreamException { return writeIntElement(null, localName, value); } @@ -567,7 +672,7 @@ public final XmlWriter writeIntElement(String localName, int value) throws XMLSt * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeIntElement(String namespaceUri, String localName, int value) throws XMLStreamException { + public XmlWriter writeIntElement(String namespaceUri, String localName, int value) throws XMLStreamException { return writeStartElement(namespaceUri, localName).writeInt(value).writeEndElement(); } @@ -579,7 +684,7 @@ public final XmlWriter writeIntElement(String namespaceUri, String localName, in * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeLongElement(String localName, long value) throws XMLStreamException { + public XmlWriter writeLongElement(String localName, long value) throws XMLStreamException { return writeLongElement(null, localName, value); } @@ -592,8 +697,7 @@ public final XmlWriter writeLongElement(String localName, long value) throws XML * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeLongElement(String namespaceUri, String localName, long value) - throws XMLStreamException { + public XmlWriter writeLongElement(String namespaceUri, String localName, long value) throws XMLStreamException { return writeStartElement(namespaceUri, localName).writeLong(value).writeEndElement(); } @@ -607,7 +711,7 @@ public final XmlWriter writeLongElement(String namespaceUri, String localName, l * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeNumberElement(String localName, Number value) throws XMLStreamException { + public XmlWriter writeNumberElement(String localName, Number value) throws XMLStreamException { return writeNumberElement(null, localName, value); } @@ -622,8 +726,7 @@ public final XmlWriter writeNumberElement(String localName, Number value) throws * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeNumberElement(String namespaceUri, String localName, Number value) - throws XMLStreamException { + public XmlWriter writeNumberElement(String namespaceUri, String localName, Number value) throws XMLStreamException { if (value == null) { return this; } @@ -641,7 +744,7 @@ public final XmlWriter writeNumberElement(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeStringElement(String localName, String value) throws XMLStreamException { + public XmlWriter writeStringElement(String localName, String value) throws XMLStreamException { return writeStringElement(null, localName, value); } @@ -656,8 +759,7 @@ public final XmlWriter writeStringElement(String localName, String value) throws * @return The updated XmlWriter object. * @throws XMLStreamException If the XML element and value cannot be written. */ - public final XmlWriter writeStringElement(String namespaceUri, String localName, String value) - throws XMLStreamException { + public XmlWriter writeStringElement(String namespaceUri, String localName, String value) throws XMLStreamException { if (value == null) { return this; } @@ -674,7 +776,7 @@ public final XmlWriter writeStringElement(String namespaceUri, String localName, * @return The updated XmlWriter object. * @throws XMLStreamException If the XML object cannot be written. */ - public final XmlWriter writeXml(XmlSerializable value) throws XMLStreamException { + public XmlWriter writeXml(XmlSerializable value) throws XMLStreamException { return writeXml(value, null); } @@ -690,7 +792,7 @@ public final XmlWriter writeXml(XmlSerializable value) throws XMLStreamExcept * @return The updated XmlWriter object. * @throws XMLStreamException If the XML object cannot be written. */ - public final XmlWriter writeXml(XmlSerializable value, String rootElementName) throws XMLStreamException { + public XmlWriter writeXml(XmlSerializable value, String rootElementName) throws XMLStreamException { return value == null ? this : value.toXml(this, rootElementName); } @@ -703,7 +805,7 @@ public final XmlWriter writeXml(XmlSerializable value, String rootElementName * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeBinary(byte[] value) throws XMLStreamException { + public XmlWriter writeBinary(byte[] value) throws XMLStreamException { return value == null ? this : writeString(convertBytesToString(value)); } @@ -714,7 +816,7 @@ public final XmlWriter writeBinary(byte[] value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeBoolean(boolean value) throws XMLStreamException { + public XmlWriter writeBoolean(boolean value) throws XMLStreamException { return writeString(String.valueOf(value)); } @@ -727,7 +829,7 @@ public final XmlWriter writeBoolean(boolean value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeBoolean(Boolean value) throws XMLStreamException { + public XmlWriter writeBoolean(Boolean value) throws XMLStreamException { return value == null ? this : writeString(String.valueOf(value)); } @@ -738,7 +840,7 @@ public final XmlWriter writeBoolean(Boolean value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeDouble(double value) throws XMLStreamException { + public XmlWriter writeDouble(double value) throws XMLStreamException { return writeString(String.valueOf(value)); } @@ -749,7 +851,7 @@ public final XmlWriter writeDouble(double value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeFloat(float value) throws XMLStreamException { + public XmlWriter writeFloat(float value) throws XMLStreamException { return writeString(String.valueOf(value)); } @@ -760,7 +862,7 @@ public final XmlWriter writeFloat(float value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeInt(int value) throws XMLStreamException { + public XmlWriter writeInt(int value) throws XMLStreamException { return writeString(String.valueOf(value)); } @@ -771,7 +873,7 @@ public final XmlWriter writeInt(int value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeLong(long value) throws XMLStreamException { + public XmlWriter writeLong(long value) throws XMLStreamException { return writeString(String.valueOf(value)); } @@ -784,7 +886,7 @@ public final XmlWriter writeLong(long value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public final XmlWriter writeNumber(Number value) throws XMLStreamException { + public XmlWriter writeNumber(Number value) throws XMLStreamException { return value == null ? this : writeString(String.valueOf(value)); } @@ -799,7 +901,14 @@ public final XmlWriter writeNumber(Number value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML value cannot be written. */ - public abstract XmlWriter writeString(String value) throws XMLStreamException; + public XmlWriter writeString(String value) throws XMLStreamException { + if (value == null) { + return this; + } + + writer.writeCharacters(value); + return this; + } /** * Writes a CData value directly into an XML element ({@code }). @@ -813,7 +922,14 @@ public final XmlWriter writeNumber(Number value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the XML CData value cannot be written. */ - public abstract XmlWriter writeCDataString(String value) throws XMLStreamException; + public XmlWriter writeCDataString(String value) throws XMLStreamException { + if (value == null) { + return this; + } + + writer.writeCData(value); + return this; + } /** * Flushes any un-flushed content that has been written to the {@link XmlWriter}. @@ -821,7 +937,10 @@ public final XmlWriter writeNumber(Number value) throws XMLStreamException { * @return The updated XmlWriter object. * @throws XMLStreamException If the un-flushed XML content could not be flushed. */ - public abstract XmlWriter flush() throws XMLStreamException; + public XmlWriter flush() throws XMLStreamException { + writer.flush(); + return this; + } /** * Closes the XML stream. @@ -831,7 +950,10 @@ public final XmlWriter writeNumber(Number value) throws XMLStreamException { * @throws XMLStreamException If the underlying content store fails to close. */ @Override - public abstract void close() throws XMLStreamException; + public void close() throws XMLStreamException { + writer.flush(); + writer.close(); + } private static String convertBytesToString(byte[] bytes) { if (bytes == null) { diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlReader.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlReader.java deleted file mode 100644 index bdbff6e94aad..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlReader.java +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.xml.implementation; - -import com.azure.xml.XmlReader; -import com.azure.xml.XmlToken; -import com.azure.xml.XmlWriter; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamConstants; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.util.Objects; - -/** - * Default {@link XmlWriter} implementation based on {@link XMLStreamReader}. - */ -public final class DefaultXmlReader extends XmlReader { - private static final XMLInputFactory XML_INPUT_FACTORY; - - static { - XML_INPUT_FACTORY = XMLInputFactory.newInstance(); - XML_INPUT_FACTORY.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); - XML_INPUT_FACTORY.setProperty(XMLInputFactory.SUPPORT_DTD, false); - } - - private final XMLStreamReader reader; - - private XmlToken currentToken; - - /** - * Creates an {@link XMLStreamReader}-based {@link XmlReader} that parses the passed {@code xml}. - * - * @param xml The XML to parse. - * @return A new {@link XmlReader} instance. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader fromBytes(byte[] xml) throws XMLStreamException { - Objects.requireNonNull(xml, "'xml' cannot be null."); - return fromStream(new ByteArrayInputStream(xml)); - } - - /** - * Creates an {@link XmlReader} that parses the passed {@code xml}. - * - * @param xml The XML to parse. - * @return A new {@link XmlReader} instance. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader fromString(String xml) throws XMLStreamException { - Objects.requireNonNull(xml, "'xml' cannot be null."); - return fromReader(new StringReader(xml)); - } - - /** - * Creates an {@link XmlReader} that parses the passed {@code xml}. - * - * @param xml The XML to parse. - * @return A new {@link XmlReader} instance. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader fromStream(InputStream xml) throws XMLStreamException { - Objects.requireNonNull(xml, "'xml' cannot be null."); - return new DefaultXmlReader(XML_INPUT_FACTORY.createXMLStreamReader(xml)); - } - - /** - * Creates an {@link XmlReader} that parses the passed {@code xml}. - * - * @param xml The XML to parse. - * @return A new {@link XmlReader} instance. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlReader} cannot be instantiated. - */ - public static XmlReader fromReader(Reader xml) throws XMLStreamException { - Objects.requireNonNull(xml, "'xml' cannot be null."); - return new DefaultXmlReader(XML_INPUT_FACTORY.createXMLStreamReader(xml)); - } - - private DefaultXmlReader(XMLStreamReader reader) { - this.reader = reader; - this.currentToken = convertEventToToken(reader.getEventType()); - } - - @Override - public XmlToken currentToken() { - return currentToken; - } - - @Override - public XmlToken nextElement() throws XMLStreamException { - int next = reader.next(); - while (next != XMLStreamConstants.START_ELEMENT - && next != XMLStreamConstants.END_ELEMENT - && next != XMLStreamConstants.END_DOCUMENT) { - next = reader.next(); - } - - currentToken = convertEventToToken(next); - return currentToken; - } - - @Override - public QName getElementName() { - return reader.getName(); - } - - @Override - public String getStringElement() throws XMLStreamException { - // The default getElementText implementation in the JDK uses an internal buffer as the API handles merging - // multiple text states, characters, CDATA, space, and entity reference, into a single String. This - // generally results in overhead as most cases will only have a single read performed but that read will - // be buffered into the buffer and then returned as-is. So instead, a custom implementation will be used - // where a small String buffer will be used to contain the intermediate reads and when the terminal state - // is reached if only a single read was performed the String can be return, and if the unlikely multiple - // read scenario is triggered those Strings can be concatenated. - // - // This logic continues to work even if the underlying XMLStreamReader implementation, such as the one - // used in Jackson XML through Woodstox, handles this already. - - int readCount = 0; - String firstRead = null; - String[] buffer = null; - int stringBufferSize = 0; - int nextEvent = reader.next(); - - // Continue reading until the next event is the end of the element or an exception state. - while (nextEvent != XMLStreamConstants.END_ELEMENT) { - if (nextEvent == XMLStreamConstants.CHARACTERS - || nextEvent == XMLStreamConstants.CDATA - || nextEvent == XMLStreamConstants.SPACE - || nextEvent == XMLStreamConstants.ENTITY_REFERENCE) { - readCount++; - if (readCount == 1) { - firstRead = reader.getText(); - stringBufferSize = firstRead.length(); - } else { - if (readCount == 2) { - buffer = new String[4]; - buffer[0] = firstRead; - } - - if (readCount > buffer.length - 1) { - String[] newBuffer = new String[buffer.length * 2]; - System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); - buffer = newBuffer; - } - - String readText = reader.getText(); - buffer[readCount - 1] = readText; - stringBufferSize += readText.length(); - } - } else if (nextEvent != XMLStreamConstants.PROCESSING_INSTRUCTION - && nextEvent != XMLStreamConstants.COMMENT) { - // Processing instructions and comments are ignored but anything else is unexpected. - throw new XMLStreamException("Unexpected event type while reading element value " + nextEvent); - } - - nextEvent = reader.next(); - } - - if (readCount == 0) { - return null; - } else if (readCount == 1) { - return firstRead; - } else { - StringBuilder finalText = new StringBuilder(stringBufferSize); - for (int i = 0; i < readCount; i++) { - finalText.append(buffer[i]); - } - - return finalText.toString(); - } - } - - @Override - public String getStringAttribute(String namespaceUri, String localName) { - String value = reader.getAttributeValue(namespaceUri, localName); - - // Treat empty string as null. - return "".equals(value) ? null : value; - } - - @Override - public void close() throws XMLStreamException { - reader.close(); - } - - private static XmlToken convertEventToToken(int event) { - switch (event) { - case 1: - return XmlToken.START_ELEMENT; - - case 2: - return XmlToken.END_ELEMENT; - - case 7: - return XmlToken.START_DOCUMENT; - - case 8: - return XmlToken.END_DOCUMENT; - - default: - throw new IllegalStateException("Unknown/unsupported XMLStreamConstants: " + event); - } - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlWriter.java deleted file mode 100644 index 449ab0a06a95..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlWriter.java +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.xml.implementation; - -import com.azure.xml.XmlWriter; - -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.util.Objects; - -import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX; - -/** - * Default {@link XmlWriter} implementation based on {@link XMLStreamWriter}. - */ -public final class DefaultXmlWriter extends XmlWriter { - private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance(); - - private final XMLStreamWriter writer; - - /** - * Creates an instance of {@link XmlWriter} that writes to the provided {@link OutputStream}. - * - * @param xml The {@link OutputStream} where content will be written. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - public static XmlWriter toStream(OutputStream xml) throws XMLStreamException { - Objects.requireNonNull(xml, "'xml' cannot be null."); - return new DefaultXmlWriter( - XML_OUTPUT_FACTORY.createXMLStreamWriter(new OutputStreamWriter(xml, StandardCharsets.UTF_8))); - } - - /** - * Creates an instance of {@link XmlWriter} that writes to the provided {@link Writer}. - * - * @param xml The {@link Writer} where content will be written. - * @return A new instance of {@link XmlWriter}. - * @throws NullPointerException If {@code xml} is null. - * @throws XMLStreamException If an {@link XmlWriter} cannot be instantiated. - */ - public static XmlWriter toWriter(Writer xml) throws XMLStreamException { - Objects.requireNonNull(xml, "'xml' cannot be null."); - return new DefaultXmlWriter(XML_OUTPUT_FACTORY.createXMLStreamWriter(xml)); - } - - private DefaultXmlWriter(XMLStreamWriter writer) { - this.writer = writer; - } - - @Override - public XmlWriter writeStartDocument(String version, String encoding) throws XMLStreamException { - writer.writeStartDocument(encoding, version); - return this; - } - - @Override - public XmlWriter writeStartElement(String namespaceUri, String localName) throws XMLStreamException { - if (namespaceUri == null) { - writer.writeStartElement(localName); - } else { - writer.writeStartElement(namespaceUri, localName); - } - return this; - } - - @Override - public XmlWriter writeStartSelfClosingElement(String namespaceUri, String localName) throws XMLStreamException { - if (namespaceUri == null) { - writer.writeEmptyElement(localName); - } else { - writer.writeEmptyElement(namespaceUri, localName); - } - return this; - } - - @Override - public XmlWriter writeNamespace(String namespaceUri) throws XMLStreamException { - if (Objects.equals(writer.getNamespaceContext().getNamespaceURI(DEFAULT_NS_PREFIX), namespaceUri)) { - return this; - } - - writer.setDefaultNamespace(namespaceUri); - writer.writeDefaultNamespace(namespaceUri); - return this; - } - - @Override - public XmlWriter writeNamespace(String namespacePrefix, String namespaceUri) throws XMLStreamException { - if (namespacePrefix == null || "xmlns".equals(namespacePrefix)) { - return writeNamespace(namespacePrefix); - } - - if (Objects.equals(writer.getNamespaceContext().getNamespaceURI(namespacePrefix), namespaceUri)) { - return this; - } - - writer.writeNamespace(namespacePrefix, namespaceUri); - return this; - } - - @Override - public XmlWriter writeEndElement() throws XMLStreamException { - writer.writeEndElement(); - return this; - } - - @Override - public XmlWriter writeStringAttribute(String namespaceUri, String localName, String value) - throws XMLStreamException { - if (value == null) { - return this; - } - - if (namespaceUri == null) { - writer.writeAttribute(localName, value); - } else { - writer.writeAttribute(namespaceUri, localName, value); - } - return this; - } - - @Override - public XmlWriter writeString(String value) throws XMLStreamException { - if (value == null) { - return this; - } - - writer.writeCharacters(value); - return this; - } - - @Override - public XmlWriter writeCDataString(String value) throws XMLStreamException { - if (value == null) { - return this; - } - - writer.writeCData(value); - return this; - } - - @Override - public XmlWriter flush() throws XMLStreamException { - writer.flush(); - return this; - } - - @Override - public void close() throws XMLStreamException { - writer.flush(); - writer.close(); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/package-info.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/package-info.java deleted file mode 100644 index a33eb394f5d2..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -/** - * Package containing implementation classes for XML parsing. - */ -package com.azure.xml.implementation; diff --git a/sdk/serialization/azure-xml/src/main/java/module-info.java b/sdk/serialization/azure-xml/src/main/java/module-info.java index 1a38d62f075d..9336476b78c5 100644 --- a/sdk/serialization/azure-xml/src/main/java/module-info.java +++ b/sdk/serialization/azure-xml/src/main/java/module-info.java @@ -5,7 +5,4 @@ requires java.xml; exports com.azure.xml; - exports com.azure.xml.implementation; - - uses com.azure.xml.XmlProvider; } diff --git a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java index a0aaf5defc13..220bfb6832b3 100644 --- a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java +++ b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java @@ -4,16 +4,15 @@ package com.azure.xml; import com.azure.xml.contract.XmlReaderContractTests; -import com.azure.xml.implementation.DefaultXmlReader; import javax.xml.stream.XMLStreamException; /** - * Tests {@link DefaultXmlReader} against the contract required by {@link XmlReader}. + * Tests {@link XmlReader} against the contract required by {@link XmlReader}. */ public final class DefaultXmlReaderContractTests extends XmlReaderContractTests { @Override protected XmlReader getXmlReader(String xml) throws XMLStreamException { - return DefaultXmlReader.fromString(xml); + return XmlReader.fromString(xml); } } diff --git a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java index 982cc2bea6ba..30ac391d4964 100644 --- a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java +++ b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java @@ -4,7 +4,6 @@ package com.azure.xml; import com.azure.xml.contract.XmlWriterContractTests; -import com.azure.xml.implementation.DefaultXmlWriter; import org.junit.jupiter.api.BeforeEach; import javax.xml.stream.XMLStreamException; @@ -13,7 +12,7 @@ import java.nio.charset.StandardCharsets; /** - * Tests {@link DefaultXmlWriter} against the contract required by {@link XmlWriter}. + * Tests {@link XmlWriter} against the contract required by {@link XmlWriter}. */ public final class DefaultXmlWriterContractTests extends XmlWriterContractTests { private ByteArrayOutputStream outputStream; @@ -22,7 +21,7 @@ public final class DefaultXmlWriterContractTests extends XmlWriterContractTests @BeforeEach public void beforeEach() throws XMLStreamException { this.outputStream = new ByteArrayOutputStream(); - this.writer = DefaultXmlWriter.toStream(outputStream); + this.writer = XmlWriter.toStream(outputStream); } @Override diff --git a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java index f03daf979d57..70d1c5090331 100644 --- a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java +++ b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java @@ -3,8 +3,6 @@ package com.azure.xml; -import com.azure.xml.implementation.DefaultXmlReader; -import com.azure.xml.implementation.DefaultXmlWriter; import org.junit.jupiter.api.Test; import javax.xml.stream.XMLStreamException; @@ -48,7 +46,7 @@ public void toXmlSimple() throws XMLStreamException, UnsupportedEncodingExceptio SignedIdentifiersWrapper wrapper = new SignedIdentifiersWrapper(Collections.singletonList(signedIdentifier)); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - try (XmlWriter xmlWriter = DefaultXmlWriter.toStream(byteArrayOutputStream)) { + try (XmlWriter xmlWriter = XmlWriter.toStream(byteArrayOutputStream)) { xmlWriter.writeStartDocument(); wrapper.toXml(xmlWriter); } @@ -68,7 +66,7 @@ public void fromXmlSimple() throws XMLStreamException { SignedIdentifiersWrapper wrapper = new SignedIdentifiersWrapper(Collections.singletonList(signedIdentifier)); - try (XmlReader xmlReader = DefaultXmlReader.fromString(SIMPLE_XML)) { + try (XmlReader xmlReader = XmlReader.fromString(SIMPLE_XML)) { SignedIdentifiersWrapper actualWrapper = SignedIdentifiersWrapper.fromXml(xmlReader); assertNotNull(actualWrapper); @@ -119,7 +117,7 @@ public void toXmlComplex() throws XMLStreamException, UnsupportedEncodingExcepti .setContent(namespacePropertiesEntryContent); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - try (XmlWriter xmlWriter = DefaultXmlWriter.toStream(byteArrayOutputStream)) { + try (XmlWriter xmlWriter = XmlWriter.toStream(byteArrayOutputStream)) { xmlWriter.writeStartDocument(); namespacePropertiesEntry.toXml(xmlWriter); } @@ -156,7 +154,7 @@ public void fromXmlComplex() throws XMLStreamException { .setLink(responseLink) .setContent(namespacePropertiesEntryContent); - try (XmlReader xmlReader = DefaultXmlReader.fromString(COMPLEX_XML)) { + try (XmlReader xmlReader = XmlReader.fromString(COMPLEX_XML)) { NamespacePropertiesEntry actualEntry = NamespacePropertiesEntry.fromXml(xmlReader); assertNotNull(actualEntry); diff --git a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/contract/XmlReaderContractTests.java b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/contract/XmlReaderContractTests.java index 84bc4b4c7beb..7ada36c3a20e 100644 --- a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/contract/XmlReaderContractTests.java +++ b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/contract/XmlReaderContractTests.java @@ -126,9 +126,9 @@ private static Stream binaryElementOperationsSupplier() { @ParameterizedTest @MethodSource("basicAttributeOperationsSupplier") - public void basicAttributeOperations(String json, T expectedValue, ReadValueCallback function) + public void basicAttributeOperations(String xml, T expectedValue, ReadValueCallback function) throws XMLStreamException { - XmlReader reader = getXmlReader(json); + XmlReader reader = getXmlReader(xml); reader.nextElement(); // Initialize the XmlReader for reading. T actualValue = assertDoesNotThrow(() -> function.read(reader)); diff --git a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DateTimeRfc1123.java b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DateTimeRfc1123.java index 7c410f8935ba..975b8b29ea6f 100644 --- a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DateTimeRfc1123.java +++ b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DateTimeRfc1123.java @@ -44,7 +44,7 @@ public OffsetDateTime getDateTime() { } /** - * JSON creator for DateTimeRfc1123. + * XML creator for DateTimeRfc1123. *

* If {@code date} is null or an empty string null will be returned. * diff --git a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java index 60a1587bc314..eab1659a3e59 100644 --- a/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java +++ b/sdk/serialization/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java @@ -3,7 +3,7 @@ package com.azure.xml.storage; -import com.azure.xml.implementation.DefaultXmlReader; +import com.azure.xml.XmlReader; import org.junit.jupiter.api.Test; import javax.xml.stream.XMLStreamException; @@ -28,7 +28,7 @@ public void minimumListing() throws XMLStreamException { .setContainerName("b9a86bdc0b9a86bdca9a521096fb76e1772d14cbaabf") .setSegment(new BlobFlatListSegment()); - ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(DefaultXmlReader.fromString(xml)); + ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(XmlReader.fromString(xml)); validateSegmentResponse(expected, actual); } @@ -90,7 +90,7 @@ public void pagedListing() throws XMLStreamException { .setNextMarker( "2!120!MDAwMDQ1IXQzNGZiY2JiYzQzNGZiY2JiYzI2YTgwMjA0YzRkMTlhYTliYTIxNDQ0NWFjYyEwMDAwMjghOTk5OS0xMi0zMVQyMzo1OTo1OS45OTk5OTk5WiE-"); - ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(DefaultXmlReader.fromString(xml)); + ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(XmlReader.fromString(xml)); validateSegmentResponse(expected, actual); } @@ -171,7 +171,7 @@ public void metadataListing() throws XMLStreamException { .setContainerName("42735743042735743c8d29610ac1e2478dbcc4df1a99") .setSegment(new BlobFlatListSegment().setBlobItems(expectedBlobs)); - ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(DefaultXmlReader.fromString(xml)); + ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(XmlReader.fromString(xml)); validateSegmentResponse(expected, actual); } @@ -253,7 +253,7 @@ public void tagsListing() throws XMLStreamException { .setContainerName("3f9c116203f9c11629bd22488e44f35974dcc48c2aa0") .setSegment(new BlobFlatListSegment().setBlobItems(expectedBlobs)); - ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(DefaultXmlReader.fromString(xml)); + ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(XmlReader.fromString(xml)); validateSegmentResponse(expected, actual); } @@ -320,7 +320,7 @@ public void restApiExample() throws XMLStreamException { .setMaxResults(5) .setSegment(new BlobFlatListSegment().setBlobItems(expectedBlobs)); - ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(DefaultXmlReader.fromString(xml)); + ListBlobsFlatSegmentResponse actual = ListBlobsFlatSegmentResponse.fromXml(XmlReader.fromString(xml)); validateSegmentResponse(expected, actual); } diff --git a/sdk/servicebus/azure-messaging-servicebus/pom.xml b/sdk/servicebus/azure-messaging-servicebus/pom.xml index 35639a5cdc5f..8e374338dc62 100644 --- a/sdk/servicebus/azure-messaging-servicebus/pom.xml +++ b/sdk/servicebus/azure-messaging-servicebus/pom.xml @@ -54,12 +54,12 @@ com.azure azure-core - 1.47.0 + 1.48.0-beta.1 com.azure azure-xml - 1.0.0-beta.3 + 1.0.0-beta.4 com.azure diff --git a/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/administration/implementation/EntityHelper.java b/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/administration/implementation/EntityHelper.java index 31779b923aac..d75fc9296967 100644 --- a/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/administration/implementation/EntityHelper.java +++ b/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/administration/implementation/EntityHelper.java @@ -28,7 +28,6 @@ import com.azure.messaging.servicebus.administration.models.SharedAccessAuthorizationRule; import com.azure.messaging.servicebus.administration.models.SubscriptionProperties; import com.azure.messaging.servicebus.administration.models.TopicProperties; -import com.azure.xml.XmlProviders; import com.azure.xml.XmlReader; import javax.xml.stream.XMLStreamException; @@ -651,11 +650,11 @@ public static Response deserializeQueueFeed(Response(response, entry); } catch (IllegalStateException ex) { - try (XmlReader xmlReader = XmlProviders.createReader(responseBody)) { + try (XmlReader xmlReader = XmlReader.fromString(responseBody)) { TopicDescriptionFeedImpl entryTopic = TopicDescriptionFeedImpl.fromXml(xmlReader); logger.atWarning() .addKeyValue("entityName", entryTopic.getTitle()) @@ -682,7 +681,7 @@ public static Response deserializeQueueFeed(Response deserializeQueue(Response response, ClientLogger logger) { String responseBody = response.getValue().toString(); - try (XmlReader xmlReader = XmlProviders.createReader(responseBody)) { + try (XmlReader xmlReader = XmlReader.fromString(responseBody)) { QueueDescriptionEntryImpl entry = QueueDescriptionEntryImpl.fromXml(xmlReader); // This was an empty response (ie. 204). if (entry == null) { @@ -700,7 +699,7 @@ public static Response deserializeQueue(Response respon return new SimpleResponse<>(response, result); } catch (IllegalStateException ex) { - try (XmlReader xmlReader = XmlProviders.createReader(responseBody)) { + try (XmlReader xmlReader = XmlReader.fromString(responseBody)) { TopicDescriptionEntryImpl entryTopic = TopicDescriptionEntryImpl.fromXml(xmlReader); logger.atWarning() .addKeyValue("entityName", entryTopic.getTitle()) @@ -728,11 +727,11 @@ public static Response deserializeTopicFeed(Response(response, entry); } catch (IllegalStateException ex) { - try (XmlReader xmlReader = XmlProviders.createReader(responseBody)) { + try (XmlReader xmlReader = XmlReader.fromString(responseBody)) { QueueDescriptionFeedImpl entryTopic = QueueDescriptionFeedImpl.fromXml(xmlReader); logger.atWarning() .addKeyValue("entityName", entryTopic.getTitle()) @@ -759,7 +758,7 @@ public static Response deserializeTopicFeed(Response deserializeTopic(Response response, ClientLogger logger) { String responseBody = response.getValue().toString(); - try (XmlReader xmlReader = XmlProviders.createReader(responseBody)) { + try (XmlReader xmlReader = XmlReader.fromString(responseBody)) { TopicDescriptionEntryImpl entry = TopicDescriptionEntryImpl.fromXml(xmlReader); // This was an empty response (ie. 204). if (entry == null) { @@ -777,7 +776,7 @@ public static Response deserializeTopic(Response respon return new SimpleResponse<>(response, result); } catch (IllegalStateException ex) { - try (XmlReader xmlReader = XmlProviders.createReader(responseBody)) { + try (XmlReader xmlReader = XmlReader.fromString(responseBody)) { QueueDescriptionEntryImpl entryQueue = QueueDescriptionEntryImpl.fromXml(xmlReader); logger.atWarning() .addKeyValue("entityName", entryQueue.getTitle()) diff --git a/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/administration/ServiceBusAdministrationAsyncClientTest.java b/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/administration/ServiceBusAdministrationAsyncClientTest.java index bb74da09f7a6..e1b4f2ae87da 100644 --- a/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/administration/ServiceBusAdministrationAsyncClientTest.java +++ b/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/administration/ServiceBusAdministrationAsyncClientTest.java @@ -36,7 +36,6 @@ import com.azure.messaging.servicebus.administration.models.CreateQueueOptions; import com.azure.messaging.servicebus.administration.models.QueueProperties; import com.azure.messaging.servicebus.administration.models.QueueRuntimeProperties; -import com.azure.xml.XmlProviders; import com.azure.xml.XmlSerializable; import com.azure.xml.XmlWriter; import io.netty.handler.codec.http.HttpResponseStatus; @@ -731,7 +730,7 @@ static boolean verifyAdditionalAuthHeaderPresent(Context context, HttpHeaderName static String serializeResponse(XmlSerializable response) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - XmlWriter xmlWriter = XmlProviders.createWriter(outputStream)) { + XmlWriter xmlWriter = XmlWriter.toStream(outputStream)) { xmlWriter.writeXml(response).flush(); return outputStream.toString(); } catch (IOException | XMLStreamException e) { diff --git a/sdk/tables/azure-data-tables/pom.xml b/sdk/tables/azure-data-tables/pom.xml index cc3645cdf4a9..854f8d89d647 100644 --- a/sdk/tables/azure-data-tables/pom.xml +++ b/sdk/tables/azure-data-tables/pom.xml @@ -47,7 +47,7 @@ Licensed under the MIT License. com.azure azure-core - 1.47.0 + 1.48.0-beta.1 com.azure @@ -62,7 +62,7 @@ Licensed under the MIT License. com.azure azure-xml - 1.0.0-beta.3 + 1.0.0-beta.4 org.junit.jupiter