blob: 91bb5f87f26585d46181f698a70bf6464a9ce7d3 [file] [log] [blame]
/*
* 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&lt;String,String&gt;}.
* 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.
* &#64;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;
}
}