001: package javax.xml.bind;
002:
003: import javax.xml.bind.annotation.XmlRootElement;
004: import javax.xml.namespace.QName;
005: import javax.xml.transform.Result;
006: import javax.xml.transform.Source;
007: import javax.xml.transform.stream.StreamResult;
008: import javax.xml.transform.stream.StreamSource;
009: import java.beans.Introspector;
010: import java.io.File;
011: import java.io.IOException;
012: import java.io.InputStream;
013: import java.io.OutputStream;
014: import java.io.Reader;
015: import java.io.Writer;
016: import java.lang.ref.WeakReference;
017: import java.net.HttpURLConnection;
018: import java.net.URI;
019: import java.net.URISyntaxException;
020: import java.net.URL;
021: import java.net.URLConnection;
022:
023: /**
024: * Class that defines convenience methods for common, simple use of JAXB.
025: *
026: * <p>
027: * Methods defined in this class are convenience methods that combine several basic operations
028: * in the {@link JAXBContext}, {@link Unmarshaller}, and {@link Marshaller}.
029: *
030: * They are designed
031: * to be the prefered methods for developers new to JAXB. They have
032: * the following characterstics:
033: *
034: * <ol>
035: * <li>Generally speaking, the performance is not necessarily optimal.
036: * It is expected that people who need to write performance
037: * critical code will use the rest of the JAXB API directly.
038: * <li>Errors that happen during the processing is wrapped into
039: * {@link DataBindingException} (which will have {@link JAXBException}
040: * as its {@link Throwable#getCause() cause}. It is expected that
041: * people who prefer the checked exception would use
042: * the rest of the JAXB API directly.
043: * </ol>
044: *
045: * <p>
046: * In addition, the <tt>unmarshal</tt> methods have the following characteristic:
047: *
048: * <ol>
049: * <li>Schema validation is not performed on the input XML.
050: * The processing will try to continue even if there
051: * are errors in the XML, as much as possible. Only as
052: * the last resort, this method fails with {@link DataBindingException}.
053: * </ol>
054: *
055: * <p>
056: * Similarly, the <tt>marshal</tt> methods have the following characteristic:
057: * <ol>
058: * <li>The processing will try to continue even if the Java object tree
059: * does not meet the validity requirement. Only as
060: * the last resort, this method fails with {@link DataBindingException}.
061: * </ol>
062: *
063: *
064: * <p>
065: * All the methods on this class require non-null arguments to all parameters.
066: * The <tt>unmarshal</tt> methods either fail with an exception or return
067: * a non-null value.
068: *
069: * @author Kohsuke Kawaguchi
070: * @since 2.1
071: */
072: public final class JAXB {
073: /**
074: * No instanciation is allowed.
075: */
076: private JAXB() {
077: }
078:
079: /**
080: * To improve the performance, we'll cache the last {@link JAXBContext} used.
081: */
082: private static final class Cache {
083: final Class type;
084: final JAXBContext context;
085:
086: public Cache(Class type) throws JAXBException {
087: this .type = type;
088: this .context = JAXBContext.newInstance(type);
089: }
090: }
091:
092: /**
093: * Cache. We don't want to prevent the {@link Cache#type} from GC-ed,
094: * hence {@link WeakReference}.
095: */
096: private static volatile WeakReference<Cache> cache;
097:
098: /**
099: * Obtains the {@link JAXBContext} from the given type,
100: * by using the cache if possible.
101: *
102: * <p>
103: * We don't use locks to control access to {@link #cache}, but this code
104: * should be thread-safe thanks to the immutable {@link Cache} and {@code volatile}.
105: */
106: private static <T> JAXBContext getContext(Class<T> type)
107: throws JAXBException {
108: WeakReference<Cache> c = cache;
109: if (c != null) {
110: Cache d = c.get();
111: if (d != null && d.type == type)
112: return d.context;
113: }
114:
115: // overwrite the cache
116: Cache d = new Cache(type);
117: cache = new WeakReference<Cache>(d);
118:
119: return d.context;
120: }
121:
122: /**
123: * Reads in a Java object tree from the given XML input.
124: *
125: * @param xml
126: * Reads the entire file as XML.
127: */
128: public static <T> T unmarshal(File xml, Class<T> type) {
129: try {
130: JAXBElement<T> item = getContext(type).createUnmarshaller()
131: .unmarshal(new StreamSource(xml), type);
132: return item.getValue();
133: } catch (JAXBException e) {
134: throw new DataBindingException(e);
135: }
136: }
137:
138: /**
139: * Reads in a Java object tree from the given XML input.
140: *
141: * @param xml
142: * The resource pointed by the URL is read in its entirety.
143: */
144: public static <T> T unmarshal(URL xml, Class<T> type) {
145: try {
146: JAXBElement<T> item = getContext(type).createUnmarshaller()
147: .unmarshal(toSource(xml), type);
148: return item.getValue();
149: } catch (JAXBException e) {
150: throw new DataBindingException(e);
151: } catch (IOException e) {
152: throw new DataBindingException(e);
153: }
154: }
155:
156: /**
157: * Reads in a Java object tree from the given XML input.
158: *
159: * @param xml
160: * The URI is {@link URI#toURL() turned into URL} and then
161: * follows the handling of <tt>URL</tt>.
162: */
163: public static <T> T unmarshal(URI xml, Class<T> type) {
164: try {
165: JAXBElement<T> item = getContext(type).createUnmarshaller()
166: .unmarshal(toSource(xml), type);
167: return item.getValue();
168: } catch (JAXBException e) {
169: throw new DataBindingException(e);
170: } catch (IOException e) {
171: throw new DataBindingException(e);
172: }
173: }
174:
175: /**
176: * Reads in a Java object tree from the given XML input.
177: *
178: * @param xml
179: * The string is first interpreted as an absolute <tt>URI</tt>.
180: * If it's not {@link URI#isAbsolute() a valid absolute URI},
181: * then it's interpreted as a <tt>File</tt>
182: */
183: public static <T> T unmarshal(String xml, Class<T> type) {
184: try {
185: JAXBElement<T> item = getContext(type).createUnmarshaller()
186: .unmarshal(toSource(xml), type);
187: return item.getValue();
188: } catch (JAXBException e) {
189: throw new DataBindingException(e);
190: } catch (IOException e) {
191: throw new DataBindingException(e);
192: }
193: }
194:
195: /**
196: * Reads in a Java object tree from the given XML input.
197: *
198: * @param xml
199: * The entire stream is read as an XML infoset.
200: * Upon a successful completion, the stream will be closed by this method.
201: */
202: public static <T> T unmarshal(InputStream xml, Class<T> type) {
203: try {
204: JAXBElement<T> item = getContext(type).createUnmarshaller()
205: .unmarshal(toSource(xml), type);
206: return item.getValue();
207: } catch (JAXBException e) {
208: throw new DataBindingException(e);
209: } catch (IOException e) {
210: throw new DataBindingException(e);
211: }
212: }
213:
214: /**
215: * Reads in a Java object tree from the given XML input.
216: *
217: * @param xml
218: * The character stream is read as an XML infoset.
219: * The encoding declaration in the XML will be ignored.
220: * Upon a successful completion, the stream will be closed by this method.
221: */
222: public static <T> T unmarshal(Reader xml, Class<T> type) {
223: try {
224: JAXBElement<T> item = getContext(type).createUnmarshaller()
225: .unmarshal(toSource(xml), type);
226: return item.getValue();
227: } catch (JAXBException e) {
228: throw new DataBindingException(e);
229: } catch (IOException e) {
230: throw new DataBindingException(e);
231: }
232: }
233:
234: /**
235: * Reads in a Java object tree from the given XML input.
236: *
237: * @param xml
238: * The XML infoset that the {@link Source} represents is read.
239: */
240: public static <T> T unmarshal(Source xml, Class<T> type) {
241: try {
242: JAXBElement<T> item = getContext(type).createUnmarshaller()
243: .unmarshal(toSource(xml), type);
244: return item.getValue();
245: } catch (JAXBException e) {
246: throw new DataBindingException(e);
247: } catch (IOException e) {
248: throw new DataBindingException(e);
249: }
250: }
251:
252: /**
253: * Creates {@link Source} from various XML representation.
254: * See {@link #unmarshal} for the conversion rules.
255: */
256: private static Source toSource(Object xml) throws IOException {
257: if (xml == null)
258: throw new IllegalArgumentException("no XML is given");
259:
260: if (xml instanceof String) {
261: try {
262: xml = new URI((String) xml);
263: } catch (URISyntaxException e) {
264: xml = new File((String) xml);
265: }
266: }
267: if (xml instanceof File) {
268: File file = (File) xml;
269: return new StreamSource(file);
270: }
271: if (xml instanceof URI) {
272: URI uri = (URI) xml;
273: xml = uri.toURL();
274: }
275: if (xml instanceof URL) {
276: URL url = (URL) xml;
277: return new StreamSource(url.toExternalForm());
278: }
279: if (xml instanceof InputStream) {
280: InputStream in = (InputStream) xml;
281: return new StreamSource(in);
282: }
283: if (xml instanceof Reader) {
284: Reader r = (Reader) xml;
285: return new StreamSource(r);
286: }
287: if (xml instanceof Source) {
288: return (Source) xml;
289: }
290: throw new IllegalArgumentException(
291: "I don't understand how to handle " + xml.getClass());
292: }
293:
294: /**
295: * Writes a Java object tree to XML and store it to the specified location.
296: *
297: * @param jaxbObject
298: * The Java object to be marshalled into XML. If this object is
299: * a {@link JAXBElement}, it will provide the root tag name and
300: * the body. If this object has {@link XmlRootElement}
301: * on its class definition, that will be used as the root tag name
302: * and the given object will provide the body. Otherwise,
303: * the root tag name is {@link Introspector#decapitalize(String) infered} from
304: * {@link Class#getSimpleName() the short class name}.
305: * This parameter must not be null.
306: *
307: * @param xml
308: * XML will be written to this file. If it already exists,
309: * it will be overwritten.
310: *
311: * @throws DataBindingException
312: * If the operation fails, such as due to I/O error, unbindable classes.
313: */
314: public static void marshal(Object jaxbObject, File xml) {
315: _marshal(jaxbObject, xml);
316: }
317:
318: /**
319: * Writes a Java object tree to XML and store it to the specified location.
320: *
321: * @param jaxbObject
322: * The Java object to be marshalled into XML. If this object is
323: * a {@link JAXBElement}, it will provide the root tag name and
324: * the body. If this object has {@link XmlRootElement}
325: * on its class definition, that will be used as the root tag name
326: * and the given object will provide the body. Otherwise,
327: * the root tag name is {@link Introspector#decapitalize(String) infered} from
328: * {@link Class#getSimpleName() the short class name}.
329: * This parameter must not be null.
330: *
331: * @param xml
332: * The XML will be {@link URLConnection#getOutputStream() sent} to the
333: * resource pointed by this URL. Note that not all <tt>URL</tt>s support
334: * such operation, and exact semantics depends on the <tt>URL</tt>
335: * implementations. In case of {@link HttpURLConnection HTTP URLs},
336: * this will perform HTTP POST.
337: *
338: * @throws DataBindingException
339: * If the operation fails, such as due to I/O error, unbindable classes.
340: */
341: public static void marshal(Object jaxbObject, URL xml) {
342: _marshal(jaxbObject, xml);
343: }
344:
345: /**
346: * Writes a Java object tree to XML and store it to the specified location.
347: *
348: * @param jaxbObject
349: * The Java object to be marshalled into XML. If this object is
350: * a {@link JAXBElement}, it will provide the root tag name and
351: * the body. If this object has {@link XmlRootElement}
352: * on its class definition, that will be used as the root tag name
353: * and the given object will provide the body. Otherwise,
354: * the root tag name is {@link Introspector#decapitalize(String) infered} from
355: * {@link Class#getSimpleName() the short class name}.
356: * This parameter must not be null.
357: *
358: * @param xml
359: * The URI is {@link URI#toURL() turned into URL} and then
360: * follows the handling of <tt>URL</tt>. See above.
361: *
362: * @throws DataBindingException
363: * If the operation fails, such as due to I/O error, unbindable classes.
364: */
365: public static void marshal(Object jaxbObject, URI xml) {
366: _marshal(jaxbObject, xml);
367: }
368:
369: /**
370: * Writes a Java object tree to XML and store it to the specified location.
371: *
372: * @param jaxbObject
373: * The Java object to be marshalled into XML. If this object is
374: * a {@link JAXBElement}, it will provide the root tag name and
375: * the body. If this object has {@link XmlRootElement}
376: * on its class definition, that will be used as the root tag name
377: * and the given object will provide the body. Otherwise,
378: * the root tag name is {@link Introspector#decapitalize(String) infered} from
379: * {@link Class#getSimpleName() the short class name}.
380: * This parameter must not be null.
381: *
382: * @param xml
383: * The string is first interpreted as an absolute <tt>URI</tt>.
384: * If it's not {@link URI#isAbsolute() a valid absolute URI},
385: * then it's interpreted as a <tt>File</tt>
386: *
387: * @throws DataBindingException
388: * If the operation fails, such as due to I/O error, unbindable classes.
389: */
390: public static void marshal(Object jaxbObject, String xml) {
391: _marshal(jaxbObject, xml);
392: }
393:
394: /**
395: * Writes a Java object tree to XML and store it to the specified location.
396: *
397: * @param jaxbObject
398: * The Java object to be marshalled into XML. If this object is
399: * a {@link JAXBElement}, it will provide the root tag name and
400: * the body. If this object has {@link XmlRootElement}
401: * on its class definition, that will be used as the root tag name
402: * and the given object will provide the body. Otherwise,
403: * the root tag name is {@link Introspector#decapitalize(String) infered} from
404: * {@link Class#getSimpleName() the short class name}.
405: * This parameter must not be null.
406: *
407: * @param xml
408: * The XML will be sent to the given {@link OutputStream}.
409: * Upon a successful completion, the stream will be closed by this method.
410: *
411: * @throws DataBindingException
412: * If the operation fails, such as due to I/O error, unbindable classes.
413: */
414: public static void marshal(Object jaxbObject, OutputStream xml) {
415: _marshal(jaxbObject, xml);
416: }
417:
418: /**
419: * Writes a Java object tree to XML and store it to the specified location.
420: *
421: * @param jaxbObject
422: * The Java object to be marshalled into XML. If this object is
423: * a {@link JAXBElement}, it will provide the root tag name and
424: * the body. If this object has {@link XmlRootElement}
425: * on its class definition, that will be used as the root tag name
426: * and the given object will provide the body. Otherwise,
427: * the root tag name is {@link Introspector#decapitalize(String) infered} from
428: * {@link Class#getSimpleName() the short class name}.
429: * This parameter must not be null.
430: *
431: * @param xml
432: * The XML will be sent as a character stream to the given {@link Writer}.
433: * Upon a successful completion, the stream will be closed by this method.
434: *
435: * @throws DataBindingException
436: * If the operation fails, such as due to I/O error, unbindable classes.
437: */
438: public static void marshal(Object jaxbObject, Writer xml) {
439: _marshal(jaxbObject, xml);
440: }
441:
442: /**
443: * Writes a Java object tree to XML and store it to the specified location.
444: *
445: * @param jaxbObject
446: * The Java object to be marshalled into XML. If this object is
447: * a {@link JAXBElement}, it will provide the root tag name and
448: * the body. If this object has {@link XmlRootElement}
449: * on its class definition, that will be used as the root tag name
450: * and the given object will provide the body. Otherwise,
451: * the root tag name is {@link Introspector#decapitalize(String) infered} from
452: * {@link Class#getSimpleName() the short class name}.
453: * This parameter must not be null.
454: *
455: * @param xml
456: * The XML will be sent to the {@link Result} object.
457: *
458: * @throws DataBindingException
459: * If the operation fails, such as due to I/O error, unbindable classes.
460: */
461: public static void marshal(Object jaxbObject, Result xml) {
462: _marshal(jaxbObject, xml);
463: }
464:
465: /**
466: * Writes a Java object tree to XML and store it to the specified location.
467: *
468: * <p>
469: * This method is a convenience method that combines several basic operations
470: * in the {@link JAXBContext} and {@link Marshaller}. This method is designed
471: * to be the prefered method for developers new to JAXB. This method
472: * has the following characterstics:
473: *
474: * <ol>
475: * <li>Generally speaking, the performance is not necessarily optimal.
476: * It is expected that those people who need to write performance
477: * critical code will use the rest of the JAXB API directly.
478: * <li>Errors that happen during the processing is wrapped into
479: * {@link DataBindingException} (which will have {@link JAXBException}
480: * as its {@link Throwable#getCause() cause}. It is expected that
481: * those people who prefer the checked exception would use
482: * the rest of the JAXB API directly.
483: * </ol>
484: *
485: * @param jaxbObject
486: * The Java object to be marshalled into XML. If this object is
487: * a {@link JAXBElement}, it will provide the root tag name and
488: * the body. If this object has {@link XmlRootElement}
489: * on its class definition, that will be used as the root tag name
490: * and the given object will provide the body. Otherwise,
491: * the root tag name is {@link Introspector#decapitalize(String) infered} from
492: * {@link Class#getSimpleName() the short class name}.
493: * This parameter must not be null.
494: *
495: * @param xml
496: * Represents the receiver of XML. Objects of the following types are allowed.
497: *
498: * <table><tr>
499: * <th>Type</th>
500: * <th>Operation</th>
501: * </tr><tr>
502: * <td>{@link File}</td>
503: * <td>XML will be written to this file. If it already exists,
504: * it will be overwritten.</td>
505: * </tr><tr>
506: * <td>{@link URL}</td>
507: * <td>The XML will be {@link URLConnection#getOutputStream() sent} to the
508: * resource pointed by this URL. Note that not all <tt>URL</tt>s support
509: * such operation, and exact semantics depends on the <tt>URL</tt>
510: * implementations. In case of {@link HttpURLConnection HTTP URLs},
511: * this will perform HTTP POST.</td>
512: * </tr><tr>
513: * <td>{@link URI}</td>
514: * <td>The URI is {@link URI#toURL() turned into URL} and then
515: * follows the handling of <tt>URL</tt>. See above.</td>
516: * </tr><tr>
517: * <td>{@link String}</td>
518: * <td>The string is first interpreted as an absolute <tt>URI</tt>.
519: * If it's not {@link URI#isAbsolute() a valid absolute URI},
520: * then it's interpreted as a <tt>File</tt></td>
521: * </tr><tr>
522: * <td>{@link OutputStream}</td>
523: * <td>The XML will be sent to the given {@link OutputStream}.
524: * Upon a successful completion, the stream will be closed by this method.</td>
525: * </tr><tr>
526: * <td>{@link Writer}</td>
527: * <td>The XML will be sent as a character stream to the given {@link Writer}.
528: * Upon a successful completion, the stream will be closed by this method.</td>
529: * </tr><tr>
530: * <td>{@link Result}</td>
531: * <td>The XML will be sent to the {@link Result} object.</td>
532: * </tr></table>
533: *
534: * @throws DataBindingException
535: * If the operation fails, such as due to I/O error, unbindable classes.
536: */
537: private static void _marshal(Object jaxbObject, Object xml) {
538: try {
539: JAXBContext context;
540:
541: if (jaxbObject instanceof JAXBElement) {
542: context = getContext(((JAXBElement<?>) jaxbObject)
543: .getDeclaredType());
544: } else {
545: Class<?> clazz = jaxbObject.getClass();
546: XmlRootElement r = clazz
547: .getAnnotation(XmlRootElement.class);
548: context = getContext(clazz);
549: if (r == null) {
550: // we need to infer the name
551: jaxbObject = new JAXBElement(new QName(
552: inferName(clazz)), clazz, jaxbObject);
553: }
554: }
555:
556: Marshaller m = context.createMarshaller();
557: m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
558: m.marshal(jaxbObject, toResult(xml));
559: } catch (JAXBException e) {
560: throw new DataBindingException(e);
561: } catch (IOException e) {
562: throw new DataBindingException(e);
563: }
564: }
565:
566: private static String inferName(Class clazz) {
567: return Introspector.decapitalize(clazz.getSimpleName());
568: }
569:
570: /**
571: * Creates {@link Result} from various XML representation.
572: * See {@link #_marshal(Object,Object)} for the conversion rules.
573: */
574: private static Result toResult(Object xml) throws IOException {
575: if (xml == null)
576: throw new IllegalArgumentException("no XML is given");
577:
578: if (xml instanceof String) {
579: try {
580: xml = new URI((String) xml);
581: } catch (URISyntaxException e) {
582: xml = new File((String) xml);
583: }
584: }
585: if (xml instanceof File) {
586: File file = (File) xml;
587: return new StreamResult(file);
588: }
589: if (xml instanceof URI) {
590: URI uri = (URI) xml;
591: xml = uri.toURL();
592: }
593: if (xml instanceof URL) {
594: URL url = (URL) xml;
595: URLConnection con = url.openConnection();
596: con.setDoOutput(true);
597: con.setDoInput(false);
598: con.connect();
599: return new StreamResult(con.getOutputStream());
600: }
601: if (xml instanceof OutputStream) {
602: OutputStream os = (OutputStream) xml;
603: return new StreamResult(os);
604: }
605: if (xml instanceof Writer) {
606: Writer w = (Writer) xml;
607: return new StreamResult(w);
608: }
609: if (xml instanceof Result) {
610: return (Result) xml;
611: }
612: throw new IllegalArgumentException(
613: "I don't understand how to handle " + xml.getClass());
614: }
615:
616: }
|