1 /** 2 * Redistribution and use of this software and associated documentation ("Software"), with or 3 * without modification, are permitted provided that the following conditions are met: 4 * 5 * 1. Redistributions of source code must retain copyright statements and notices. Redistributions 6 * must also contain a copy of this document. 7 * 8 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 9 * conditions and the following disclaimer in the documentation and/or other materials provided with 10 * the distribution. 11 * 12 * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software 13 * without prior written permission of Intalio, Inc. For written permission, please contact 14 * info@exolab.org. 15 * 16 * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in 17 * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of 18 * Intalio, Inc. 19 * 20 * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/). 21 * 22 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 29 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved. 32 * 33 * $Id$ 34 */ 35 36 package org.exolab.castor.xml; 37 38 import java.io.PrintWriter; 39 import java.io.Reader; 40 import java.util.HashMap; 41 import java.util.Iterator; 42 import java.util.StringTokenizer; 43 44 import javax.xml.stream.XMLEventReader; 45 import javax.xml.stream.XMLStreamReader; 46 import javax.xml.transform.Source; 47 import javax.xml.transform.dom.DOMSource; 48 import javax.xml.transform.sax.SAXSource; 49 import javax.xml.transform.stream.StreamSource; 50 51 import org.apache.commons.logging.Log; 52 import org.apache.commons.logging.LogFactory; 53 import org.castor.mapping.BindingType; 54 import org.castor.mapping.MappingUnmarshaller; 55 import org.castor.xml.BackwardCompatibilityContext; 56 import org.castor.xml.InternalContext; 57 import org.castor.xml.UnmarshalListenerAdapter; 58 import org.castor.xml.XMLProperties; 59 import org.exolab.castor.mapping.Mapping; 60 import org.exolab.castor.mapping.MappingException; 61 import org.exolab.castor.mapping.MappingLoader; 62 import org.exolab.castor.types.AnyNode; 63 import org.exolab.castor.util.ObjectFactory; 64 import org.exolab.castor.xml.location.FileLocation; 65 import org.exolab.castor.xml.util.AnyNode2SAX2; 66 import org.exolab.castor.xml.util.DOMEventProducer; 67 import org.w3c.dom.Node; 68 import org.xml.sax.ContentHandler; 69 import org.xml.sax.EntityResolver; 70 import org.xml.sax.InputSource; 71 import org.xml.sax.Parser; 72 import org.xml.sax.SAXException; 73 import org.xml.sax.XMLReader; 74 75 /** 76 * An unmarshaller to allowing unmarshalling of XML documents to Java Objects. The Class must 77 * specify the proper access methods (setters/getters) in order for instances of the Class to be 78 * properly unmarshalled. 79 * 80 * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a> 81 * @version $Revision$ $Date: 2006-02-23 14:16:51 -0700 (Thu, 23 Feb 2006) $ 82 */ 83 public class Unmarshaller { 84 85 /** 86 * Logger from commons-logging. 87 */ 88 private static final Log LOG = LogFactory.getLog(Unmarshaller.class); 89 90 // ----------------------------/ 91 // - Private Member Variables -/ 92 // ----------------------------/ 93 94 /** 95 * The Class that this Unmarshaller was created with. 96 */ 97 private Class _class = null; 98 99 /** 100 * A boolean indicating whether or not collections (including arrays) should be cleared upon 101 * initial use by Castor. False by default for backward compatibility. 102 */ 103 private boolean _clearCollections = false; 104 105 /** 106 * A user specified IDResolver for resolving IDREFs. 107 */ 108 private IDResolver _idResolver = null; 109 110 /** 111 * A boolean that specifies whether or not non-matched attributes should be ignored upon 112 * unmarshalling. 113 */ 114 private boolean _ignoreExtraAtts = true; 115 116 /** 117 * A boolean that specifies whether or not non-matched elements should be ignored upon 118 * unmarshalling. 119 */ 120 private boolean _ignoreExtraElements = false; 121 122 /** 123 * The instance of _class to Unmarshal into (optional) 124 */ 125 private Object _instanceObj = null; 126 127 /** 128 * The EntityResolver used for resolving entities 129 */ 130 EntityResolver entityResolver = null; 131 132 /** 133 * The class loader to use 134 */ 135 private ClassLoader _loader = null; 136 137 /** 138 * A boolean to indicate that objects should be re-used where appropriate 139 */ 140 private boolean _reuseObjects = false; 141 142 143 /** 144 * The unmarshaller listener that listens to unmarshalling event 145 */ 146 private org.castor.xml.UnmarshalListener _unmarshalListener = null; 147 148 /** 149 * The flag indicating whether or not to validate during unmarshalling 150 */ 151 private boolean _validate = false; 152 153 /** 154 * A flag indicating the unmarshaller should preserve "ignorable" whitespace. The XML instance can 155 * control it's own behavior using the xml:space attribute. This sets the "default" behavior when 156 * xml:space="default". 157 */ 158 private boolean _wsPreserve = false; 159 160 /** 161 * A list of namespace To Package Mappings 162 */ 163 private HashMap _namespaceToPackage = null; 164 165 /** 166 * An optional factory for unmarshalling objects 167 */ 168 private ObjectFactory _objectFactory; 169 170 /** 171 * The Castor XML context to use at unmarshalling. 172 */ 173 private InternalContext _internalContext; 174 175 // ----------------/ 176 // - Constructors -/ 177 // ----------------/ 178 179 /** 180 * An empty default constructor which: - sets the internal context to the backward compatibility 181 * context - all other flags to defaults Internally the Unmarshaller(Class) constructor is called. 182 */ 183 public Unmarshaller() { 184 this((Class) null); 185 } 186 187 /** 188 * A constructor which sets the root class. 189 * 190 * Internally calls constructor Unmarshaller(InternalContext, Class) with an instance of 191 * BackwardCompatibilityContext as context. 192 * 193 * @param clazz root class for unmarshalling 194 */ 195 public Unmarshaller(final Class clazz) { 196 this(new BackwardCompatibilityContext(), clazz); 197 } 198 199 /** 200 * Creates a new basic Unmarshaller. 201 * 202 * When using this constructor it will most likely be necessary to use a mapping file or 203 * ClassDescriptorResolver So that the Unmarshaller can find the classes during the unmarshalling 204 * process. 205 * 206 * @param internalContext the {@link InternalContext} to use 207 * 208 * @throws IllegalArgumentException if internalContext is null 209 */ 210 public Unmarshaller(final InternalContext internalContext) { 211 this(internalContext, (Class) null, (ClassLoader) null); 212 } 213 214 /** 215 * Creates a new Unmarshaller with the given Class. 216 * 217 * @param internalContext the {@link InternalContext} to use 218 * @param c the Class to create the Unmarshaller for, this may be null, if the 219 * Unmarshaller#setMapping is called to load a mapping for the root element of xml 220 * document. 221 * 222 * @throws IllegalArgumentException if internalContext is null 223 */ 224 public Unmarshaller(final InternalContext internalContext, final Class c) { 225 this(internalContext, c, null); 226 } // -- Unmarshaller(Class) 227 228 /** 229 * Creates a new {@link Unmarshaller} with the given Class. 230 * 231 * @param internalContext the {@link InternalContext} to be used, for config, and such... 232 * @param c the {@link Class} to create the {@link Unmarshaller} for, this may be null, if the 233 * Unmarshaller#setMapping is called to load a mapping for the root element of xml 234 * document. 235 * @param loader The {@link ClassLoader} to use. 236 * 237 * @throws IllegalArgumentException if internalContext is null 238 */ 239 public Unmarshaller(final InternalContext internalContext, final Class c, 240 final ClassLoader loader) { 241 super(); 242 243 checkNotNull(internalContext, "InternalContext must not be null."); 244 setInternalContext(internalContext); 245 246 setClass(c); 247 _loader = loader; 248 if ((loader == null) && (c != null)) { 249 _loader = c.getClassLoader(); 250 } 251 _internalContext.setClassLoader(_loader); 252 } 253 254 /** 255 * Creates a new Unmarshaller with the given Mapping. An instance of BackwardsCompatibilityContext 256 * is used as InternalContext. 257 * 258 * @param mapping The Mapping to use. 259 * @throws MappingException in case that Unmarshaller fails to be instantiated 260 */ 261 public Unmarshaller(final Mapping mapping) throws MappingException { 262 this(new BackwardCompatibilityContext(), mapping); 263 } 264 265 /** 266 * Creates a new Unmarshaller with the given Mapping. 267 * 268 * @param internalContext the internal context to use 269 * @param mapping The Mapping to use. 270 * @throws MappingException in case that Unmarshaller fails to be instantiated 271 * 272 * @throws IllegalArgumentException if internalContext is null 273 */ 274 public Unmarshaller(final InternalContext internalContext, final Mapping mapping) 275 throws MappingException { 276 this(internalContext, null, null); 277 if (mapping != null) { 278 setMapping(mapping); 279 this._loader = mapping.getClassLoader(); 280 } 281 } 282 283 /** 284 * Creates a new Unmarshaller with the given Object. 285 * 286 * @param root the instance to unmarshal into. This may be null, if the Unmarshaller#setMapping is 287 * called to load a mapping for the root element of xml document. 288 */ 289 public Unmarshaller(final Object root) { 290 this(new BackwardCompatibilityContext(), root); 291 } 292 293 /** 294 * Creates a new Unmarshaller with the given Object. 295 * 296 * @param internalContext the internal context to use 297 * @param root the instance to unmarshal into. This may be null, if the Unmarshaller#setMapping is 298 * called to load a mapping for the root element of xml document. 299 * 300 * @throws IllegalArgumentException if internalContext is null 301 */ 302 public Unmarshaller(final InternalContext internalContext, final Object root) { 303 this(internalContext, null, null); 304 if (root != null) { 305 final Class clazz = root.getClass(); 306 setClass(clazz); 307 _loader = clazz.getClassLoader(); 308 } 309 _instanceObj = root; 310 } 311 312 /** 313 * Adds a mapping from the given namespace URI to the given package name. 314 * 315 * @param nsURI the namespace URI to map from 316 * @param packageName the package name to map to 317 */ 318 public void addNamespaceToPackageMapping(final String nsURI, final String packageName) { 319 if (_namespaceToPackage == null) { 320 _namespaceToPackage = new HashMap(); 321 } 322 String iNsUri = (nsURI == null) ? "" : nsURI; 323 String iPackageName = (packageName == null) ? "" : packageName; 324 _namespaceToPackage.put(iNsUri, iPackageName); 325 326 } // -- addNamespaceToPackageMapping 327 328 329 /** 330 * Creates and initalizes an UnmarshalHandler 331 * 332 * @return the new UnmarshalHandler 333 **/ 334 public UnmarshalHandler createHandler() { 335 336 UnmarshalHandler handler = new UnmarshalHandler(_internalContext, _class); 337 338 handler.setClearCollections(_clearCollections); 339 handler.setReuseObjects(_reuseObjects); 340 handler.setValidation(_validate); 341 handler.setIgnoreExtraAttributes(_ignoreExtraAtts); 342 handler.setIgnoreExtraElements(_ignoreExtraElements); 343 handler.setInternalContext(_internalContext); 344 handler.setWhitespacePreserve(_wsPreserve); 345 346 // If the object factory has been set, set it on the handler 347 if (this._objectFactory != null) { 348 handler.setObjectFactory(this._objectFactory); 349 } 350 351 // -- copy namespaceToPackageMappings 352 if (_namespaceToPackage != null) { 353 Iterator keys = _namespaceToPackage.keySet().iterator(); 354 while (keys.hasNext()) { 355 String nsURI = (String) keys.next(); 356 String pkgName = (String) _namespaceToPackage.get(nsURI); 357 handler.addNamespaceToPackageMapping(nsURI, pkgName); 358 } 359 } 360 361 if (_instanceObj != null) { 362 handler.setRootObject(_instanceObj); 363 } 364 if (_idResolver != null) 365 handler.setIDResolver(_idResolver); 366 367 if (_loader != null) 368 handler.setClassLoader(_loader); 369 370 if (_unmarshalListener != null) 371 handler.setUnmarshalListener(_unmarshalListener); 372 373 return handler; 374 } // -- createHandler 375 376 /** 377 * Indicates whether or not validation should be performed during umarshalling. 378 * 379 * @return True if validation is performed during umarshalling. 380 */ 381 public boolean isValidating() { 382 return _validate; 383 } 384 385 /** 386 * Sets the 'expected' {@link Class} instance on the Unmarshaller. 387 * 388 * @param clazz the Class to create the Unmarshaller for, this may be null, if the 389 * Unmarshaller#setMapping is called to load a mapping for the root element of xml 390 * document. 391 */ 392 public void setClass(Class clazz) { 393 _class = clazz; 394 } // -- setClass(Class) 395 396 /** 397 * Sets the 'expected' {@link Object} instance on the Unmarshaller, into which will be 398 * unmarshalled. 399 * 400 * @param root the instance to unmarshal into. This may be null, if the Unmarshaller#setMapping is 401 * called to load a mapping for the root element of xml document. 402 */ 403 public void setObject(Object root) { 404 _instanceObj = root; 405 } // -- setObject(Object) 406 407 /** 408 * Sets the ClassLoader to use when loading new classes. <br /> 409 * <b>Note:</b>This ClassLoader is used for classes loaded by the unmarshaller only. If a Mapping 410 * has been set, the Mapping has it's own ClassLoader and may also need to be set propertly. 411 * <br /> 412 * 413 * @param loader the ClassLoader to use 414 **/ 415 public void setClassLoader(ClassLoader loader) { 416 this._loader = loader; 417 } // -- setClassLoader 418 419 420 /** 421 * Sets whether or not to clear collections (including arrays) upon first use to remove default 422 * values. By default, and for backward compatibility with previous versions of Castor this value 423 * is false, indicating that collections are not cleared before initial use by Castor. 424 * 425 * @param clear the boolean value that when true indicates collections should be cleared upon 426 * first use. 427 */ 428 public void setClearCollections(boolean clear) { 429 _clearCollections = clear; 430 } // -- setClearCollections 431 432 /** 433 * Custom debugging is replaced with commons-logging 434 * 435 * @deprecated 436 **/ 437 public void setDebug(boolean debug) { 438 // no-op 439 } // -- setDebug 440 441 /** 442 * Sets the EntityResolver to use when resolving system and public ids with respect to entites and 443 * Document Type. 444 * 445 * @param entityResolver the EntityResolver to use when resolving System and Public ids. 446 **/ 447 public void setEntityResolver(EntityResolver entityResolver) { 448 this.entityResolver = entityResolver; 449 } // -- entityResolver 450 451 /** 452 * Sets the IDResolver to use when resolving IDREFs for which no associated element may exist in 453 * XML document. 454 * 455 * @param idResolver the IDResolver to use when resolving IDREFs for which no associated element 456 * may exist in the XML document. 457 **/ 458 public void setIDResolver(IDResolver idResolver) { 459 _idResolver = idResolver; 460 } // -- idResolver 461 462 /** 463 * Sets whether or not attributes that do not match a specific field should simply be ignored or 464 * reported as an error. By default, extra attributes are ignored. 465 * 466 * @param ignoreExtraAtts a boolean that when true will allow non-matched attributes to simply be 467 * ignored. 468 */ 469 public void setIgnoreExtraAttributes(boolean ignoreExtraAtts) { 470 _ignoreExtraAtts = ignoreExtraAtts; 471 } // -- setIgnoreExtraAttributes 472 473 /** 474 * Sets whether or not elements that do not match a specific field should simply be ignored or 475 * reported as an error. By default, extra elements are flagged as an error. 476 * 477 * @param ignoreExtraElements a boolean that when true will allow non-matched elements to simply 478 * be ignored. 479 */ 480 public void setIgnoreExtraElements(boolean ignoreExtraElements) { 481 _ignoreExtraElements = ignoreExtraElements; 482 } // -- setIgnoreExtraElements 483 484 /** 485 * Logging is replaced with commons-logging. 486 * 487 * @param printWriter the PrintWriter to use for logging 488 * @deprecated 489 **/ 490 public void setLogWriter(PrintWriter printWriter) { 491 // no-op 492 } // -- setLogWriter 493 494 /** 495 * Sets the Mapping to use during unmarshalling. If the Mapping has a ClassLoader it will be used 496 * during unmarshalling. 497 * 498 * @param mapping Mapping to use during unmarshalling. 499 * @see #setResolver 500 */ 501 public void setMapping(final Mapping mapping) throws MappingException { 502 if (_loader == null) { 503 _loader = mapping.getClassLoader(); 504 } 505 506 MappingUnmarshaller mum = new MappingUnmarshaller(); 507 MappingLoader resolver = mum.getMappingLoader(mapping, BindingType.XML); 508 _internalContext.getXMLClassDescriptorResolver().setMappingLoader(resolver); 509 } 510 511 /** 512 * Sets a boolean that when true indicates that objects contained within the object model should 513 * be re-used where appropriate. This is only valid when unmarshalling to an existing object. 514 * 515 * @param reuse the boolean indicating whether or not to re-use existing objects in the object 516 * model. 517 **/ 518 public void setReuseObjects(boolean reuse) { 519 _reuseObjects = reuse; 520 } // -- setReuseObjects 521 522 /** 523 * Sets an optional {@link org.exolab.castor.xml.UnmarshalListener} to receive pre and post 524 * unmarshal notification for each Object in the tree. An UnmarshalListener is often used to allow 525 * objects to appropriately initialize themselves by taking application specific behavior as they 526 * are unloaded. Current only one (1) listener is allowed. If you need register multiple 527 * listeners, you will have to create your own master listener that will forward the event 528 * notifications and manage the multiple listeners.<br/> 529 * The deprecated listener set with this method will be wrapped by an adapter. 530 * 531 * @param listener the {@link org.exolab.castor.xml.UnmarshalListener} to set. 532 * @deprecated replaced by {@link org.castor.xml.UnmarshalListener} 533 */ 534 public void setUnmarshalListener(org.exolab.castor.xml.UnmarshalListener listener) { 535 if (listener == null) { 536 _unmarshalListener = null; 537 } else { 538 UnmarshalListenerAdapter adapter = new UnmarshalListenerAdapter(); 539 adapter.setOldListener(listener); 540 _unmarshalListener = adapter; 541 } 542 } 543 544 /** 545 * Sets an optional {@link org.castor.xml.UnmarshalListener} to receive pre and post unmarshal 546 * notification for each Object in the tree. An UnmarshalListener is often used to allow objects 547 * to appropriately initialize themselves by taking application specific behavior as they are 548 * unloaded. Current only one (1) listener is allowed. If you need register multiple listeners, 549 * you will have to create your own master listener that will forward the event notifications and 550 * manage the multiple listeners. 551 * 552 * @param listener the {@link org.castor.xml.UnmarshalListener} to set. 553 */ 554 public void setUnmarshalListener(org.castor.xml.UnmarshalListener listener) { 555 _unmarshalListener = listener; 556 } 557 558 /** 559 * Sets the flag for validation. 560 * 561 * @param validate A boolean to indicate whether or not validation should be done during 562 * umarshalling. <br/> 563 * By default validation will be performed. 564 */ 565 public void setValidation(boolean validate) { 566 _validate = validate; 567 } // -- setValidation 568 569 /** 570 * Sets the top-level whitespace (xml:space) to either preserving or non preserving. The XML 571 * document can override this value using xml:space on specific elements.This sets the "default" 572 * behavior when xml:space="default". 573 * 574 * @param preserve a boolean that when true enables whitespace preserving by default. 575 */ 576 public void setWhitespacePreserve(boolean preserve) { 577 _wsPreserve = preserve; 578 } // -- setWhitespacePreserve 579 580 /** 581 * Unmarshals Objects of this Unmarshaller's Class type. The Class must specify the proper access 582 * methods (setters/getters) in order for instances of the Class to be properly unmarshalled. 583 * 584 * @param reader the Reader to read the XML from 585 * @exception MarshalException when there is an error during the unmarshalling process 586 * @exception ValidationException when there is a validation error 587 **/ 588 public Object unmarshal(Reader reader) throws MarshalException, ValidationException { 589 return unmarshal(new InputSource(reader)); 590 } // -- unmarshal(Reader reader) 591 592 /** 593 * Unmarshals Objects of this Unmarshaller's Class type. The Class must specify the proper access 594 * methods (setters/getters) in order for instances of the Class to be properly unmarshalled. 595 * 596 * @param eventProducer the EventProducer which produces the SAX events 597 * @exception MarshalException when there is an error during the unmarshalling process 598 * @exception ValidationException when there is a validation error 599 * @deprecated please use @see #unmarshal(SAX2EventProducer) instead. 600 **/ 601 public Object unmarshal(EventProducer eventProducer) 602 throws MarshalException, ValidationException { 603 UnmarshalHandler handler = createHandler(); 604 eventProducer.setDocumentHandler(handler); 605 try { 606 eventProducer.start(); 607 } catch (org.xml.sax.SAXException sx) { 608 convertSAXExceptionToMarshalException(handler, sx); 609 } 610 return handler.getObject(); 611 612 } // -- unmarshal(EventProducer) 613 614 /** 615 * Unmarshals Objects of this Unmarshaller's Class type. The Class must specify the proper access 616 * methods (setters/getters) in order for instances of the Class to be properly unmarshalled. 617 * 618 * @param eventProducer the SAX2EventProducer instance which produces the SAX 2 events 619 * @exception MarshalException when there is an error during the unmarshalling process 620 * @exception ValidationException when there is a validation error 621 * @since 1.0M3 622 **/ 623 public Object unmarshal(SAX2EventProducer eventProducer) 624 throws MarshalException, ValidationException { 625 UnmarshalHandler handler = createHandler(); 626 eventProducer.setContentHandler(handler); 627 try { 628 eventProducer.start(); 629 } catch (org.xml.sax.SAXException sx) { 630 convertSAXExceptionToMarshalException(handler, sx); 631 } 632 return handler.getObject(); 633 634 } // -- unmarshal(SAX2EventProducer) 635 636 /** 637 * Unmarshals objects of this {@link Unmarshaller}'s Class type from an {@link AnyNode} instance. 638 * 639 * The Class must specify the proper access methods (setters/getters) in order for instances of 640 * the Class to be properly unmarshalled. 641 * 642 * @param anyNode {@link AnyNode} instance to be unmarshalled from 643 * @exception MarshalException when there is an error during the unmarshalling process 644 * @return The {@link Object} instance that is a result of unmarshalling. 645 **/ 646 public Object unmarshal(final AnyNode anyNode) throws MarshalException { 647 UnmarshalHandler handler = createHandler(); 648 try { 649 AnyNode2SAX2.fireEvents(anyNode, handler); 650 } catch (SAXException sex) { 651 convertSAXExceptionToMarshalException(handler, sex); 652 } 653 return handler.getObject(); 654 } 655 656 /** 657 * Unmarshals Objects of this Unmarshaller's Class type. The Class must specify the proper access 658 * methods (setters/getters) in order for instances of the Class to be properly unmarshalled. 659 * 660 * @param source the InputSource to read the XML from 661 * @exception MarshalException when there is an error during the unmarshalling process 662 * @exception ValidationException when there is a validation error 663 **/ 664 public Object unmarshal(InputSource source) throws MarshalException, ValidationException { 665 XMLReader reader = null; 666 Parser parser = null; 667 668 // -- First try XMLReader 669 try { 670 reader = _internalContext.getXMLReader(); 671 if (entityResolver != null) { 672 reader.setEntityResolver(entityResolver); 673 } 674 } catch (RuntimeException rx) { 675 LOG.debug("Unable to create SAX XMLReader, attempting SAX Parser."); 676 } 677 678 if (reader == null) { 679 parser = _internalContext.getParser(); 680 if (parser == null) 681 throw new MarshalException("Unable to create SAX Parser."); 682 if (entityResolver != null) 683 parser.setEntityResolver(entityResolver); 684 } 685 686 687 UnmarshalHandler handler = createHandler(); 688 689 690 try { 691 if (reader != null) { 692 reader.setContentHandler(handler); 693 reader.setErrorHandler(handler); 694 reader.parse(source); 695 } else { 696 parser.setDocumentHandler(handler); 697 parser.setErrorHandler(handler); 698 parser.parse(source); 699 } 700 } catch (java.io.IOException ioe) { 701 throw new MarshalException(ioe); 702 } catch (org.xml.sax.SAXException sx) { 703 convertSAXExceptionToMarshalException(handler, sx); 704 } 705 706 return handler.getObject(); 707 } // -- unmarshal(InputSource) 708 709 710 /** 711 * Unmarshals Objects of this Unmarshaller's Class type. The Class must specify the proper access 712 * methods (setters/getters) in order for instances of the Class to be properly unmarshalled. 713 * 714 * @param node the DOM node to read the XML from 715 * @exception MarshalException when there is an error during the unmarshalling process 716 * @exception ValidationException when there is a validation error 717 **/ 718 public Object unmarshal(Node node) throws MarshalException, ValidationException { 719 return unmarshal(new DOMEventProducer(node)); 720 } // -- unmarshal(EventProducer) 721 722 /** 723 * Unmarshals objects of this {@link Unmarshaller}'s class type. The class must specify the proper 724 * access methods (setters/getters) in order for instances of the class to be properly 725 * unmarshalled. 726 * 727 * @param eventReader the StaX {@link XMLEventReader} to read XML from. 728 * @exception MarshalException indicates a general problem during the unmarshalling process. 729 * @throws ValidationException indicates a problem related to validation. 730 * 731 * @since 1.3.2 732 **/ 733 public Object unmarshal(XMLEventReader eventReader) throws MarshalException, ValidationException { 734 return unmarshal(BaseSax2EventFromStaxProducer.createSax2EventFromStax(eventReader)); 735 } 736 737 /** 738 * Unmarshals objects of this {@link Unmarshaller}'s class type. The class must specify the proper 739 * access methods (setters/getters) in order for instances of the class to be properly 740 * unmarshalled. 741 * 742 * @param streamReader the STaX {@link XMLStreamReader} to read XML from. 743 * @exception MarshalException indicates a general problem during the unmarshalling process. 744 * @throws ValidationException indicates a problem related to validation. 745 * 746 * @since 1.3.2 747 **/ 748 public Object unmarshal(XMLStreamReader streamReader) 749 throws MarshalException, ValidationException { 750 return unmarshal(BaseSax2EventFromStaxProducer.createSax2EventFromStax(streamReader)); 751 } 752 753 /** 754 * Unmarshals objects of this {@link Unmarshaller}'s class type. <br/> 755 * The class must specify the proper access methods (setters/getters) in order for instances of 756 * the class to be properly unmarshalled. </br/> 757 * 758 * @param eventProducer the {@link SAX2EventAndErrorProducer} instance which produces the SAX 2 759 * events and handles SAX 2 errors. 760 * @exception MarshalException indiactes a general error during the unmarshalling process. 761 * @exception ValidationException indicates a validation error. 762 * @since 1.3.2 763 **/ 764 public Object unmarshal(SAX2EventAndErrorProducer eventProducer) 765 throws MarshalException, ValidationException { 766 UnmarshalHandler handler = createHandler(); 767 eventProducer.setContentHandler(handler); 768 eventProducer.setErrorHandler(handler); 769 try { 770 eventProducer.start(); 771 } catch (org.xml.sax.SAXException sx) { 772 convertSAXExceptionToMarshalException(handler, sx); 773 } 774 return handler.getObject(); 775 776 } 777 778 /** 779 * Unmarshals ths given {@link Source} instance. Currently this method will support fallowing 780 * classes {@link DOMSource}, {@link SAXSource} and {@link StreamSource}. 781 * 782 * @param source the source to unmarshal 783 * 784 * @return the unmarshalled object instance 785 * 786 * @throws IllegalArgumentException if the given source is null or it is unsupported 787 * @throws MarshalException indiactes a general error during the unmarshalling process. 788 * @throws ValidationException indicates a validation error. 789 */ 790 public Object unmarshal(Source source) throws MarshalException, ValidationException { 791 checkNotNull(source, "The given 'javax.xml.transform.Source' instance is null."); 792 793 if (source instanceof DOMSource) { 794 DOMSource domSource = (DOMSource) source; 795 if (domSource.getNode() != null) { 796 return unmarshal(domSource.getNode()); 797 } 798 } else if (source instanceof SAXSource) { 799 SAXSource saxSource = (SAXSource) source; 800 801 if (saxSource.getInputSource() != null) { 802 // TODO should the XMLReader from the SAXSource should be used instead ? 803 return unmarshal(saxSource.getInputSource()); 804 } 805 } else if (source instanceof StreamSource) { 806 StreamSource streamSource = (StreamSource) source; 807 808 if (streamSource.getInputStream() != null) { 809 return unmarshal(new InputSource(streamSource.getInputStream())); 810 } else if (streamSource.getReader() != null) { 811 return unmarshal(streamSource.getReader()); 812 } 813 } 814 815 throw new IllegalArgumentException( 816 "The given 'javax.transform.xml.Source' is not supported, or were incorrectly instantiated."); 817 } 818 819 /** 820 * Converts a SAXException to a (localised) MarshalException. 821 * 822 * @param handler The {@link UnmarshalHandler} required to obtain DocumentLocator instance. 823 * @param sex The {@link SAXException} instance 824 * @throws MarshalException The {@link MarshalException} instance derived from the SAX exception. 825 */ 826 private void convertSAXExceptionToMarshalException(UnmarshalHandler handler, SAXException sex) 827 throws MarshalException { 828 Exception except = sex.getException(); 829 if (except == null) { 830 except = sex; 831 } 832 MarshalException marshalEx = new MarshalException(except); 833 if (handler.getDocumentLocator() != null) { 834 FileLocation location = new FileLocation(); 835 location.setFilename(handler.getDocumentLocator().getSystemId()); 836 location.setLineNumber(handler.getDocumentLocator().getLineNumber()); 837 location.setColumnNumber(handler.getDocumentLocator().getColumnNumber()); 838 marshalEx.setLocation(location); 839 } 840 throw marshalEx; 841 } 842 843 // -------------------------/ 844 // - Public Static Methods -/ 845 // -------------------------/ 846 /** 847 * Returns a ContentHandler for the given UnmarshalHandler 848 * 849 * @return the ContentHandler 850 */ 851 public static ContentHandler getContentHandler(UnmarshalHandler handler) throws SAXException { 852 return handler; 853 } // -- getContentHandler 854 855 /** 856 * Unmarshals Objects of the given Class type. The Class must specify the proper access methods 857 * (setters/getters) in order for instances of the Class to be properly unmarshalled. 858 * 859 * <p> 860 * <b>Note:</b>This is a *static* method, any mapping files set on a particular Unmarshaller 861 * instance, and any changes made via setters will be unavailable to this method. 862 * </p> 863 * 864 * @param c the Class to create a new instance of 865 * @param reader the Reader to read the XML from 866 * @exception MarshalException when there is an error during the unmarshalling process 867 * @exception ValidationException when there is a validation error 868 **/ 869 public static Object unmarshal(Class c, Reader reader) 870 throws MarshalException, ValidationException { 871 Unmarshaller unmarshaller = createUnmarshaller(c); 872 return unmarshaller.unmarshal(reader); 873 } // -- void unmarshal(Writer) 874 875 /** 876 * Helper method for static #unmarshal methods to create an {@link Unmarshaller} instance. 877 * 878 * @param clazz The root class to be used during unmarshalling. 879 * @return An {@link Unmarshaller} instance. 880 */ 881 private static Unmarshaller createUnmarshaller(final Class clazz) { 882 XMLContext xmlContext = new XMLContext(); 883 Unmarshaller unmarshaller = xmlContext.createUnmarshaller(); 884 unmarshaller.setClass(clazz); 885 886 // TODO: Should this be at level INFO? 887 if (LOG.isDebugEnabled()) { 888 LOG.debug("*static* unmarshal method called, this will ignore any " 889 + "mapping files or changes made to an Unmarshaller instance."); 890 } 891 892 // -- for backward compatibility with Castor versions 893 // -- prior to version 0.9.5.3 894 unmarshaller.setWhitespacePreserve(true); 895 896 return unmarshaller; 897 } 898 899 /** 900 * Unmarshals Objects of the given Class type. The Class must specify the proper access methods 901 * (setters/getters) in order for instances of the Class to be properly unmarshalled. 902 * 903 * <p> 904 * <b>Note:</b>This is a *static* method, any mapping files set on a particular Unmarshaller 905 * instance, and any changes made via setters will be unavailable to this method. 906 * </p> 907 * 908 * @param c the Class to create a new instance of 909 * @param source the InputSource to read the XML from 910 * @exception MarshalException when there is an error during the unmarshalling process 911 * @exception ValidationException when there is a validation error 912 */ 913 public static Object unmarshal(Class c, InputSource source) 914 throws MarshalException, ValidationException { 915 Unmarshaller unmarshaller = createUnmarshaller(c); 916 917 return unmarshaller.unmarshal(source); 918 } // -- void unmarshal(Writer) 919 920 /** 921 * Unmarshals Objects of the given Class type. The Class must specify the proper access methods 922 * (setters/getters) in order for instances of the Class to be properly unmarshalled. 923 * 924 * <p> 925 * <b>Note:</b>This is a *static* method, any mapping files set on a particular Unmarshaller 926 * instance, and any changes made via setters will be unavailable to this method. 927 * </p> 928 * 929 * @param c The Class to create a new instance of. 930 * @param node The DOM Node to read the XML from. 931 * @exception MarshalException When there is an error during the unmarshalling process. 932 * @exception ValidationException When there is a validation error. 933 */ 934 public static Object unmarshal(Class c, Node node) throws MarshalException, ValidationException { 935 Unmarshaller unmarshaller = createUnmarshaller(c); 936 937 return unmarshaller.unmarshal(node); 938 } // -- void unmarshal(Writer) 939 940 /** 941 * Set an object factory for the unmarshaller. This factory will be used to construct the objects 942 * being unmarshalled. 943 * 944 * @param objectFactory Factory used for constructing objects during unmarshalling. 945 */ 946 public void setObjectFactory(final ObjectFactory objectFactory) { 947 this._objectFactory = objectFactory; 948 } // -- setObjectFactory 949 950 /** 951 * Returns the value of the given Castor XML-specific property. 952 * 953 * @param name Qualified name of the CASTOR XML-specific property. 954 * @return The current value of the given property. 955 * @since 1.1.2 956 */ 957 public String getProperty(final String name) { 958 Object propertyValue = _internalContext.getProperty(name); 959 if ((propertyValue != null) && !(propertyValue instanceof String)) { 960 String message = "Requested property: " + name + " is not of type String, but: " 961 + propertyValue.getClass() + " throwing IllegalStateException."; 962 LOG.warn(message); 963 throw new IllegalStateException(message); 964 } 965 return (String) propertyValue; 966 } 967 968 /** 969 * Sets a custom value of a given Castor XML-specific property. 970 * 971 * @param name Name of the Castor XML property 972 * @param value Custom value to set. 973 * @since 1.1.2 974 */ 975 public void setProperty(final String name, final String value) { 976 _internalContext.setProperty(name, value); 977 } 978 979 /** 980 * To set the internal XML Context to be used. 981 * 982 * @param internalContext the context to be used 983 */ 984 public void setInternalContext(final InternalContext internalContext) { 985 _internalContext = internalContext; 986 deriveProperties(); 987 } 988 989 /** 990 * Derive class-level properties from {@link XMLProperties} as defined {@link InternalContext}. 991 * This method will be called after a new {@link InternalContext} has been set. 992 * 993 * @link #setInternalContext(InternalContext) 994 */ 995 private void deriveProperties() { 996 _validate = _internalContext.marshallingValidation(); 997 _ignoreExtraElements = (!_internalContext.strictElements()); 998 999 // -- process namespace to package mappings 1000 String mappings = _internalContext.getStringProperty(XMLProperties.NAMESPACE_PACKAGE_MAPPINGS); 1001 if (mappings != null && mappings.length() > 0) { 1002 StringTokenizer tokens = new StringTokenizer(mappings, ","); 1003 while (tokens.hasMoreTokens()) { 1004 String token = tokens.nextToken(); 1005 int sepIdx = token.indexOf('='); 1006 if (sepIdx < 0) { 1007 continue; 1008 } 1009 String ns = token.substring(0, sepIdx).trim(); 1010 String javaPackage = token.substring(sepIdx + 1).trim(); 1011 addNamespaceToPackageMapping(ns, javaPackage); 1012 } 1013 } 1014 } 1015 1016 /** 1017 * To get the internal XML Context that is in use. 1018 * 1019 * @return the {@link InternalContext} in use 1020 */ 1021 public InternalContext getInternalContext() { 1022 return _internalContext; 1023 } 1024 1025 /** 1026 * Sets the XMLClassDescriptorResolver to use during unmarshalling 1027 * 1028 * @param xmlClassDescriptorResolver the XMLClassDescriptorResolver to use 1029 * @see #setMapping <BR /> 1030 * <B>Note:</B> This method will nullify any Mapping currently being used by this 1031 * Unmarshaller 1032 */ 1033 public void setResolver(XMLClassDescriptorResolver xmlClassDescriptorResolver) { 1034 _internalContext.setResolver(xmlClassDescriptorResolver); 1035 } 1036 1037 /** 1038 * Checks if passed parameter is not null. In case it is, a {@link IllegalArgumentException} is 1039 * thrown. 1040 * 1041 * @param param the parameter to check 1042 * @param msg the error message to use for thrown exception 1043 * 1044 * @throws IllegalArgumentException if param is null 1045 */ 1046 private static void checkNotNull(Object param, String msg) { 1047 1048 if (param == null) { 1049 throw new IllegalArgumentException(msg); 1050 } 1051 } 1052 } // -- Unmarshaller 1053