001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.oxm.castor; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.OutputStream; 022import java.io.OutputStreamWriter; 023import java.io.Reader; 024import java.io.Writer; 025import java.util.Map; 026import javax.xml.stream.XMLEventReader; 027import javax.xml.stream.XMLEventWriter; 028import javax.xml.stream.XMLStreamReader; 029import javax.xml.stream.XMLStreamWriter; 030 031import org.exolab.castor.mapping.Mapping; 032import org.exolab.castor.mapping.MappingException; 033import org.exolab.castor.util.ObjectFactory; 034import org.exolab.castor.xml.IDResolver; 035import org.exolab.castor.xml.MarshalException; 036import org.exolab.castor.xml.Marshaller; 037import org.exolab.castor.xml.ResolverException; 038import org.exolab.castor.xml.UnmarshalHandler; 039import org.exolab.castor.xml.Unmarshaller; 040import org.exolab.castor.xml.ValidationException; 041import org.exolab.castor.xml.XMLClassDescriptorResolver; 042import org.exolab.castor.xml.XMLContext; 043import org.exolab.castor.xml.XMLException; 044import org.w3c.dom.Node; 045import org.xml.sax.ContentHandler; 046import org.xml.sax.EntityResolver; 047import org.xml.sax.InputSource; 048import org.xml.sax.SAXException; 049import org.xml.sax.XMLReader; 050import org.xml.sax.ext.LexicalHandler; 051 052import org.springframework.beans.factory.BeanClassLoaderAware; 053import org.springframework.beans.factory.InitializingBean; 054import org.springframework.core.io.Resource; 055import org.springframework.oxm.MarshallingFailureException; 056import org.springframework.oxm.UncategorizedMappingException; 057import org.springframework.oxm.UnmarshallingFailureException; 058import org.springframework.oxm.ValidationFailureException; 059import org.springframework.oxm.XmlMappingException; 060import org.springframework.oxm.support.AbstractMarshaller; 061import org.springframework.oxm.support.SaxResourceUtils; 062import org.springframework.util.ObjectUtils; 063import org.springframework.util.xml.DomUtils; 064import org.springframework.util.xml.StaxUtils; 065 066/** 067 * Implementation of the {@code Marshaller} interface for Castor. By default, Castor does 068 * not require any further configuration, though setting target classes, target packages or 069 * providing a mapping file can be used to have more control over the behavior of Castor. 070 * 071 * <p>If a target class is specified using {@code setTargetClass}, the {@code CastorMarshaller} 072 * can only be used to unmarshal XML that represents that specific class. If you want to unmarshal 073 * multiple classes, you have to provide a mapping file using {@code setMappingLocations}. 074 * 075 * <p>Due to limitations of Castor's API, it is required to set the encoding used for writing 076 * to output streams. It defaults to {@code UTF-8}. 077 * 078 * @author Arjen Poutsma 079 * @author Jakub Narloch 080 * @author Juergen Hoeller 081 * @since 3.0 082 * @see #setEncoding(String) 083 * @see #setTargetClass(Class) 084 * @see #setTargetPackages(String[]) 085 * @see #setMappingLocation(Resource) 086 * @see #setMappingLocations(Resource[]) 087 * @deprecated as of Spring Framework 4.3.13, due to the lack of activity on the Castor project 088 */ 089@Deprecated 090public class CastorMarshaller extends AbstractMarshaller implements InitializingBean, BeanClassLoaderAware { 091 092 /** 093 * The default encoding used for stream access: UTF-8. 094 */ 095 public static final String DEFAULT_ENCODING = "UTF-8"; 096 097 098 private Resource[] mappingLocations; 099 100 private String encoding = DEFAULT_ENCODING; 101 102 private Class<?>[] targetClasses; 103 104 private String[] targetPackages; 105 106 private boolean validating = false; 107 108 private boolean suppressNamespaces = false; 109 110 private boolean suppressXsiType = false; 111 112 private boolean marshalAsDocument = true; 113 114 private boolean marshalExtendedType = true; 115 116 private String rootElement; 117 118 private String noNamespaceSchemaLocation; 119 120 private String schemaLocation; 121 122 private boolean useXSITypeAtRoot = false; 123 124 private boolean whitespacePreserve = false; 125 126 private boolean ignoreExtraAttributes = true; 127 128 private boolean ignoreExtraElements = false; 129 130 private Object rootObject; 131 132 private boolean reuseObjects = false; 133 134 private boolean clearCollections = false; 135 136 private Map<String, String> castorProperties; 137 138 private Map<String, String> doctypes; 139 140 private Map<String, String> processingInstructions; 141 142 private Map<String, String> namespaceMappings; 143 144 private Map<String, String> namespaceToPackageMapping; 145 146 private EntityResolver entityResolver; 147 148 private XMLClassDescriptorResolver classDescriptorResolver; 149 150 private IDResolver idResolver; 151 152 private ObjectFactory objectFactory; 153 154 private ClassLoader beanClassLoader; 155 156 private XMLContext xmlContext; 157 158 159 /** 160 * Set the encoding to be used for stream access. 161 * @see #DEFAULT_ENCODING 162 */ 163 public void setEncoding(String encoding) { 164 this.encoding = encoding; 165 } 166 167 @Override 168 protected String getDefaultEncoding() { 169 return this.encoding; 170 } 171 172 /** 173 * Set the locations of the Castor XML mapping files. 174 */ 175 public void setMappingLocation(Resource mappingLocation) { 176 this.mappingLocations = new Resource[]{mappingLocation}; 177 } 178 179 /** 180 * Set the locations of the Castor XML mapping files. 181 */ 182 public void setMappingLocations(Resource... mappingLocations) { 183 this.mappingLocations = mappingLocations; 184 } 185 186 /** 187 * Set the Castor target class. 188 * @see #setTargetPackage 189 * @see #setMappingLocation 190 */ 191 public void setTargetClass(Class<?> targetClass) { 192 this.targetClasses = new Class<?>[] {targetClass}; 193 } 194 195 /** 196 * Set the Castor target classes. 197 * @see #setTargetPackages 198 * @see #setMappingLocations 199 */ 200 public void setTargetClasses(Class<?>... targetClasses) { 201 this.targetClasses = targetClasses; 202 } 203 204 /** 205 * Set the name of a package with the Castor descriptor classes. 206 */ 207 public void setTargetPackage(String targetPackage) { 208 this.targetPackages = new String[] {targetPackage}; 209 } 210 211 /** 212 * Set the names of packages with the Castor descriptor classes. 213 */ 214 public void setTargetPackages(String... targetPackages) { 215 this.targetPackages = targetPackages; 216 } 217 218 /** 219 * Set whether this marshaller should validate in- and outgoing documents. 220 * <p>Default is {@code false}. 221 * @see Marshaller#setValidation(boolean) 222 */ 223 public void setValidating(boolean validating) { 224 this.validating = validating; 225 } 226 227 /** 228 * Sets whether this marshaller should output namespaces. 229 * <p>The default is {@code false}, i.e. namespaces are written. 230 * @see org.exolab.castor.xml.Marshaller#setSuppressNamespaces(boolean) 231 */ 232 public void setSuppressNamespaces(boolean suppressNamespaces) { 233 this.suppressNamespaces = suppressNamespaces; 234 } 235 236 /** 237 * Set whether this marshaller should output the {@code xsi:type} attribute. 238 * <p>The default is {@code false}, i.e. the {@code xsi:type} is written. 239 * @see org.exolab.castor.xml.Marshaller#setSuppressXSIType(boolean) 240 */ 241 public void setSuppressXsiType(boolean suppressXsiType) { 242 this.suppressXsiType = suppressXsiType; 243 } 244 245 /** 246 * Set whether this marshaller should output the xml declaration. 247 * <p>The default is {@code true}, the XML declaration will be written. 248 * @see org.exolab.castor.xml.Marshaller#setMarshalAsDocument(boolean) 249 */ 250 public void setMarshalAsDocument(boolean marshalAsDocument) { 251 this.marshalAsDocument = marshalAsDocument; 252 } 253 254 /** 255 * Set whether this marshaller should output for given type the {@code xsi:type} attribute. 256 * <p>The default is {@code true}, the {@code xsi:type} attribute will be written. 257 * @see org.exolab.castor.xml.Marshaller#setMarshalExtendedType(boolean) 258 */ 259 public void setMarshalExtendedType(boolean marshalExtendedType) { 260 this.marshalExtendedType = marshalExtendedType; 261 } 262 263 /** 264 * Set the name of the root element. 265 * @see org.exolab.castor.xml.Marshaller#setRootElement(String) 266 */ 267 public void setRootElement(String rootElement) { 268 this.rootElement = rootElement; 269 } 270 271 /** 272 * Set the value of {@code xsi:noNamespaceSchemaLocation} attribute. When set, the 273 * {@code xsi:noNamespaceSchemaLocation} attribute will be written for the root element. 274 * @see org.exolab.castor.xml.Marshaller#setNoNamespaceSchemaLocation(String) 275 */ 276 public void setNoNamespaceSchemaLocation(String noNamespaceSchemaLocation) { 277 this.noNamespaceSchemaLocation = noNamespaceSchemaLocation; 278 } 279 280 /** 281 * Set the value of {@code xsi:schemaLocation} attribute. When set, the 282 * {@code xsi:schemaLocation} attribute will be written for the root element. 283 * @see org.exolab.castor.xml.Marshaller#setSchemaLocation(String) 284 */ 285 public void setSchemaLocation(String schemaLocation) { 286 this.schemaLocation = schemaLocation; 287 } 288 289 /** 290 * Sets whether this marshaller should output the {@code xsi:type} attribute for the root element. 291 * This can be useful when the type of the element can not be simply determined from the element name. 292 * <p>The default is {@code false}: The {@code xsi:type} attribute for the root element won't be written. 293 * @see org.exolab.castor.xml.Marshaller#setUseXSITypeAtRoot(boolean) 294 */ 295 public void setUseXSITypeAtRoot(boolean useXSITypeAtRoot) { 296 this.useXSITypeAtRoot = useXSITypeAtRoot; 297 } 298 299 /** 300 * Set whether the Castor {@link Unmarshaller} should preserve "ignorable" whitespace. 301 * <p>Default is {@code false}. 302 * @see org.exolab.castor.xml.Unmarshaller#setWhitespacePreserve(boolean) 303 */ 304 public void setWhitespacePreserve(boolean whitespacePreserve) { 305 this.whitespacePreserve = whitespacePreserve; 306 } 307 308 /** 309 * Set whether the Castor {@link Unmarshaller} should ignore attributes that do not match a specific field. 310 * <p>Default is {@code true}: Extra attributes are ignored. 311 * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraAttributes(boolean) 312 */ 313 public void setIgnoreExtraAttributes(boolean ignoreExtraAttributes) { 314 this.ignoreExtraAttributes = ignoreExtraAttributes; 315 } 316 317 /** 318 * Set whether the Castor {@link Unmarshaller} should ignore elements that do not match a specific field. 319 * <p>Default is {@code false}: Extra elements are flagged as an error. 320 * @see org.exolab.castor.xml.Unmarshaller#setIgnoreExtraElements(boolean) 321 */ 322 public void setIgnoreExtraElements(boolean ignoreExtraElements) { 323 this.ignoreExtraElements = ignoreExtraElements; 324 } 325 326 /** 327 * Set the expected root object for the unmarshaller, into which the source will be unmarshalled. 328 * @see org.exolab.castor.xml.Unmarshaller#setObject(Object) 329 */ 330 public void setRootObject(Object root) { 331 this.rootObject = root; 332 } 333 334 /** 335 * Set whether this unmarshaller should re-use objects. 336 * This will be only used when unmarshalling to an existing object. 337 * <p>The default is {@code false}, which means that the objects won't be re-used. 338 * @see org.exolab.castor.xml.Unmarshaller#setReuseObjects(boolean) 339 */ 340 public void setReuseObjects(boolean reuseObjects) { 341 this.reuseObjects = reuseObjects; 342 } 343 344 /** 345 * Sets whether this unmarshaller should clear collections upon the first use. 346 * <p>The default is {@code false} which means that marshaller won't clear collections. 347 * @see org.exolab.castor.xml.Unmarshaller#setClearCollections(boolean) 348 */ 349 public void setClearCollections(boolean clearCollections) { 350 this.clearCollections = clearCollections; 351 } 352 353 /** 354 * Set Castor-specific properties for marshalling and unmarshalling. 355 * Each entry key is considered the property name and each value the property value. 356 * @see org.exolab.castor.xml.Marshaller#setProperty(String, String) 357 * @see org.exolab.castor.xml.Unmarshaller#setProperty(String, String) 358 */ 359 public void setCastorProperties(Map<String, String> castorProperties) { 360 this.castorProperties = castorProperties; 361 } 362 363 /** 364 * Set the map containing document type definition for the marshaller. 365 * Each entry has system id as key and public id as value. 366 * @see org.exolab.castor.xml.Marshaller#setDoctype(String, String) 367 */ 368 public void setDoctypes(Map<String, String> doctypes) { 369 this.doctypes = doctypes; 370 } 371 372 /** 373 * Sets the processing instructions that will be used by during marshalling. 374 * Keys are the processing targets and values contain the processing data. 375 * @see org.exolab.castor.xml.Marshaller#addProcessingInstruction(String, String) 376 */ 377 public void setProcessingInstructions(Map<String, String> processingInstructions) { 378 this.processingInstructions = processingInstructions; 379 } 380 381 /** 382 * Set the namespace mappings. 383 * Property names are interpreted as namespace prefixes; values are namespace URIs. 384 * @see org.exolab.castor.xml.Marshaller#setNamespaceMapping(String, String) 385 */ 386 public void setNamespaceMappings(Map<String, String> namespaceMappings) { 387 this.namespaceMappings = namespaceMappings; 388 } 389 390 /** 391 * Set the namespace to package mappings. Property names are represents the namespaces URI, values are packages. 392 * @see org.exolab.castor.xml.Marshaller#setNamespaceMapping(String, String) 393 */ 394 public void setNamespaceToPackageMapping(Map<String, String> namespaceToPackageMapping) { 395 this.namespaceToPackageMapping = namespaceToPackageMapping; 396 } 397 398 /** 399 * Set the {@link EntityResolver} to be used during unmarshalling. 400 * This resolver will used to resolve system and public ids. 401 * @see org.exolab.castor.xml.Unmarshaller#setEntityResolver(EntityResolver) 402 */ 403 public void setEntityResolver(EntityResolver entityResolver) { 404 this.entityResolver = entityResolver; 405 } 406 407 /** 408 * Set the {@link XMLClassDescriptorResolver} to be used during unmarshalling. 409 * This resolver will used to resolve class descriptors. 410 * @see org.exolab.castor.xml.Unmarshaller#setResolver(XMLClassDescriptorResolver) 411 */ 412 public void setClassDescriptorResolver(XMLClassDescriptorResolver classDescriptorResolver) { 413 this.classDescriptorResolver = classDescriptorResolver; 414 } 415 416 /** 417 * Set the Castor {@link IDResolver} to be used during unmarshalling. 418 * @see org.exolab.castor.xml.Unmarshaller#setIDResolver(IDResolver) 419 */ 420 public void setIdResolver(IDResolver idResolver) { 421 this.idResolver = idResolver; 422 } 423 424 /** 425 * Set the Castor {@link ObjectFactory} to be used during unmarshalling. 426 * @see org.exolab.castor.xml.Unmarshaller#setObjectFactory(ObjectFactory) 427 */ 428 public void setObjectFactory(ObjectFactory objectFactory) { 429 this.objectFactory = objectFactory; 430 } 431 432 @Override 433 public void setBeanClassLoader(ClassLoader classLoader) { 434 this.beanClassLoader = classLoader; 435 } 436 437 438 @Override 439 public void afterPropertiesSet() throws CastorMappingException, IOException { 440 try { 441 this.xmlContext = createXMLContext(this.mappingLocations, this.targetClasses, this.targetPackages); 442 } 443 catch (MappingException ex) { 444 throw new CastorMappingException("Could not load Castor mapping", ex); 445 } 446 catch (ResolverException ex) { 447 throw new CastorMappingException("Could not resolve Castor mapping", ex); 448 } 449 } 450 451 /** 452 * Create the Castor {@code XMLContext}. Subclasses can override this to create a custom context. 453 * <p>The default implementation loads mapping files if defined, or the target class or packages if defined. 454 * @return the created resolver 455 * @throws MappingException when the mapping file cannot be loaded 456 * @throws IOException in case of I/O errors 457 * @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping) 458 * @see XMLContext#addClass(Class) 459 */ 460 protected XMLContext createXMLContext(Resource[] mappingLocations, Class<?>[] targetClasses, 461 String[] targetPackages) throws MappingException, ResolverException, IOException { 462 463 XMLContext context = new XMLContext(); 464 if (!ObjectUtils.isEmpty(mappingLocations)) { 465 Mapping mapping = new Mapping(); 466 for (Resource mappingLocation : mappingLocations) { 467 mapping.loadMapping(SaxResourceUtils.createInputSource(mappingLocation)); 468 } 469 context.addMapping(mapping); 470 } 471 if (!ObjectUtils.isEmpty(targetClasses)) { 472 context.addClasses(targetClasses); 473 } 474 if (!ObjectUtils.isEmpty(targetPackages)) { 475 context.addPackages(targetPackages); 476 } 477 if (this.castorProperties != null) { 478 for (Map.Entry<String, String> property : this.castorProperties.entrySet()) { 479 context.setProperty(property.getKey(), property.getValue()); 480 } 481 } 482 return context; 483 } 484 485 486 /** 487 * Returns {@code true} for all classes, i.e. Castor supports arbitrary classes. 488 */ 489 @Override 490 public boolean supports(Class<?> clazz) { 491 return true; 492 } 493 494 495 // Marshalling 496 497 @Override 498 protected void marshalDomNode(Object graph, Node node) throws XmlMappingException { 499 marshalSaxHandlers(graph, DomUtils.createContentHandler(node), null); 500 } 501 502 @Override 503 protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException { 504 ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter); 505 LexicalHandler lexicalHandler = null; 506 if (contentHandler instanceof LexicalHandler) { 507 lexicalHandler = (LexicalHandler) contentHandler; 508 } 509 marshalSaxHandlers(graph, contentHandler, lexicalHandler); 510 } 511 512 @Override 513 protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException { 514 ContentHandler contentHandler = StaxUtils.createContentHandler(streamWriter); 515 LexicalHandler lexicalHandler = null; 516 if (contentHandler instanceof LexicalHandler) { 517 lexicalHandler = (LexicalHandler) contentHandler; 518 } 519 marshalSaxHandlers(graph, StaxUtils.createContentHandler(streamWriter), lexicalHandler); 520 } 521 522 @Override 523 protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler) 524 throws XmlMappingException { 525 526 Marshaller marshaller = xmlContext.createMarshaller(); 527 marshaller.setContentHandler(contentHandler); 528 doMarshal(graph, marshaller); 529 } 530 531 @Override 532 protected void marshalOutputStream(Object graph, OutputStream outputStream) throws XmlMappingException, IOException { 533 marshalWriter(graph, new OutputStreamWriter(outputStream, encoding)); 534 } 535 536 @Override 537 protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { 538 Marshaller marshaller = xmlContext.createMarshaller(); 539 marshaller.setWriter(writer); 540 doMarshal(graph, marshaller); 541 } 542 543 private void doMarshal(Object graph, Marshaller marshaller) { 544 try { 545 customizeMarshaller(marshaller); 546 marshaller.marshal(graph); 547 } 548 catch (XMLException ex) { 549 throw convertCastorException(ex, true); 550 } 551 } 552 553 /** 554 * Template method that allows for customizing of the given Castor {@link Marshaller}. 555 */ 556 protected void customizeMarshaller(Marshaller marshaller) { 557 marshaller.setValidation(this.validating); 558 marshaller.setSuppressNamespaces(this.suppressNamespaces); 559 marshaller.setSuppressXSIType(this.suppressXsiType); 560 marshaller.setMarshalAsDocument(this.marshalAsDocument); 561 marshaller.setMarshalExtendedType(this.marshalExtendedType); 562 marshaller.setRootElement(this.rootElement); 563 marshaller.setNoNamespaceSchemaLocation(this.noNamespaceSchemaLocation); 564 marshaller.setSchemaLocation(this.schemaLocation); 565 marshaller.setUseXSITypeAtRoot(this.useXSITypeAtRoot); 566 if (this.doctypes != null) { 567 for (Map.Entry<String, String> doctype : this.doctypes.entrySet()) { 568 marshaller.setDoctype(doctype.getKey(), doctype.getValue()); 569 } 570 } 571 if (this.processingInstructions != null) { 572 for (Map.Entry<String, String> processingInstruction : this.processingInstructions.entrySet()) { 573 marshaller.addProcessingInstruction(processingInstruction.getKey(), processingInstruction.getValue()); 574 } 575 } 576 if (this.namespaceMappings != null) { 577 for (Map.Entry<String, String> entry : this.namespaceMappings.entrySet()) { 578 marshaller.setNamespaceMapping(entry.getKey(), entry.getValue()); 579 } 580 } 581 } 582 583 584 // Unmarshalling 585 586 @Override 587 protected Object unmarshalDomNode(Node node) throws XmlMappingException { 588 try { 589 return createUnmarshaller().unmarshal(node); 590 } 591 catch (XMLException ex) { 592 throw convertCastorException(ex, false); 593 } 594 } 595 596 @Override 597 protected Object unmarshalXmlEventReader(XMLEventReader eventReader) { 598 try { 599 return createUnmarshaller().unmarshal(eventReader); 600 } 601 catch (XMLException ex) { 602 throw convertCastorException(ex, false); 603 } 604 } 605 606 @Override 607 protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) { 608 try { 609 return createUnmarshaller().unmarshal(streamReader); 610 } 611 catch (XMLException ex) { 612 throw convertCastorException(ex, false); 613 } 614 } 615 616 @Override 617 protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) 618 throws XmlMappingException, IOException { 619 620 UnmarshalHandler unmarshalHandler = createUnmarshaller().createHandler(); 621 try { 622 ContentHandler contentHandler = Unmarshaller.getContentHandler(unmarshalHandler); 623 xmlReader.setContentHandler(contentHandler); 624 xmlReader.parse(inputSource); 625 return unmarshalHandler.getObject(); 626 } 627 catch (SAXException ex) { 628 throw new UnmarshallingFailureException("SAX reader exception", ex); 629 } 630 } 631 632 @Override 633 protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException { 634 try { 635 return createUnmarshaller().unmarshal(new InputSource(inputStream)); 636 } 637 catch (XMLException ex) { 638 throw convertCastorException(ex, false); 639 } 640 } 641 642 @Override 643 protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException { 644 try { 645 return createUnmarshaller().unmarshal(new InputSource(reader)); 646 } 647 catch (XMLException ex) { 648 throw convertCastorException(ex, false); 649 } 650 } 651 652 private Unmarshaller createUnmarshaller() { 653 Unmarshaller unmarshaller = this.xmlContext.createUnmarshaller(); 654 customizeUnmarshaller(unmarshaller); 655 return unmarshaller; 656 } 657 658 /** 659 * Template method that allows for customizing of the given Castor {@link Unmarshaller}. 660 */ 661 protected void customizeUnmarshaller(Unmarshaller unmarshaller) { 662 unmarshaller.setValidation(this.validating); 663 unmarshaller.setWhitespacePreserve(this.whitespacePreserve); 664 unmarshaller.setIgnoreExtraAttributes(this.ignoreExtraAttributes); 665 unmarshaller.setIgnoreExtraElements(this.ignoreExtraElements); 666 unmarshaller.setObject(this.rootObject); 667 unmarshaller.setReuseObjects(this.reuseObjects); 668 unmarshaller.setClearCollections(this.clearCollections); 669 if (this.namespaceToPackageMapping != null) { 670 for (Map.Entry<String, String> mapping : this.namespaceToPackageMapping.entrySet()) { 671 unmarshaller.addNamespaceToPackageMapping(mapping.getKey(), mapping.getValue()); 672 } 673 } 674 if (this.entityResolver != null) { 675 unmarshaller.setEntityResolver(this.entityResolver); 676 } 677 if (this.classDescriptorResolver != null) { 678 unmarshaller.setResolver(this.classDescriptorResolver); 679 } 680 if (this.idResolver != null) { 681 unmarshaller.setIDResolver(this.idResolver); 682 } 683 if (this.objectFactory != null) { 684 unmarshaller.setObjectFactory(this.objectFactory); 685 } 686 if (this.beanClassLoader != null) { 687 unmarshaller.setClassLoader(this.beanClassLoader); 688 } 689 } 690 691 692 /** 693 * Convert the given {@code XMLException} to an appropriate exception from the 694 * {@code org.springframework.oxm} hierarchy. 695 * <p>A boolean flag is used to indicate whether this exception occurs during marshalling or 696 * unmarshalling, since Castor itself does not make this distinction in its exception hierarchy. 697 * @param ex Castor {@code XMLException} that occurred 698 * @param marshalling indicates whether the exception occurs during marshalling ({@code true}), 699 * or unmarshalling ({@code false}) 700 * @return the corresponding {@code XmlMappingException} 701 */ 702 protected XmlMappingException convertCastorException(XMLException ex, boolean marshalling) { 703 if (ex instanceof ValidationException) { 704 return new ValidationFailureException("Castor validation exception", ex); 705 } 706 else if (ex instanceof MarshalException) { 707 if (marshalling) { 708 return new MarshallingFailureException("Castor marshalling exception", ex); 709 } 710 else { 711 return new UnmarshallingFailureException("Castor unmarshalling exception", ex); 712 } 713 } 714 else { 715 // fallback 716 return new UncategorizedMappingException("Unknown Castor exception", ex); 717 } 718 } 719 720}