| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.xml; |
| |
| import java.util.Map; |
| import java.util.Locale; |
| import java.util.TimeZone; |
| import java.util.Collections; |
| import java.util.logging.Filter; |
| import java.util.logging.LogRecord; // For javadoc |
| import java.net.URL; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.StandardOpenOption; |
| import javax.xml.bind.Marshaller; |
| import javax.xml.bind.Unmarshaller; |
| import javax.xml.bind.JAXBElement; |
| import javax.xml.bind.JAXBException; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.stax.StAXSource; |
| import javax.xml.transform.stax.StAXResult; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.stream.XMLStreamWriter; |
| import org.apache.sis.util.Static; |
| import org.apache.sis.util.Version; |
| import org.apache.sis.util.Workaround; |
| import org.apache.sis.util.resources.Errors; |
| import org.apache.sis.internal.system.Modules; |
| import org.apache.sis.internal.system.SystemListener; |
| import org.apache.sis.internal.jaxb.TypeRegistration; |
| |
| import static org.apache.sis.util.ArgumentChecks.ensureNonNull; |
| |
| |
| /** |
| * Provides convenience methods for marshalling and unmarshalling SIS objects. |
| * Marshalling operations use the standard versions listed below |
| * (for marshalling a document in a different version, see {@link MarshallerPool}). |
| * Unmarshalling detects the version automatically. |
| * |
| * <table class="sis"> |
| * <caption>Versions of standards applied at marshalling time</caption> |
| * <tr><th>Topic</th> <th>SIS 0.3 to 0.8</th> <th>SIS 1.0</th> <th>Remarks</th></tr> |
| * <tr><td>Metadata</td> <td>ISO 19139:2007</td> <td>ISO 19115-3:2016</td> <td></td></tr> |
| * <tr><td>Referencing</td> <td>ISO 19136:2007</td> <td>ISO 19136:2007</td> <td>Same as GML 3.2</td></tr> |
| * </table> |
| * |
| * This class defines also some property keys that can be given to the {@link Marshaller} |
| * and {@link Unmarshaller} instances created by {@link MarshallerPool}: |
| * |
| * <table class="sis"> |
| * <caption>Supported (un)marshaller properties</caption> |
| * <tr><th>Key</th> <th>Value type</th> <th>Purpose</th></tr> |
| * <tr><td>{@link #LOCALE}</td> <td>{@link Locale}</td> <td>for specifying the locale to use for international strings and code lists.</td></tr> |
| * <tr><td>{@link #TIMEZONE}</td> <td>{@link TimeZone}</td> <td>for specifying the timezone to use for dates and times.</td></tr> |
| * <tr><td>{@link #SCHEMAS}</td> <td>{@link Map}</td> <td>for specifying the root URL of metadata schemas to use.</td></tr> |
| * <tr><td>{@link #GML_VERSION}</td> <td>{@link Version}</td> <td>for specifying the GML version of the document to be (un)marshalled.</td></tr> |
| * <tr><td>{@link #METADATA_VERSION}</td> <td>{@link Version}</td> <td>for specifying the metadata version of the document to be (un)marshalled.</td></tr> |
| * <tr><td>{@link #RESOLVER}</td> <td>{@link ReferenceResolver}</td> <td>for replacing {@code xlink} or {@code uuidref} attributes by the actual object to use.</td></tr> |
| * <tr><td>{@link #CONVERTER}</td> <td>{@link ValueConverter}</td> <td>for controlling the conversion of URL, UUID, Units or similar objects.</td></tr> |
| * <tr><td>{@link #STRING_SUBSTITUTES}</td> <td>{@code String[]}</td> <td>for specifying which code lists to replace by simpler {@code <gco:CharacterString>} elements.</td></tr> |
| * <tr><td>{@link #WARNING_FILTER}</td> <td>{@link Filter}</td> <td>for being notified about non-fatal warnings.</td></tr> |
| * </table> |
| * |
| * @author Cédric Briançon (Geomatys) |
| * @author Martin Desruisseaux (Geomatys) |
| * @author Cullen Rombach (Image Matters) |
| * @version 1.1 |
| * @since 0.3 |
| * @module |
| */ |
| public final class XML extends Static { |
| /** |
| * Specifies the locale to use for marshalling |
| * {@link org.opengis.util.InternationalString} and {@link org.opengis.util.CodeList} |
| * instances. The value for this property shall be an instance of {@link Locale} or a |
| * {@link CharSequence} recognized by {@link org.apache.sis.util.Locales#parse(String)}. |
| * |
| * <p>This property is mostly for marshallers. However this property can also be used at |
| * unmarshalling time, for example if a {@code <lan:PT_FreeText>} element containing |
| * many localized strings need to be represented in a Java {@link String} object. In |
| * such case, the unmarshaller will try to pickup a string in the language specified |
| * by this property.</p> |
| * |
| * <h4>Default behavior</h4> |
| * If this property is never set, then (un)marshalling will try to use "unlocalized" strings - |
| * typically some programmatic strings like {@linkplain org.opengis.annotation.UML#identifier() |
| * UML identifiers}. While such identifiers often look like English words, they are not |
| * considered as the {@linkplain Locale#ENGLISH English} localization. |
| * The algorithm attempting to find a "unlocalized" string is defined in the |
| * {@link org.apache.sis.util.iso.DefaultInternationalString#toString(Locale)} javadoc. |
| * |
| * <h4>Special case</h4> |
| * If the object to be marshalled is an instance of |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata}, then the value given to its |
| * {@link org.apache.sis.metadata.iso.DefaultMetadata#setLanguage(Locale) setLanguage(Locale)} |
| * method will have precedence over this property. This behavior is compliant with INSPIRE rules. |
| * |
| * @see org.apache.sis.setup.OptionKey#LOCALE |
| * @see Marshaller#setProperty(String, Object) |
| * @see org.apache.sis.metadata.iso.DefaultMetadata#setLanguage(Locale) |
| */ |
| public static final String LOCALE = "org.apache.sis.xml.locale"; |
| |
| /** |
| * Specifies the timezone to use for marshalling dates and times. |
| * The value for this property shall be an instance of {@link TimeZone} |
| * or a {@link CharSequence} recognized by {@link TimeZone#getTimeZone(String)}. |
| * |
| * <h4>Default behavior</h4> |
| * If this property is never set, then (un)marshalling will use the |
| * {@linkplain TimeZone#getDefault() default timezone}. |
| * |
| * @see org.apache.sis.setup.OptionKey#TIMEZONE |
| */ |
| public static final String TIMEZONE = "org.apache.sis.xml.timezone"; |
| |
| /** |
| * Specifies the root URL of schemas. The value for this property shall |
| * be an instance of {@link Map Map<String,String>}. |
| * This property controls the URL to be used when marshalling the following elements: |
| * |
| * <ul> |
| * <li>The value of the {@code codeList} attribute when marshalling subclasses of |
| * {@link org.opengis.util.CodeList}.</li> |
| * <li>The value of the {@code uom} attribute when marshalling measures |
| * (for example {@code <gco:Distance>}).</li> |
| * </ul> |
| * |
| * Two {@code Map} keys are currently recognized: {@code "cat"} and {@code "gmd"}, |
| * which stands for the new ISO 19115-3:2016 and the legacy ISO 19139:2007 schemas respectively. |
| * The key to be used depends on the {@linkplain #METADATA_VERSION metadata version} to be marshalled. |
| * Additional keys, if any, are ignored. Future SIS versions may recognize more keys. |
| * |
| * <h4>Valid values</h4> |
| * The following table gives some typical URLs. |
| * The URL in bold character is the default one. |
| * |
| * <table class="sis"> |
| * <caption>Supported schemas</caption> |
| * <tr><th>Map key</th> <th>Typical values (choose only one)</th></tr> |
| * <tr><td><b>cat</b></td><td> |
| * <b>http://standards.iso.org/iso/19115/</b> |
| * </td></tr> |
| * <tr><td><b>gmd</b></td><td> |
| * http://www.isotc211.org/2005/<br> |
| * <b>http://schemas.opengis.net/iso/19139/20070417/</b><br> |
| * http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/<br> |
| * http://eden.ign.fr/xsd/fra/20060922/ |
| * </td></tr> |
| * </table> |
| */ |
| public static final String SCHEMAS = "org.apache.sis.xml.schemas"; |
| // If more keys are documented, update the Pooled.SCHEMAS_KEY array. |
| |
| /** |
| * Specifies the GML version of the document to be marshalled or unmarshalled. |
| * The GML version may affect the set of XML elements to be marshalled and their namespaces. |
| * Note that GML 3.2 is identical to ISO 19136:2007. |
| * |
| * <div class="note"><b>Compatibility note:</b> |
| * Newer versions typically have more elements, but not always. For example in {@code <gml:VerticalDatum>}, |
| * the {@code <gml:verticalDatumType>} property presents in GML 3.0 and 3.1 has been removed in GML 3.2.</div> |
| * |
| * The value can be {@link String} or {@link Version} object. |
| * If no version is specified, then the most recent supported GML version is assumed. |
| * |
| * <h4>Supported GML versions</h4> |
| * Apache SIS currently supports GML 3.2.1 by default. SIS can read and write GML 3.2 |
| * if this property is set to "3.2". It is also possible to set this property to "3.1", |
| * but the marshalled XML is not GML 3.1.1 conformant because of the differences between the two schemas. |
| * See <a href="http://issues.apache.org/jira/browse/SIS-160">SIS-160: Need XSLT between GML 3.1 and 3.2</a> |
| * for information about the status of GML 3.1.1 support. |
| */ |
| public static final String GML_VERSION = "org.apache.sis.gml.version"; |
| |
| /** |
| * Specifies the metadata version of the document to be marshalled or unmarshalled. |
| * The metadata version may affect the set of XML elements to be marshalled and their namespaces. |
| * The value can be {@link String} or {@link Version} object. |
| * If no version is specified, then the most recent supported metadata version is assumed. |
| * |
| * <p>The metadata version may be ignored when the metadata to marshal is inside a GML element. |
| * For example the {@code <gml:domainOfValidity>} element inside a coordinate reference system |
| * is always marshalled using ISO 19139:2007 if the enclosing element uses GML 3.2 schema.</p> |
| * |
| * <h4>Supported metadata versions</h4> |
| * Apache SIS currently supports ISO 19115-3:2016 by default. This version can be explicitly |
| * set with value "2014" or above (because the abstract model was defined in ISO 19115-1:2014). |
| * SIS can write legacy ISO 19139:2007 documents if this property is set to a value less than "2014". |
| * Both versions can be read without the need to specify this property. |
| * |
| * @since 1.0 |
| */ |
| public static final String METADATA_VERSION = "org.apache.sis.xml.version.metadata"; |
| |
| /** |
| * Specifies whether the unmarshalling process should accept any metadata or GML supported version |
| * if the user did not specified an explicit version. The value can be a {@link Boolean} instance, |
| * or {@code "true"} or {@code "false"} as a {@link String}. If this value is not specified, then |
| * the default is {@code true} for all {@code XML.unmarshal} methods and {@code false} otherwise. |
| * |
| * <p>Metadata and Geographic Markup Language have slightly different XML encoding depending on the |
| * OGC/ISO version in use. Often the namespaces are different, but not only. Internally, Apache SIS |
| * supports only the schema versions documented in this {@linkplain XML class javadoc}, for example |
| * the ISO 19115-3:2016 version of metadata schema. For unmarshalling a document encoded according |
| * an older metadata schema (e.g. ISO 19139:2007), a transformation is applied on-the-fly. However |
| * this transformation may sometime produce undesirable results or make debugging more difficult. |
| * For this reason {@link MarshallerPool} applies the transformation only if explicitly requested, |
| * either by setting a {@link #METADATA_VERSION} or {@link #GML_VERSION} explicitly, or by setting |
| * this {@code LENIENT_UNMARSHAL} property to {@code true} if the version to unmarshal is not known |
| * in advance.</p> |
| * |
| * @since 1.0 |
| */ |
| public static final String LENIENT_UNMARSHAL = "org.apache.sis.xml.lenient"; |
| |
| /** |
| * Allows client code to replace {@code xlink} or {@code uuidref} attributes by the actual objects to use. |
| * The value for this property shall be an instance of {@link ReferenceResolver}. |
| * |
| * <p>If a property in a XML document is defined only by {@code xlink} or {@code uuidref} attributes, |
| * without any concrete definition, then the default behavior is as below:</p> |
| * |
| * <ul> |
| * <li>If the reference is of the form {@code xlink:href="#foo"} and an object with the {@code gml:id="foo"} |
| * attribute was previously found in the same XML document, then that object will be used.</li> |
| * <li>Otherwise an empty element containing only the values of the above-cited attributes is created.</li> |
| * </ul> |
| * |
| * Applications can sometime do better by using some domain-specific knowledge, for example by searching in a |
| * database. Users can define their search algorithm by subclassing {@link ReferenceResolver} and configuring |
| * a unmarshaller as below: |
| * |
| * {@preformat java |
| * ReferenceResolver myResolver = ...; |
| * Map<String,Object> properties = new HashMap<>(); |
| * properties.put(XML.RESOLVER, myResolver); |
| * Object obj = XML.unmarshal(source, properties); |
| * } |
| * |
| * @see Unmarshaller#setProperty(String, Object) |
| * @see ReferenceResolver |
| */ |
| public static final String RESOLVER = "org.apache.sis.xml.resolver"; |
| |
| /** |
| * Controls the behaviors of the (un)marshalling process when an element can not be processed, |
| * or alter the element values. The value for this property shall be an instance of {@link ValueConverter}. |
| * |
| * <p>If an element in a XML document can not be parsed (for example if a {@linkplain java.net.URL} |
| * string is not valid), the default behavior is to throw an exception which cause the |
| * (un)marshalling of the entire document to fail. This default behavior can be customized by |
| * invoking {@link Marshaller#setProperty(String, Object)} with this {@code CONVERTER} property |
| * key and a custom {@link ValueConverter} instance. {@code ValueConverter} can also be used |
| * for replacing an erroneous URL by a fixed URL. See the {@link ValueConverter} javadoc for |
| * more details.</p> |
| * |
| * <div class="note"><b>Example:</b> |
| * the following example collects the failures in a list without stopping the (un)marshalling process. |
| * |
| * {@preformat java |
| * class WarningCollector extends ValueConverter { |
| * // The warnings collected during (un)marshalling. |
| * List<String> messages = new ArrayList<String>(); |
| * |
| * // Override the default implementation in order to |
| * // collect the warnings and allow the process to continue. |
| * @Override |
| * protected <T> boolean exceptionOccured(MarshalContext context, |
| * T value, Class<T> sourceType, Class<T> targetType, Exception e) |
| * { |
| * mesages.add(e.getLocalizedMessage()); |
| * return true; |
| * } |
| * } |
| * |
| * // Unmarshal a XML string, trapping some kind of errors. |
| * // Not all errors are trapped - see the ValueConverter |
| * // javadoc for more details. |
| * WarningCollector myWarningList = new WarningCollector(); |
| * Map<String,Object> properties = new HashMap<>(); |
| * properties.put(XML.CONVERTER, myWarningList); |
| * Object obj = XML.unmarshal(source, properties); |
| * if (!myWarningList.isEmpty()) { |
| * // Report here the warnings to the user. |
| * } |
| * } |
| * </div> |
| * |
| * @see Unmarshaller#setProperty(String, Object) |
| * @see ValueConverter |
| */ |
| public static final String CONVERTER = "org.apache.sis.xml.converter"; |
| |
| /** |
| * Allows marshallers to substitute some code lists by the simpler {@code <gco:CharacterString>} element. |
| * The value for this property shall be a {@code String[]} array of any of the following values: |
| * |
| * <ul> |
| * <li>"{@code language}" for substituting {@code <lan:LanguageCode>} elements</li> |
| * <li>"{@code country}" for substituting {@code <lan:Country>} elements</li> |
| * <li>"{@code filename}" for substituting {@code <gcx:FileName>} elements</li> |
| * <li>"{@code mimetype}" for substituting {@code <gcx:MimeFileType>} elements</li> |
| * </ul> |
| * |
| * <div class="note"><b>Example:</b> |
| * INSPIRE compliant language code shall be formatted like below (details may vary): |
| * |
| * {@preformat xml |
| * <gmd:language> |
| * <gmd:LanguageCode |
| * codeList="http://schemas.opengis.net/iso/19139/20070417/resources/Codelist/gmxCodelists.xml#LanguageCode" |
| * codeListValue="fra">French</gmd:LanguageCode> |
| * </gmd:language> |
| * } |
| * |
| * However if this property contains the "{@code language}" value, then the marshaller will format |
| * the language code like below (which is legal according OGC schemas, but is not INSPIRE compliant): |
| * |
| * {@preformat xml |
| * <lan:language> |
| * <gco:CharacterString>fra</gco:CharacterString> |
| * </lan:language> |
| * } |
| * </div> |
| */ |
| public static final String STRING_SUBSTITUTES = "org.apache.sis.xml.stringSubstitutes"; |
| |
| /** |
| * Specifies a listener to be notified when a non-fatal error occurred during the (un)marshalling. |
| * The value for this property shall be an instance of {@link Filter}. |
| * |
| * <p>By default, warnings that occur during the (un)marshalling process are logged. However if a |
| * property is set for this key, then the {@link Filter#isLoggable(LogRecord)} method will be invoked. |
| * If that method returns {@code false}, then the warning will not be logged by the (un)marshaller.</p> |
| * |
| * @since 1.0 |
| */ |
| public static final String WARNING_FILTER = "org.apache.sis.xml.warningFilter"; |
| |
| /** |
| * The pool of marshallers and unmarshallers used by this class. |
| * The field name uses the uppercase convention because this field is almost constant: |
| * this field is initially null, then created by {@link #getPool()} when first needed. |
| * Once created the field value usually doesn't change. However the field may be reset |
| * to {@code null} in an OSGi context when modules are loaded or unloaded, because the |
| * set of classes returned by {@link TypeRegistration#load(boolean)} may have changed. |
| * |
| * @see #getPool() |
| */ |
| private static volatile MarshallerPool POOL; |
| |
| /** |
| * Registers a listener for classpath changes. In such case, a new pool will need to |
| * be created because the {@code JAXBContext} may be different. |
| */ |
| static { |
| SystemListener.add(new SystemListener(Modules.UTILITIES) { |
| @Override protected void classpathChanged() { |
| POOL = null; |
| } |
| }); |
| } |
| |
| /** |
| * Do not allow instantiation on this class. |
| */ |
| private XML() { |
| } |
| |
| /** |
| * Returns the default (un)marshaller pool used by all methods in this class. |
| * |
| * <div class="note"><b>Implementation note:</b> |
| * Current implementation uses the double-check idiom. This is usually a deprecated practice |
| * (the recommended alterative is to use static class initialization), but in this particular |
| * case the field may be reset to {@code null} if OSGi modules are loaded or unloaded, so static |
| * class initialization would be a little bit too rigid.</div> |
| */ |
| @SuppressWarnings("DoubleCheckedLocking") |
| private static MarshallerPool getPool() throws JAXBException { |
| MarshallerPool pool = POOL; |
| if (pool == null) { |
| synchronized (XML.class) { |
| pool = POOL; // Double-check idiom: see javadoc. |
| if (pool == null) { |
| POOL = pool = new MarshallerPool(Collections.singletonMap(LENIENT_UNMARSHAL, Boolean.TRUE)); |
| } |
| } |
| } |
| return pool; |
| } |
| |
| /** |
| * Marshal the given object into a string. |
| * |
| * @param object the root of content tree to be marshalled. |
| * @return the XML representation of the given object. |
| * @throws JAXBException if an error occurred during the marshalling. |
| */ |
| public static String marshal(final Object object) throws JAXBException { |
| ensureNonNull("object", object); |
| final StringWriter output = new StringWriter(); |
| final MarshallerPool pool = getPool(); |
| final Marshaller marshaller = pool.acquireMarshaller(); |
| marshaller.marshal(object, output); |
| pool.recycle(marshaller); |
| return output.toString(); |
| } |
| |
| /** |
| * Marshal the given object into a stream. |
| * |
| * @param object the root of content tree to be marshalled. |
| * @param output the stream where to write. |
| * @throws JAXBException if an error occurred during the marshalling. |
| */ |
| public static void marshal(final Object object, final OutputStream output) throws JAXBException { |
| ensureNonNull("object", object); |
| ensureNonNull("output", output); |
| final MarshallerPool pool = getPool(); |
| final Marshaller marshaller = pool.acquireMarshaller(); |
| marshaller.marshal(object, output); |
| pool.recycle(marshaller); |
| } |
| |
| /** |
| * Marshal the given object into a file. |
| * |
| * @param object the root of content tree to be marshalled. |
| * @param output the file to be written. |
| * @throws JAXBException if an error occurred during the marshalling. |
| */ |
| public static void marshal(final Object object, final File output) throws JAXBException { |
| ensureNonNull("object", object); |
| ensureNonNull("output", output); |
| final MarshallerPool pool = getPool(); |
| final Marshaller marshaller = pool.acquireMarshaller(); |
| marshaller.marshal(object, output); |
| pool.recycle(marshaller); |
| } |
| |
| /** |
| * Marshal the given object into a path. |
| * |
| * @param object the root of content tree to be marshalled. |
| * @param output the file to be written. |
| * @throws JAXBException if an error occurred during the marshalling. |
| */ |
| public static void marshal(final Object object, final Path output) throws JAXBException { |
| ensureNonNull("object", object); |
| ensureNonNull("output", output); |
| try (OutputStream out = Files.newOutputStream(output, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { |
| final MarshallerPool pool = getPool(); |
| final Marshaller marshaller = pool.acquireMarshaller(); |
| marshaller.marshal(object, out); |
| pool.recycle(marshaller); |
| } catch (IOException e) { |
| throw new JAXBException(Errors.format(Errors.Keys.CanNotOpen_1, output), e); |
| } |
| } |
| |
| /** |
| * Marshal the given object to a stream, DOM or other destinations. |
| * This is the most flexible marshalling method provided in this {@code XML} class. |
| * The destination is specified by the {@code output} argument implementation, for example |
| * {@link javax.xml.transform.stream.StreamResult} for writing to a file or output stream. |
| * The optional {@code properties} map can contain any key documented in this {@code XML} class, |
| * together with the keys documented in the <cite>supported properties</cite> section of the the |
| * {@link Marshaller} class. |
| * |
| * @param object the root of content tree to be marshalled. |
| * @param output the file to be written. |
| * @param properties an optional map of properties to give to the marshaller, or {@code null} if none. |
| * @throws JAXBException if a property has an illegal value, or if an error occurred during the marshalling. |
| * |
| * @since 0.4 |
| */ |
| public static void marshal(final Object object, final Result output, final Map<String,?> properties) throws JAXBException { |
| ensureNonNull("object", object); |
| ensureNonNull("output", output); |
| final MarshallerPool pool = getPool(); |
| final Marshaller marshaller = pool.acquireMarshaller(); |
| if (properties != null) { |
| for (final Map.Entry<String,?> entry : properties.entrySet()) { |
| marshaller.setProperty(entry.getKey(), entry.getValue()); |
| } |
| } |
| /* |
| * STAX results are not handled by JAXB as of JDK 8. We have to handle those cases ourselves. |
| * This workaround should be removed if a future JDK version handles those cases. |
| */ |
| if (output instanceof StAXResult) { |
| @Workaround(library = "JDK", version = "1.8") |
| final XMLStreamWriter writer = ((StAXResult) output).getXMLStreamWriter(); |
| if (writer != null) { |
| marshaller.marshal(object, writer); |
| } else { |
| marshaller.marshal(object, ((StAXResult) output).getXMLEventWriter()); |
| } |
| } else { |
| marshaller.marshal(object, output); |
| } |
| pool.recycle(marshaller); |
| } |
| |
| /** |
| * Unmarshal an object from the given string. |
| * Note that the given argument is the XML document itself, |
| * <strong>not</strong> a URL to a XML document. |
| * |
| * @param xml the XML representation of an object. |
| * @return the object unmarshalled from the given input. |
| * @throws JAXBException if an error occurred during the unmarshalling. |
| */ |
| public static Object unmarshal(final String xml) throws JAXBException { |
| ensureNonNull("input", xml); |
| final StringReader in = new StringReader(xml); |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(); |
| final Object object = unmarshaller.unmarshal(in); |
| pool.recycle(unmarshaller); |
| return object; |
| } |
| |
| /** |
| * Unmarshal an object from the given stream. |
| * |
| * @param input the stream from which to read a XML representation. |
| * @return the object unmarshalled from the given input. |
| * @throws JAXBException if an error occurred during the unmarshalling. |
| */ |
| public static Object unmarshal(final InputStream input) throws JAXBException { |
| ensureNonNull("input", input); |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(); |
| final Object object = unmarshaller.unmarshal(input); |
| pool.recycle(unmarshaller); |
| return object; |
| } |
| |
| /** |
| * Unmarshal an object from the given URL. |
| * |
| * @param input the URL from which to read a XML representation. |
| * @return the object unmarshalled from the given input. |
| * @throws JAXBException if an error occurred during the unmarshalling. |
| */ |
| public static Object unmarshal(final URL input) throws JAXBException { |
| ensureNonNull("input", input); |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(); |
| final Object object = unmarshaller.unmarshal(input); |
| pool.recycle(unmarshaller); |
| return object; |
| } |
| |
| /** |
| * Unmarshal an object from the given file. |
| * |
| * @param input the file from which to read a XML representation. |
| * @return the object unmarshalled from the given input. |
| * @throws JAXBException if an error occurred during the unmarshalling. |
| */ |
| public static Object unmarshal(final File input) throws JAXBException { |
| ensureNonNull("input", input); |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(); |
| final Object object = unmarshaller.unmarshal(input); |
| pool.recycle(unmarshaller); |
| return object; |
| } |
| |
| /** |
| * Unmarshal an object from the given path. |
| * |
| * @param input the path from which to read a XML representation. |
| * @return the object unmarshalled from the given input. |
| * @throws JAXBException if an error occurred during the unmarshalling. |
| */ |
| public static Object unmarshal(final Path input) throws JAXBException { |
| ensureNonNull("input", input); |
| final Object object; |
| try (InputStream in = Files.newInputStream(input, StandardOpenOption.READ)) { |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(); |
| object = unmarshaller.unmarshal(in); |
| pool.recycle(unmarshaller); |
| } catch (IOException e) { |
| throw new JAXBException(Errors.format(Errors.Keys.CanNotRead_1, input), e); |
| } |
| return object; |
| } |
| |
| /** |
| * Unmarshal an object from the given stream, DOM or other sources. |
| * Together with the {@linkplain #unmarshal(Source, Class, Map) Unmarshal by Declared Type} variant, |
| * this is the most flexible unmarshalling method provided in this {@code XML} class. |
| * The source is specified by the {@code input} argument implementation, for example |
| * {@link javax.xml.transform.stream.StreamSource} for reading from a file or input stream. |
| * The optional {@code properties} map can contain any key documented in this {@code XML} class, |
| * together with the keys documented in the <cite>supported properties</cite> section of the the |
| * {@link Unmarshaller} class. |
| * |
| * @param input the file from which to read a XML representation. |
| * @param properties an optional map of properties to give to the unmarshaller, or {@code null} if none. |
| * @return the object unmarshalled from the given input. |
| * @throws JAXBException if a property has an illegal value, or if an error occurred during the unmarshalling. |
| * |
| * @since 0.4 |
| */ |
| public static Object unmarshal(final Source input, final Map<String,?> properties) throws JAXBException { |
| ensureNonNull("input", input); |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(properties); |
| final Object object; |
| /* |
| * STAX sources are not handled by javax.xml.bind.helpers.AbstractUnmarshallerImpl implementation as of JDK 8. |
| * We have to handle those cases ourselves. This workaround should be removed if a future JDK version handles |
| * those cases. |
| */ |
| if (input instanceof StAXSource) { |
| @Workaround(library = "JDK", version = "1.8") |
| final XMLStreamReader reader = ((StAXSource) input).getXMLStreamReader(); |
| if (reader != null) { |
| object = unmarshaller.unmarshal(reader); |
| } else { |
| object = unmarshaller.unmarshal(((StAXSource) input).getXMLEventReader()); |
| } |
| } else { |
| object = unmarshaller.unmarshal(input); |
| } |
| pool.recycle(unmarshaller); |
| return object; |
| } |
| |
| /** |
| * Unmarshal an object from the given stream, DOM or other sources. |
| * Together with the {@linkplain #unmarshal(Source, Map) Unmarshal Global Root Element} variant, |
| * this is the most flexible unmarshalling method provided in this {@code XML} class. |
| * The source is specified by the {@code input} argument implementation, for example |
| * {@link javax.xml.transform.stream.StreamSource} for reading from a file or input stream. |
| * The optional {@code properties} map can contain any key documented in this {@code XML} class, |
| * together with the keys documented in the <cite>supported properties</cite> section of the the |
| * {@link Unmarshaller} class. |
| * |
| * @param <T> compile-time value of the {@code declaredType} argument. |
| * @param input the file from which to read a XML representation. |
| * @param declaredType the JAXB mapped class of the object to unmarshal. |
| * @param properties an optional map of properties to give to the unmarshaller, or {@code null} if none. |
| * @return the object unmarshalled from the given input, wrapped in a JAXB element. |
| * @throws JAXBException if a property has an illegal value, or if an error occurred during the unmarshalling. |
| * |
| * @since 0.8 |
| */ |
| public static <T> JAXBElement<T> unmarshal(final Source input, final Class<T> declaredType, final Map<String,?> properties) |
| throws JAXBException |
| { |
| ensureNonNull("input", input); |
| ensureNonNull("declaredType", declaredType); |
| final MarshallerPool pool = getPool(); |
| final Unmarshaller unmarshaller = pool.acquireUnmarshaller(properties); |
| final JAXBElement<T> element; |
| if (input instanceof StAXSource) { // Same workaround than the one documented in above method. |
| @Workaround(library = "JDK", version = "1.8") |
| final XMLStreamReader reader = ((StAXSource) input).getXMLStreamReader(); |
| if (reader != null) { |
| element = unmarshaller.unmarshal(reader, declaredType); |
| } else { |
| element = unmarshaller.unmarshal(((StAXSource) input).getXMLEventReader(), declaredType); |
| } |
| } else { |
| element = unmarshaller.unmarshal(input, declaredType); |
| } |
| pool.recycle(unmarshaller); |
| return element; |
| } |
| } |