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