1 /* 2 * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.bind; 27 28 import javax.xml.bind.annotation.XmlRootElement; 29 import javax.xml.namespace.QName; 30 import javax.xml.transform.Result; 31 import javax.xml.transform.Source; 32 import javax.xml.transform.stream.StreamResult; 33 import javax.xml.transform.stream.StreamSource; 34 import java.beans.Introspector; 35 import java.io.File; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.io.OutputStream; 39 import java.io.Reader; 40 import java.io.Writer; 41 import java.lang.ref.WeakReference; 42 import java.net.HttpURLConnection; 43 import java.net.URI; 44 import java.net.URISyntaxException; 45 import java.net.URL; 46 import java.net.URLConnection; 47 48 /** 49 * Class that defines convenience methods for common, simple use of JAXB. 50 * 51 * <p> 52 * Methods defined in this class are convenience methods that combine several basic operations 53 * in the {@link JAXBContext}, {@link Unmarshaller}, and {@link Marshaller}. 54 * 55 * They are designed 56 * to be the prefered methods for developers new to JAXB. They have 57 * the following characterstics: 58 * 59 * <ol> 60 * <li>Generally speaking, the performance is not necessarily optimal. 61 * It is expected that people who need to write performance 62 * critical code will use the rest of the JAXB API directly. 63 * <li>Errors that happen during the processing is wrapped into 64 * {@link DataBindingException} (which will have {@link JAXBException} 65 * as its {@link Throwable#getCause() cause}. It is expected that 66 * people who prefer the checked exception would use 67 * the rest of the JAXB API directly. 68 * </ol> 69 * 70 * <p> 71 * In addition, the <tt>unmarshal</tt> methods have the following characteristic: 72 * 73 * <ol> 74 * <li>Schema validation is not performed on the input XML. 75 * The processing will try to continue even if there 76 * are errors in the XML, as much as possible. Only as 77 * the last resort, this method fails with {@link DataBindingException}. 78 * </ol> 79 * 80 * <p> 81 * Similarly, the <tt>marshal</tt> methods have the following characteristic: 82 * <ol> 83 * <li>The processing will try to continue even if the Java object tree 84 * does not meet the validity requirement. Only as 85 * the last resort, this method fails with {@link DataBindingException}. 86 * </ol> 87 * 88 * 89 * <p> 90 * All the methods on this class require non-null arguments to all parameters. 91 * The <tt>unmarshal</tt> methods either fail with an exception or return 92 * a non-null value. 93 * 94 * @author Kohsuke Kawaguchi 95 * @since 2.1 96 */ 97 public final class JAXB { 98 /** 99 * No instanciation is allowed. 100 */ 101 private JAXB() {} 102 103 /** 104 * To improve the performance, we'll cache the last {@link JAXBContext} used. 105 */ 106 private static final class Cache { 107 final Class type; 108 final JAXBContext context; 109 110 public Cache(Class type) throws JAXBException { 111 this.type = type; 112 this.context = JAXBContext.newInstance(type); 113 } 114 } 115 116 /** 117 * Cache. We don't want to prevent the {@link Cache#type} from GC-ed, 118 * hence {@link WeakReference}. 119 */ 120 private static volatile WeakReference<Cache> cache; 121 122 /** 123 * Obtains the {@link JAXBContext} from the given type, 124 * by using the cache if possible. 125 * 126 * <p> 127 * We don't use locks to control access to {@link #cache}, but this code 128 * should be thread-safe thanks to the immutable {@link Cache} and {@code volatile}. 129 */ 130 private static <T> JAXBContext getContext(Class<T> type) throws JAXBException { 131 WeakReference<Cache> c = cache; 132 if(c!=null) { 133 Cache d = c.get(); 134 if(d!=null && d.type==type) 135 return d.context; 136 } 137 138 // overwrite the cache 139 Cache d = new Cache(type); 140 cache = new WeakReference<Cache>(d); 141 142 return d.context; 143 } 144 145 /** 146 * Reads in a Java object tree from the given XML input. 147 * 148 * @param xml 149 * Reads the entire file as XML. 150 */ 151 public static <T> T unmarshal( File xml, Class<T> type ) { 152 try { 153 JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(new StreamSource(xml), type); 154 return item.getValue(); 155 } catch (JAXBException e) { 156 throw new DataBindingException(e); 157 } 158 } 159 160 /** 161 * Reads in a Java object tree from the given XML input. 162 * 163 * @param xml 164 * The resource pointed by the URL is read in its entirety. 165 */ 166 public static <T> T unmarshal( URL xml, Class<T> type ) { 167 try { 168 JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type); 169 return item.getValue(); 170 } catch (JAXBException e) { 171 throw new DataBindingException(e); 172 } catch (IOException e) { 173 throw new DataBindingException(e); 174 } 175 } 176 177 /** 178 * Reads in a Java object tree from the given XML input. 179 * 180 * @param xml 181 * The URI is {@link URI#toURL() turned into URL} and then 182 * follows the handling of <tt>URL</tt>. 183 */ 184 public static <T> T unmarshal( URI xml, Class<T> type ) { 185 try { 186 JAXBElement<T> item = getContext(type).createUnmarshaller().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 string is first interpreted as an absolute <tt>URI</tt>. 200 * If it's not {@link URI#isAbsolute() a valid absolute URI}, 201 * then it's interpreted as a <tt>File</tt> 202 */ 203 public static <T> T unmarshal( String xml, Class<T> type ) { 204 try { 205 JAXBElement<T> item = getContext(type).createUnmarshaller().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 entire stream is read as an XML infoset. 219 * Upon a successful completion, the stream will be closed by this method. 220 */ 221 public static <T> T unmarshal( InputStream xml, Class<T> type ) { 222 try { 223 JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type); 224 return item.getValue(); 225 } catch (JAXBException e) { 226 throw new DataBindingException(e); 227 } catch (IOException e) { 228 throw new DataBindingException(e); 229 } 230 } 231 232 /** 233 * Reads in a Java object tree from the given XML input. 234 * 235 * @param xml 236 * The character stream is read as an XML infoset. 237 * The encoding declaration in the XML will be ignored. 238 * Upon a successful completion, the stream will be closed by this method. 239 */ 240 public static <T> T unmarshal( Reader xml, Class<T> type ) { 241 try { 242 JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type); 243 return item.getValue(); 244 } catch (JAXBException e) { 245 throw new DataBindingException(e); 246 } catch (IOException e) { 247 throw new DataBindingException(e); 248 } 249 } 250 251 /** 252 * Reads in a Java object tree from the given XML input. 253 * 254 * @param xml 255 * The XML infoset that the {@link Source} represents is read. 256 */ 257 public static <T> T unmarshal( Source xml, Class<T> type ) { 258 try { 259 JAXBElement<T> item = getContext(type).createUnmarshaller().unmarshal(toSource(xml), type); 260 return item.getValue(); 261 } catch (JAXBException e) { 262 throw new DataBindingException(e); 263 } catch (IOException e) { 264 throw new DataBindingException(e); 265 } 266 } 267 268 269 270 /** 271 * Creates {@link Source} from various XML representation. 272 * See {@link #unmarshal} for the conversion rules. 273 */ 274 private static Source toSource(Object xml) throws IOException { 275 if(xml==null) 276 throw new IllegalArgumentException("no XML is given"); 277 278 if (xml instanceof String) { 279 try { 280 xml=new URI((String)xml); 281 } catch (URISyntaxException e) { 282 xml=new File((String)xml); 283 } 284 } 285 if (xml instanceof File) { 286 File file = (File) xml; 287 return new StreamSource(file); 288 } 289 if (xml instanceof URI) { 290 URI uri = (URI) xml; 291 xml=uri.toURL(); 292 } 293 if (xml instanceof URL) { 294 URL url = (URL) xml; 295 return new StreamSource(url.toExternalForm()); 296 } 297 if (xml instanceof InputStream) { 298 InputStream in = (InputStream) xml; 299 return new StreamSource(in); 300 } 301 if (xml instanceof Reader) { 302 Reader r = (Reader) xml; 303 return new StreamSource(r); 304 } 305 if (xml instanceof Source) { 306 return (Source) xml; 307 } 308 throw new IllegalArgumentException("I don't understand how to handle "+xml.getClass()); 309 } 310 311 /** 312 * Writes a Java object tree to XML and store it to the specified location. 313 * 314 * @param jaxbObject 315 * The Java object to be marshalled into XML. If this object is 316 * a {@link JAXBElement}, it will provide the root tag name and 317 * the body. If this object has {@link XmlRootElement} 318 * on its class definition, that will be used as the root tag name 319 * and the given object will provide the body. Otherwise, 320 * the root tag name is {@link Introspector#decapitalize(String) infered} from 321 * {@link Class#getSimpleName() the short class name}. 322 * This parameter must not be null. 323 * 324 * @param xml 325 * XML will be written to this file. If it already exists, 326 * it will be overwritten. 327 * 328 * @throws DataBindingException 329 * If the operation fails, such as due to I/O error, unbindable classes. 330 */ 331 public static void marshal( Object jaxbObject, File xml ) { 332 _marshal(jaxbObject,xml); 333 } 334 335 /** 336 * Writes a Java object tree to XML and store it to the specified location. 337 * 338 * @param jaxbObject 339 * The Java object to be marshalled into XML. If this object is 340 * a {@link JAXBElement}, it will provide the root tag name and 341 * the body. If this object has {@link XmlRootElement} 342 * on its class definition, that will be used as the root tag name 343 * and the given object will provide the body. Otherwise, 344 * the root tag name is {@link Introspector#decapitalize(String) infered} from 345 * {@link Class#getSimpleName() the short class name}. 346 * This parameter must not be null. 347 * 348 * @param xml 349 * The XML will be {@link URLConnection#getOutputStream() sent} to the 350 * resource pointed by this URL. Note that not all <tt>URL</tt>s support 351 * such operation, and exact semantics depends on the <tt>URL</tt> 352 * implementations. In case of {@link HttpURLConnection HTTP URLs}, 353 * this will perform HTTP POST. 354 * 355 * @throws DataBindingException 356 * If the operation fails, such as due to I/O error, unbindable classes. 357 */ 358 public static void marshal( Object jaxbObject, URL xml ) { 359 _marshal(jaxbObject,xml); 360 } 361 362 /** 363 * Writes a Java object tree to XML and store it to the specified location. 364 * 365 * @param jaxbObject 366 * The Java object to be marshalled into XML. If this object is 367 * a {@link JAXBElement}, it will provide the root tag name and 368 * the body. If this object has {@link XmlRootElement} 369 * on its class definition, that will be used as the root tag name 370 * and the given object will provide the body. Otherwise, 371 * the root tag name is {@link Introspector#decapitalize(String) infered} from 372 * {@link Class#getSimpleName() the short class name}. 373 * This parameter must not be null. 374 * 375 * @param xml 376 * The URI is {@link URI#toURL() turned into URL} and then 377 * follows the handling of <tt>URL</tt>. See above. 378 * 379 * @throws DataBindingException 380 * If the operation fails, such as due to I/O error, unbindable classes. 381 */ 382 public static void marshal( Object jaxbObject, URI xml ) { 383 _marshal(jaxbObject,xml); 384 } 385 386 /** 387 * Writes a Java object tree to XML and store it to the specified location. 388 * 389 * @param jaxbObject 390 * The Java object to be marshalled into XML. If this object is 391 * a {@link JAXBElement}, it will provide the root tag name and 392 * the body. If this object has {@link XmlRootElement} 393 * on its class definition, that will be used as the root tag name 394 * and the given object will provide the body. Otherwise, 395 * the root tag name is {@link Introspector#decapitalize(String) infered} from 396 * {@link Class#getSimpleName() the short class name}. 397 * This parameter must not be null. 398 * 399 * @param xml 400 * The string is first interpreted as an absolute <tt>URI</tt>. 401 * If it's not {@link URI#isAbsolute() a valid absolute URI}, 402 * then it's interpreted as a <tt>File</tt> 403 * 404 * @throws DataBindingException 405 * If the operation fails, such as due to I/O error, unbindable classes. 406 */ 407 public static void marshal( Object jaxbObject, String xml ) { 408 _marshal(jaxbObject,xml); 409 } 410 411 /** 412 * Writes a Java object tree to XML and store it to the specified location. 413 * 414 * @param jaxbObject 415 * The Java object to be marshalled into XML. If this object is 416 * a {@link JAXBElement}, it will provide the root tag name and 417 * the body. If this object has {@link XmlRootElement} 418 * on its class definition, that will be used as the root tag name 419 * and the given object will provide the body. Otherwise, 420 * the root tag name is {@link Introspector#decapitalize(String) infered} from 421 * {@link Class#getSimpleName() the short class name}. 422 * This parameter must not be null. 423 * 424 * @param xml 425 * The XML will be sent to the given {@link OutputStream}. 426 * Upon a successful completion, the stream will be closed by this method. 427 * 428 * @throws DataBindingException 429 * If the operation fails, such as due to I/O error, unbindable classes. 430 */ 431 public static void marshal( Object jaxbObject, OutputStream xml ) { 432 _marshal(jaxbObject,xml); 433 } 434 435 /** 436 * Writes a Java object tree to XML and store it to the specified location. 437 * 438 * @param jaxbObject 439 * The Java object to be marshalled into XML. If this object is 440 * a {@link JAXBElement}, it will provide the root tag name and 441 * the body. If this object has {@link XmlRootElement} 442 * on its class definition, that will be used as the root tag name 443 * and the given object will provide the body. Otherwise, 444 * the root tag name is {@link Introspector#decapitalize(String) infered} from 445 * {@link Class#getSimpleName() the short class name}. 446 * This parameter must not be null. 447 * 448 * @param xml 449 * The XML will be sent as a character stream to the given {@link Writer}. 450 * Upon a successful completion, the stream will be closed by this method. 451 * 452 * @throws DataBindingException 453 * If the operation fails, such as due to I/O error, unbindable classes. 454 */ 455 public static void marshal( Object jaxbObject, Writer xml ) { 456 _marshal(jaxbObject,xml); 457 } 458 459 /** 460 * Writes a Java object tree to XML and store it to the specified location. 461 * 462 * @param jaxbObject 463 * The Java object to be marshalled into XML. If this object is 464 * a {@link JAXBElement}, it will provide the root tag name and 465 * the body. If this object has {@link XmlRootElement} 466 * on its class definition, that will be used as the root tag name 467 * and the given object will provide the body. Otherwise, 468 * the root tag name is {@link Introspector#decapitalize(String) infered} from 469 * {@link Class#getSimpleName() the short class name}. 470 * This parameter must not be null. 471 * 472 * @param xml 473 * The XML will be sent to the {@link Result} object. 474 * 475 * @throws DataBindingException 476 * If the operation fails, such as due to I/O error, unbindable classes. 477 */ 478 public static void marshal( Object jaxbObject, Result xml ) { 479 _marshal(jaxbObject,xml); 480 } 481 482 /** 483 * Writes a Java object tree to XML and store it to the specified location. 484 * 485 * <p> 486 * This method is a convenience method that combines several basic operations 487 * in the {@link JAXBContext} and {@link Marshaller}. This method is designed 488 * to be the prefered method for developers new to JAXB. This method 489 * has the following characterstics: 490 * 491 * <ol> 492 * <li>Generally speaking, the performance is not necessarily optimal. 493 * It is expected that those people who need to write performance 494 * critical code will use the rest of the JAXB API directly. 495 * <li>Errors that happen during the processing is wrapped into 496 * {@link DataBindingException} (which will have {@link JAXBException} 497 * as its {@link Throwable#getCause() cause}. It is expected that 498 * those people who prefer the checked exception would use 499 * the rest of the JAXB API directly. 500 * </ol> 501 * 502 * @param jaxbObject 503 * The Java object to be marshalled into XML. If this object is 504 * a {@link JAXBElement}, it will provide the root tag name and 505 * the body. If this object has {@link XmlRootElement} 506 * on its class definition, that will be used as the root tag name 507 * and the given object will provide the body. Otherwise, 508 * the root tag name is {@link Introspector#decapitalize(String) infered} from 509 * {@link Class#getSimpleName() the short class name}. 510 * This parameter must not be null. 511 * 512 * @param xml 513 * Represents the receiver of XML. Objects of the following types are allowed. 514 * 515 * <table><tr> 516 * <th>Type</th> 517 * <th>Operation</th> 518 * </tr><tr> 519 * <td>{@link File}</td> 520 * <td>XML will be written to this file. If it already exists, 521 * it will be overwritten.</td> 522 * </tr><tr> 523 * <td>{@link URL}</td> 524 * <td>The XML will be {@link URLConnection#getOutputStream() sent} to the 525 * resource pointed by this URL. Note that not all <tt>URL</tt>s support 526 * such operation, and exact semantics depends on the <tt>URL</tt> 527 * implementations. In case of {@link HttpURLConnection HTTP URLs}, 528 * this will perform HTTP POST.</td> 529 * </tr><tr> 530 * <td>{@link URI}</td> 531 * <td>The URI is {@link URI#toURL() turned into URL} and then 532 * follows the handling of <tt>URL</tt>. See above.</td> 533 * </tr><tr> 534 * <td>{@link String}</td> 535 * <td>The string is first interpreted as an absolute <tt>URI</tt>. 536 * If it's not {@link URI#isAbsolute() a valid absolute URI}, 537 * then it's interpreted as a <tt>File</tt></td> 538 * </tr><tr> 539 * <td>{@link OutputStream}</td> 540 * <td>The XML will be sent to the given {@link OutputStream}. 541 * Upon a successful completion, the stream will be closed by this method.</td> 542 * </tr><tr> 543 * <td>{@link Writer}</td> 544 * <td>The XML will be sent as a character stream to the given {@link Writer}. 545 * Upon a successful completion, the stream will be closed by this method.</td> 546 * </tr><tr> 547 * <td>{@link Result}</td> 548 * <td>The XML will be sent to the {@link Result} object.</td> 549 * </tr></table> 550 * 551 * @throws DataBindingException 552 * If the operation fails, such as due to I/O error, unbindable classes. 553 */ 554 private static void _marshal( Object jaxbObject, Object xml ) { 555 try { 556 JAXBContext context; 557 558 if(jaxbObject instanceof JAXBElement) { 559 context = getContext(((JAXBElement<?>)jaxbObject).getDeclaredType()); 560 } else { 561 Class<?> clazz = jaxbObject.getClass(); 562 XmlRootElement r = clazz.getAnnotation(XmlRootElement.class); 563 context = getContext(clazz); 564 if(r==null) { 565 // we need to infer the name 566 jaxbObject = new JAXBElement(new QName(inferName(clazz)),clazz,jaxbObject); 567 } 568 } 569 570 Marshaller m = context.createMarshaller(); 571 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true); 572 m.marshal(jaxbObject, toResult(xml)); 573 } catch (JAXBException e) { 574 throw new DataBindingException(e); 575 } catch (IOException e) { 576 throw new DataBindingException(e); 577 } 578 } 579 580 private static String inferName(Class clazz) { 581 return Introspector.decapitalize(clazz.getSimpleName()); 582 } 583 584 /** 585 * Creates {@link Result} from various XML representation. 586 * See {@link #_marshal(Object,Object)} for the conversion rules. 587 */ 588 private static Result toResult(Object xml) throws IOException { 589 if(xml==null) 590 throw new IllegalArgumentException("no XML is given"); 591 592 if (xml instanceof String) { 593 try { 594 xml=new URI((String)xml); 595 } catch (URISyntaxException e) { 596 xml=new File((String)xml); 597 } 598 } 599 if (xml instanceof File) { 600 File file = (File) xml; 601 return new StreamResult(file); 602 } 603 if (xml instanceof URI) { 604 URI uri = (URI) xml; 605 xml=uri.toURL(); 606 } 607 if (xml instanceof URL) { 608 URL url = (URL) xml; 609 URLConnection con = url.openConnection(); 610 con.setDoOutput(true); 611 con.setDoInput(false); 612 con.connect(); 613 return new StreamResult(con.getOutputStream()); 614 } 615 if (xml instanceof OutputStream) { 616 OutputStream os = (OutputStream) xml; 617 return new StreamResult(os); 618 } 619 if (xml instanceof Writer) { 620 Writer w = (Writer)xml; 621 return new StreamResult(w); 622 } 623 if (xml instanceof Result) { 624 return (Result) xml; 625 } 626 throw new IllegalArgumentException("I don't understand how to handle "+xml.getClass()); 627 } 628 629 }