6161
6262/**
6363 * Implementation of the <code>Marshaller</code> interface for Castor. By default, Castor does not require any further
64- * configuration, though setting a target class or providing a mapping file can be used to have more control over the
64+ * configuration, though setting target classes, target packages or providing a mapping file can be used to have more control over the
6565 * behavior of Castor.
6666 *
6767 * <p>If a target class is specified using <code>setTargetClass</code>, the <code>CastorMarshaller</code> can only be
7474 * @author Arjen Poutsma
7575 * @see #setEncoding(String)
7676 * @see #setTargetClass(Class)
77+ * @see #setTargetPackages(String[])
7778 * @see #setMappingLocation(Resource)
7879 * @see #setMappingLocations(Resource[])
7980 * @since 3.0
@@ -90,7 +91,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
9091
9192 private String encoding = DEFAULT_ENCODING ;
9293
93- private Class targetClass ;
94+ private Class [] targetClasses ;
95+
96+ private String [] targetPackages ;
9497
9598 private boolean validating = false ;
9699
@@ -132,12 +135,28 @@ public void setMappingLocations(Resource[] mappingLocations) {
132135 }
133136
134137 /**
135- * Set the Castor target class. If this property is set, this <code>CastorMarshaller</code>
136- * is tied to this one specific class. Use a mapping file for unmarshalling multiple classes.
137- * <p>You cannot set both this property and the mapping (location) .
138+ * Set the Castor target class. Alternative means of configuring
139+ * <code>CastorMarshaller<code> for unmarshalling multiple classes include
140+ * use of mapping files, and specifying packages with Castor descriptor classes .
138141 */
139142 public void setTargetClass (Class targetClass ) {
140- this .targetClass = targetClass ;
143+ this .targetClasses = new Class []{targetClass };
144+ }
145+
146+ /**
147+ * Set the Castor target classes. Alternative means of configuring
148+ * <code>CastorMarshaller<code> for unmarshalling multiple classes include
149+ * use of mapping files, and specifying packages with Castor descriptor classes.
150+ */
151+ public void setTargetClasses (Class [] targetClasses ) {
152+ this .targetClasses = targetClasses ;
153+ }
154+
155+ /**
156+ * Set the package names of packages with the Castor descriptor classes.
157+ */
158+ public void setTargetPackages (String [] targetPackages ) {
159+ this .targetPackages = targetPackages ;
141160 }
142161
143162 /**
@@ -214,21 +233,28 @@ public void setSuppressXsiType(boolean suppressXsiType) {
214233 this .suppressXsiType = suppressXsiType ;
215234 }
216235
217-
218236 public final void afterPropertiesSet () throws CastorMappingException , IOException {
219237 if (logger .isInfoEnabled ()) {
220- if (this .mappingLocations != null ) {
221- logger .info ("Configured using " + StringUtils .arrayToCommaDelimitedString (this .mappingLocations ));
238+ if (!ObjectUtils .isEmpty (this .mappingLocations )) {
239+ logger .info (
240+ "Configured using [" + StringUtils .arrayToCommaDelimitedString (this .mappingLocations ) + "]" );
241+ }
242+ if (!ObjectUtils .isEmpty (this .targetClasses )) {
243+ logger .info ("Configured for target classes " + StringUtils .arrayToCommaDelimitedString (targetClasses ) +
244+ "]" );
222245 }
223- if (this .targetClass != null ) {
224- logger .info ("Configured for target class [" + this .targetClass .getName () + "]" );
246+ if (!ObjectUtils .isEmpty (this .targetPackages )) {
247+ logger .info (
248+ "Configured for target packages [" + StringUtils .arrayToCommaDelimitedString (targetPackages ) +
249+ "]" );
225250 }
226- if (this .mappingLocations == null && this .targetClass == null ) {
251+ if (ObjectUtils .isEmpty (this .mappingLocations ) && ObjectUtils .isEmpty (this .targetClasses ) &&
252+ ObjectUtils .isEmpty (this .targetPackages )) {
227253 logger .info ("Using default configuration" );
228254 }
229255 }
230256 try {
231- this .xmlContext = createXMLContext (this .mappingLocations , this .targetClass );
257+ this .xmlContext = createXMLContext (this .mappingLocations , this .targetClasses , this . targetPackages );
232258 }
233259 catch (MappingException ex ) {
234260 throw new CastorMappingException ("Could not load Castor mapping" , ex );
@@ -240,14 +266,16 @@ public final void afterPropertiesSet() throws CastorMappingException, IOExceptio
240266
241267 /**
242268 * Create the Castor <code>XMLContext</code>. Subclasses can override this to create a custom context.
243- * <p>The default implementation loads mapping files if defined, and the target class if not defined.
269+ * <p>
270+ * The default implementation loads mapping files if defined, or the target class or packages if defined.
271+ *
244272 * @return the created resolver
245273 * @throws MappingException when the mapping file cannot be loaded
246- * @throws IOException in case of I/O errors
274+ * @throws IOException in case of I/O errors
247275 * @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping)
248276 * @see XMLContext#addClass(Class)
249277 */
250- protected XMLContext createXMLContext (Resource [] mappingLocations , Class targetClass )
278+ protected XMLContext createXMLContext (Resource [] mappingLocations , Class [] targetClasses , String [] targetPackages )
251279 throws MappingException , ResolverException , IOException {
252280
253281 XMLContext context = new XMLContext ();
@@ -258,21 +286,22 @@ protected XMLContext createXMLContext(Resource[] mappingLocations, Class targetC
258286 }
259287 context .addMapping (mapping );
260288 }
261- if (targetClass != null ) {
262- context .addClass (targetClass );
289+ if (!ObjectUtils .isEmpty (targetClasses )) {
290+ context .addClasses (targetClasses );
291+ }
292+ if (!ObjectUtils .isEmpty (targetPackages )) {
293+ context .addPackages (targetPackages );
263294 }
264295 return context ;
265296 }
266297
267-
268298 /**
269299 * Returns <code>true</code> for all classes, i.e. Castor supports arbitrary classes.
270300 */
271301 public boolean supports (Class <?> clazz ) {
272302 return true ;
273303 }
274304
275-
276305 // Marshalling
277306
278307 @ Override
@@ -378,7 +407,7 @@ protected final Object unmarshalXmlEventReader(XMLEventReader eventReader) {
378407 return unmarshalSaxReader (reader , new InputSource ());
379408 }
380409 catch (IOException ex ) {
381- throw new UnmarshallingFailureException ("Failed to read XML stream" , ex );
410+ throw new UnmarshallingFailureException ("Failed to read XML stream" , ex );
382411 }
383412 }
384413
@@ -411,19 +440,20 @@ protected final Object unmarshalXmlStreamReader(XMLStreamReader streamReader) {
411440
412441 private Unmarshaller createUnmarshaller () {
413442 Unmarshaller unmarshaller = this .xmlContext .createUnmarshaller ();
414- if (this .targetClass != null ) {
415- unmarshaller .setClass (this .targetClass );
416- unmarshaller .setClassLoader (this .targetClass .getClassLoader ());
417- }
418443 customizeUnmarshaller (unmarshaller );
419444 return unmarshaller ;
420445 }
421446
422447 /**
423- * Template method that allows for customizing of the given Castor {@link Unmarshaller}.
424- * <p>The default implementation invokes {@link Unmarshaller#setValidation(boolean)},
425- * {@link Unmarshaller#setWhitespacePreserve(boolean)}, {@link Unmarshaller#setIgnoreExtraAttributes(boolean)},
426- * and {@link Unmarshaller#setIgnoreExtraElements(boolean)} with the properties set on this marshaller.
448+ * Template method that allows for customizing of the given Castor
449+ * {@link Unmarshaller}.
450+ * <p>
451+ * The default implementation invokes
452+ * {@link Unmarshaller#setValidation(boolean)},
453+ * {@link Unmarshaller#setWhitespacePreserve(boolean)},
454+ * {@link Unmarshaller#setIgnoreExtraAttributes(boolean)}, and
455+ * {@link Unmarshaller#setIgnoreExtraElements(boolean)} with the properties
456+ * set on this marshaller.
427457 */
428458 protected void customizeUnmarshaller (Unmarshaller unmarshaller ) {
429459 unmarshaller .setValidation (this .validating );
@@ -433,13 +463,16 @@ protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
433463 }
434464
435465 /**
436- * Convert the given <code>XMLException</code> to an appropriate exception from the
437- * <code>org.springframework.oxm</code> hierarchy.
438- * <p>A boolean flag is used to indicate whether this exception occurs during marshalling or
439- * unmarshalling, since Castor itself does not make this distinction in its exception hierarchy.
440- * @param ex Castor <code>XMLException</code> that occured
441- * @param marshalling indicates whether the exception occurs during marshalling (<code>true</code>),
442- * or unmarshalling (<code>false</code>)
466+ * Convert the given <code>XMLException</code> to an appropriate exception
467+ * from the <code>org.springframework.oxm</code> hierarchy.
468+ * <p>
469+ * A boolean flag is used to indicate whether this exception occurs during
470+ * marshalling or unmarshalling, since Castor itself does not make this
471+ * distinction in its exception hierarchy.
472+ *
473+ * @param ex Castor <code>XMLException</code> that occured
474+ * @param marshalling indicates whether the exception occurs during
475+ * marshalling (<code>true</code>), or unmarshalling (<code>false</code>)
443476 * @return the corresponding <code>XmlMappingException</code>
444477 */
445478 protected XmlMappingException convertCastorException (XMLException ex , boolean marshalling ) {
@@ -448,7 +481,7 @@ protected XmlMappingException convertCastorException(XMLException ex, boolean ma
448481 }
449482 else if (ex instanceof MarshalException ) {
450483 if (marshalling ) {
451- return new MarshallingFailureException ("Castor marshalling exception" , ex );
484+ return new MarshallingFailureException ("Castor marshalling exception" , ex );
452485 }
453486 else {
454487 return new UnmarshallingFailureException ("Castor unmarshalling exception" , ex );
0 commit comments