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