You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
645 lines
25 KiB
645 lines
25 KiB
5 years ago
|
/*
|
||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
||
|
*
|
||
|
* Copyright (c) 2006-2017 Oracle and/or its affiliates. All rights reserved.
|
||
|
*
|
||
|
* The contents of this file are subject to the terms of either the GNU
|
||
|
* General Public License Version 2 only ("GPL") or the Common Development
|
||
|
* and Distribution License("CDDL") (collectively, the "License"). You
|
||
|
* may not use this file except in compliance with the License. You can
|
||
|
* obtain a copy of the License at
|
||
|
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
|
||
|
* or LICENSE.txt. See the License for the specific
|
||
|
* language governing permissions and limitations under the License.
|
||
|
*
|
||
|
* When distributing the software, include this License Header Notice in each
|
||
|
* file and include the License file at LICENSE.txt.
|
||
|
*
|
||
|
* GPL Classpath Exception:
|
||
|
* Oracle designates this particular file as subject to the "Classpath"
|
||
|
* exception as provided by Oracle in the GPL Version 2 section of the License
|
||
|
* file that accompanied this code.
|
||
|
*
|
||
|
* Modifications:
|
||
|
* If applicable, add the following below the License Header, with the fields
|
||
|
* enclosed by brackets [] replaced by your own identifying information:
|
||
|
* "Portions Copyright [year] [name of copyright owner]"
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
* If you wish your version of this file to be governed by only the CDDL or
|
||
|
* only the GPL Version 2, indicate your decision by adding "[Contributor]
|
||
|
* elects to include this software in this distribution under the [CDDL or GPL
|
||
|
* Version 2] license." If you don't indicate a single choice of license, a
|
||
|
* recipient has the option to distribute your version of this file under
|
||
|
* either the CDDL, the GPL Version 2 or to extend the choice of license to
|
||
|
* its licensees as provided above. However, if you add GPL Version 2 code
|
||
|
* and therefore, elected the GPL Version 2 license, then the option applies
|
||
|
* only if the new code is made subject to such option by the copyright
|
||
|
* holder.
|
||
|
*/
|
||
|
|
||
|
package javax.xml.bind;
|
||
|
|
||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||
|
import javax.xml.namespace.QName;
|
||
|
import javax.xml.transform.Result;
|
||
|
import javax.xml.transform.Source;
|
||
|
import javax.xml.transform.stream.StreamResult;
|
||
|
import javax.xml.transform.stream.StreamSource;
|
||
|
import java.beans.Introspector;
|
||
|
import java.io.File;
|
||
|
import java.io.IOException;
|
||
|
import java.io.InputStream;
|
||
|
import java.io.OutputStream;
|
||
|
import java.io.Reader;
|
||
|
import java.io.Writer;
|
||
|
import java.lang.ref.WeakReference;
|
||
|
import java.net.HttpURLConnection;
|
||
|
import java.net.URI;
|
||
|
import java.net.URISyntaxException;
|
||
|
import java.net.URL;
|
||
|
import java.net.URLConnection;
|
||
|
|
||
|
/**
|
||
|
* Class that defines convenience methods for common, simple use of JAXB.
|
||
|
*
|
||
|
* <p>
|
||
|
* Methods defined in this class are convenience methods that combine several basic operations
|
||
|
* in the {@link JAXBContext}, {@link Unmarshaller}, and {@link Marshaller}.
|
||
|
*
|
||
|
* They are designed
|
||
|
* to be the prefered methods for developers new to JAXB. They have
|
||
|
* the following characterstics:
|
||
|
*
|
||
|
* <ol>
|
||
|
* <li>Generally speaking, the performance is not necessarily optimal.
|
||
|
* It is expected that people who need to write performance
|
||
|
* critical code will use the rest of the JAXB API directly.
|
||
|
* <li>Errors that happen during the processing is wrapped into
|
||
|
* {@link DataBindingException} (which will have {@link JAXBException}
|
||
|
* as its {@link Throwable#getCause() cause}. It is expected that
|
||
|
* people who prefer the checked exception would use
|
||
|
* the rest of the JAXB API directly.
|
||
|
* </ol>
|
||
|
*
|
||
|
* <p>
|
||
|
* In addition, the {@code unmarshal} methods have the following characteristic:
|
||
|
*
|
||
|
* <ol>
|
||
|
* <li>Schema validation is not performed on the input XML.
|
||
|
* The processing will try to continue even if there
|
||
|
* are errors in the XML, as much as possible. Only as
|
||
|
* the last resort, this method fails with {@link DataBindingException}.
|
||
|
* </ol>
|
||
|
*
|
||
|
* <p>
|
||
|
* Similarly, the {@code marshal} methods have the following characteristic:
|
||
|
* <ol>
|
||
|
* <li>The processing will try to continue even if the Java object tree
|
||
|
* does not meet the validity requirement. Only as
|
||
|
* the last resort, this method fails with {@link DataBindingException}.
|
||
|
* </ol>
|
||
|
*
|
||
|
*
|
||
|
* <p>
|
||
|
* All the methods on this class require non-null arguments to all parameters.
|
||
|
* The {@code unmarshal} methods either fail with an exception or return
|
||
|
* a non-null value.
|
||
|
*
|
||
|
* @author Kohsuke Kawaguchi
|
||
|
* @since 1.6, JAXB 2.1
|
||
|
*/
|
||
|
public final class JAXB {
|
||
|
/**
|
||
|
* No instanciation is allowed.
|
||
|
*/
|
||
|
private JAXB() {}
|
||
|
|
||
|
/**
|
||
|
* To improve the performance, we'll cache the last {@link JAXBContext} used.
|
||
|
*/
|
||
|
private static final class Cache {
|
||
|
final Class type;
|
||
|
final JAXBContext context;
|
||
|
|
||
|
public Cache(Class type) throws JAXBException {
|
||
|
this.type = type;
|
||
|
this.context = JAXBContext.newInstance(type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Cache. We don't want to prevent the {@link Cache#type} from GC-ed,
|
||
|
* hence {@link WeakReference}.
|
||
|
*/
|
||
|
private static volatile WeakReference<Cache> cache;
|
||
|
|
||
|
/**
|
||
|
* Obtains the {@link JAXBContext} from the given type,
|
||
|
* by using the cache if possible.
|
||
|
*
|
||
|
* <p>
|
||
|
* We don't use locks to control access to {@link #cache}, but this code
|
||
|
* should be thread-safe thanks to the immutable {@link Cache} and {@code volatile}.
|
||
|
*/
|
||
|
private static <T> JAXBContext getContext(Class<T> type) throws JAXBException {
|
||
|
WeakReference<Cache> c = cache;
|
||
|
if(c!=null) {
|
||
|
Cache d = c.get();
|
||
|
if(d!=null && d.type==type)
|
||
|
return d.context;
|
||
|
}
|
||
|
|
||
|
// overwrite the cache
|
||
|
Cache d = new Cache(type);
|
||
|
cache = new WeakReference<Cache>(d);
|
||
|
|
||
|
return d.context;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* Reads the entire file as XML.
|
||
|
*/
|
||
|
public static <T> T unmarshal( File xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(new StreamSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The resource pointed by the URL is read in its entirety.
|
||
|
*/
|
||
|
public static <T> T unmarshal( URL xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The URI is {@link URI#toURL() turned into URL} and then
|
||
|
* follows the handling of {@code URL}.
|
||
|
*/
|
||
|
public static <T> T unmarshal( URI xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The string is first interpreted as an absolute {@code URI}.
|
||
|
* If it's not {@link URI#isAbsolute() a valid absolute URI},
|
||
|
* then it's interpreted as a {@code File}
|
||
|
*/
|
||
|
public static <T> T unmarshal( String xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The entire stream is read as an XML infoset.
|
||
|
* Upon a successful completion, the stream will be closed by this method.
|
||
|
*/
|
||
|
public static <T> T unmarshal( InputStream xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The character stream is read as an XML infoset.
|
||
|
* The encoding declaration in the XML will be ignored.
|
||
|
* Upon a successful completion, the stream will be closed by this method.
|
||
|
*/
|
||
|
public static <T> T unmarshal( Reader xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads in a Java object tree from the given XML input.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The XML infoset that the {@link Source} represents is read.
|
||
|
*/
|
||
|
public static <T> T unmarshal( Source xml, Class<T> type ) {
|
||
|
try {
|
||
|
JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type);
|
||
|
return item.getValue();
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Creates {@link Source} from various XML representation.
|
||
|
* See {@link #unmarshal} for the conversion rules.
|
||
|
*/
|
||
|
private static Source toSource(Object xml) throws IOException {
|
||
|
if(xml==null)
|
||
|
throw new IllegalArgumentException("no XML is given");
|
||
|
|
||
|
if (xml instanceof String) {
|
||
|
try {
|
||
|
xml=new URI((String)xml);
|
||
|
} catch (URISyntaxException e) {
|
||
|
xml=new File((String)xml);
|
||
|
}
|
||
|
}
|
||
|
if (xml instanceof File) {
|
||
|
File file = (File) xml;
|
||
|
return new StreamSource(file);
|
||
|
}
|
||
|
if (xml instanceof URI) {
|
||
|
URI uri = (URI) xml;
|
||
|
xml=uri.toURL();
|
||
|
}
|
||
|
if (xml instanceof URL) {
|
||
|
URL url = (URL) xml;
|
||
|
return new StreamSource(url.toExternalForm());
|
||
|
}
|
||
|
if (xml instanceof InputStream) {
|
||
|
InputStream in = (InputStream) xml;
|
||
|
return new StreamSource(in);
|
||
|
}
|
||
|
if (xml instanceof Reader) {
|
||
|
Reader r = (Reader) xml;
|
||
|
return new StreamSource(r);
|
||
|
}
|
||
|
if (xml instanceof Source) {
|
||
|
return (Source) xml;
|
||
|
}
|
||
|
throw new IllegalArgumentException("I don't understand how to handle "+xml.getClass());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* XML will be written to this file. If it already exists,
|
||
|
* it will be overwritten.
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, File xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The XML will be {@link URLConnection#getOutputStream() sent} to the
|
||
|
* resource pointed by this URL. Note that not all {@code URL}s support
|
||
|
* such operation, and exact semantics depends on the {@code URL}
|
||
|
* implementations. In case of {@link HttpURLConnection HTTP URLs},
|
||
|
* this will perform HTTP POST.
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, URL xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The URI is {@link URI#toURL() turned into URL} and then
|
||
|
* follows the handling of {@code URL}. See above.
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, URI xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The string is first interpreted as an absolute {@code URI}.
|
||
|
* If it's not {@link URI#isAbsolute() a valid absolute URI},
|
||
|
* then it's interpreted as a {@code File}
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, String xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The XML will be sent to the given {@link OutputStream}.
|
||
|
* Upon a successful completion, the stream will be closed by this method.
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, OutputStream xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The XML will be sent as a character stream to the given {@link Writer}.
|
||
|
* Upon a successful completion, the stream will be closed by this method.
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, Writer xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* The XML will be sent to the {@link Result} object.
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
public static void marshal( Object jaxbObject, Result xml ) {
|
||
|
_marshal(jaxbObject,xml);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Writes a Java object tree to XML and store it to the specified location.
|
||
|
*
|
||
|
* <p>
|
||
|
* This method is a convenience method that combines several basic operations
|
||
|
* in the {@link JAXBContext} and {@link Marshaller}. This method is designed
|
||
|
* to be the prefered method for developers new to JAXB. This method
|
||
|
* has the following characterstics:
|
||
|
*
|
||
|
* <ol>
|
||
|
* <li>Generally speaking, the performance is not necessarily optimal.
|
||
|
* It is expected that those people who need to write performance
|
||
|
* critical code will use the rest of the JAXB API directly.
|
||
|
* <li>Errors that happen during the processing is wrapped into
|
||
|
* {@link DataBindingException} (which will have {@link JAXBException}
|
||
|
* as its {@link Throwable#getCause() cause}. It is expected that
|
||
|
* those people who prefer the checked exception would use
|
||
|
* the rest of the JAXB API directly.
|
||
|
* </ol>
|
||
|
*
|
||
|
* @param jaxbObject
|
||
|
* The Java object to be marshalled into XML. If this object is
|
||
|
* a {@link JAXBElement}, it will provide the root tag name and
|
||
|
* the body. If this object has {@link XmlRootElement}
|
||
|
* on its class definition, that will be used as the root tag name
|
||
|
* and the given object will provide the body. Otherwise,
|
||
|
* the root tag name is {@link Introspector#decapitalize(String) infered} from
|
||
|
* {@link Class#getSimpleName() the short class name}.
|
||
|
* This parameter must not be null.
|
||
|
*
|
||
|
* @param xml
|
||
|
* Represents the receiver of XML. Objects of the following types are allowed.
|
||
|
*
|
||
|
* <table><tr>
|
||
|
* <th>Type</th>
|
||
|
* <th>Operation</th>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link File}</td>
|
||
|
* <td>XML will be written to this file. If it already exists,
|
||
|
* it will be overwritten.</td>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link URL}</td>
|
||
|
* <td>The XML will be {@link URLConnection#getOutputStream() sent} to the
|
||
|
* resource pointed by this URL. Note that not all {@code URL}s support
|
||
|
* such operation, and exact semantics depends on the {@code URL}
|
||
|
* implementations. In case of {@link HttpURLConnection HTTP URLs},
|
||
|
* this will perform HTTP POST.</td>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link URI}</td>
|
||
|
* <td>The URI is {@link URI#toURL() turned into URL} and then
|
||
|
* follows the handling of {@code URL}. See above.</td>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link String}</td>
|
||
|
* <td>The string is first interpreted as an absolute {@code URI}.
|
||
|
* If it's not {@link URI#isAbsolute() a valid absolute URI},
|
||
|
* then it's interpreted as a {@code File}</td>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link OutputStream}</td>
|
||
|
* <td>The XML will be sent to the given {@link OutputStream}.
|
||
|
* Upon a successful completion, the stream will be closed by this method.</td>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link Writer}</td>
|
||
|
* <td>The XML will be sent as a character stream to the given {@link Writer}.
|
||
|
* Upon a successful completion, the stream will be closed by this method.</td>
|
||
|
* </tr><tr>
|
||
|
* <td>{@link Result}</td>
|
||
|
* <td>The XML will be sent to the {@link Result} object.</td>
|
||
|
* </tr></table>
|
||
|
*
|
||
|
* @throws DataBindingException
|
||
|
* If the operation fails, such as due to I/O error, unbindable classes.
|
||
|
*/
|
||
|
private static void _marshal( Object jaxbObject, Object xml ) {
|
||
|
try {
|
||
|
JAXBContext context;
|
||
|
|
||
|
if(jaxbObject instanceof JAXBElement) {
|
||
|
context = getContext(((JAXBElement<?>)jaxbObject).getDeclaredType());
|
||
|
} else {
|
||
|
Class<?> clazz = jaxbObject.getClass();
|
||
|
XmlRootElement r = clazz.getAnnotation(XmlRootElement.class);
|
||
|
context = getContext(clazz);
|
||
|
if(r==null) {
|
||
|
// we need to infer the name
|
||
|
jaxbObject = new JAXBElement(new QName(inferName(clazz)),clazz,jaxbObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Marshaller m = context.createMarshaller();
|
||
|
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true);
|
||
|
m.marshal(jaxbObject, toResult(xml));
|
||
|
} catch (JAXBException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
} catch (IOException e) {
|
||
|
throw new DataBindingException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static String inferName(Class clazz) {
|
||
|
return Introspector.decapitalize(clazz.getSimpleName());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates {@link Result} from various XML representation.
|
||
|
* See {@link #_marshal(Object,Object)} for the conversion rules.
|
||
|
*/
|
||
|
private static Result toResult(Object xml) throws IOException {
|
||
|
if(xml==null)
|
||
|
throw new IllegalArgumentException("no XML is given");
|
||
|
|
||
|
if (xml instanceof String) {
|
||
|
try {
|
||
|
xml=new URI((String)xml);
|
||
|
} catch (URISyntaxException e) {
|
||
|
xml=new File((String)xml);
|
||
|
}
|
||
|
}
|
||
|
if (xml instanceof File) {
|
||
|
File file = (File) xml;
|
||
|
return new StreamResult(file);
|
||
|
}
|
||
|
if (xml instanceof URI) {
|
||
|
URI uri = (URI) xml;
|
||
|
xml=uri.toURL();
|
||
|
}
|
||
|
if (xml instanceof URL) {
|
||
|
URL url = (URL) xml;
|
||
|
URLConnection con = url.openConnection();
|
||
|
con.setDoOutput(true);
|
||
|
con.setDoInput(false);
|
||
|
con.connect();
|
||
|
return new StreamResult(con.getOutputStream());
|
||
|
}
|
||
|
if (xml instanceof OutputStream) {
|
||
|
OutputStream os = (OutputStream) xml;
|
||
|
return new StreamResult(os);
|
||
|
}
|
||
|
if (xml instanceof Writer) {
|
||
|
Writer w = (Writer)xml;
|
||
|
return new StreamResult(w);
|
||
|
}
|
||
|
if (xml instanceof Result) {
|
||
|
return (Result) xml;
|
||
|
}
|
||
|
throw new IllegalArgumentException("I don't understand how to handle "+xml.getClass());
|
||
|
}
|
||
|
|
||
|
}
|