101
101
/**
102
102
* Implementation of the <code>Marshaller</code> interface for JAXB 2.0.
103
103
*
104
- * <p>The typical usage will be to set either the <code> contextPath</code> or the <code> classesToBeBound</code> property
105
- * on this bean, possibly customize the marshaller and unmarshaller by setting properties, schemas, adapters, and
106
- * listeners, and to refer to it.
104
+ * <p>The typical usage will be to set either the " contextPath" or the " classesToBeBound"
105
+ * property on this bean, possibly customize the marshaller and unmarshaller by setting
106
+ * properties, schemas, adapters, and listeners, and to refer to it.
107
107
*
108
108
* @author Arjen Poutsma
109
+ * @author Juergen Hoeller
109
110
* @since 3.0
110
111
* @see #setContextPath(String)
111
112
* @see #setClassesToBeBound(Class[])
@@ -125,9 +126,7 @@ public class Jaxb2Marshaller
125
126
private static final String CID = "cid:" ;
126
127
127
128
128
- /**
129
- * Logger available to subclasses.
130
- */
129
+ /** Logger available to subclasses */
131
130
protected final Log logger = LogFactory .getLog (getClass ());
132
131
133
132
private String contextPath ;
@@ -154,21 +153,25 @@ public class Jaxb2Marshaller
154
153
155
154
private String schemaLanguage = XMLConstants .W3C_XML_SCHEMA_NS_URI ;
156
155
156
+ private LSResourceResolver schemaResourceResolver ;
157
+
157
158
private boolean mtomEnabled = false ;
158
159
159
- private ClassLoader beanClassLoader ;
160
+ private boolean lazyInit = false ;
160
161
161
- private ResourceLoader resourceLoader ;
162
+ private boolean supportJaxbElementClass = false ;
162
163
163
- private JAXBContext jaxbContext ;
164
+ private boolean checkForXmlRootElement = true ;
164
165
165
- private Schema schema ;
166
+ private ClassLoader beanClassLoader ;
166
167
167
- private boolean lazyInit = false ;
168
+ private ResourceLoader resourceLoader ;
168
169
169
- private boolean supportJaxbElementClass = false ;
170
+ private final Object jaxbContextMonitor = new Object () ;
170
171
171
- private LSResourceResolver schemaResourceResolver ;
172
+ private volatile JAXBContext jaxbContext ;
173
+
174
+ private Schema schema ;
172
175
173
176
174
177
/**
@@ -358,6 +361,21 @@ public void setSupportJaxbElementClass(boolean supportJaxbElementClass) {
358
361
this .supportJaxbElementClass = supportJaxbElementClass ;
359
362
}
360
363
364
+ /**
365
+ * Specify whether the {@link #supports(Class)} should check for
366
+ * {@link XmlRootElement @XmlRootElement} annotations.
367
+ * <p>Default is {@code true}, meaning that {@code supports(Class)} will check for
368
+ * this annotation. However, some JAXB implementations (i.e. EclipseLink MOXy) allow
369
+ * for defining the bindings in an external definition file, thus keeping the classes
370
+ * annotations free. Setting this property to {@code false} supports these
371
+ * JAXB implementations.
372
+ * @see #supports(Class)
373
+ * @see #supports(Type)
374
+ */
375
+ public void setCheckForXmlRootElement (boolean checkForXmlRootElement ) {
376
+ this .checkForXmlRootElement = checkForXmlRootElement ;
377
+ }
378
+
361
379
public void setBeanClassLoader (ClassLoader classLoader ) {
362
380
this .beanClassLoader = classLoader ;
363
381
}
@@ -388,24 +406,29 @@ public final void afterPropertiesSet() throws Exception {
388
406
}
389
407
}
390
408
391
- protected synchronized JAXBContext getJaxbContext () {
392
- if (this .jaxbContext == null ) {
393
- try {
394
- if (StringUtils .hasLength (this .contextPath )) {
395
- this .jaxbContext = createJaxbContextFromContextPath ();
396
- }
397
- else if (!ObjectUtils .isEmpty (this .classesToBeBound )) {
398
- this .jaxbContext = createJaxbContextFromClasses ();
409
+ protected JAXBContext getJaxbContext () {
410
+ if (this .jaxbContext != null ) {
411
+ return this .jaxbContext ;
412
+ }
413
+ synchronized (this .jaxbContextMonitor ) {
414
+ if (this .jaxbContext == null ) {
415
+ try {
416
+ if (StringUtils .hasLength (this .contextPath )) {
417
+ this .jaxbContext = createJaxbContextFromContextPath ();
418
+ }
419
+ else if (!ObjectUtils .isEmpty (this .classesToBeBound )) {
420
+ this .jaxbContext = createJaxbContextFromClasses ();
421
+ }
422
+ else if (!ObjectUtils .isEmpty (this .packagesToScan )) {
423
+ this .jaxbContext = createJaxbContextFromPackages ();
424
+ }
399
425
}
400
- else if (! ObjectUtils . isEmpty ( this . packagesToScan ) ) {
401
- this . jaxbContext = createJaxbContextFromPackages ( );
426
+ catch ( JAXBException ex ) {
427
+ throw convertJaxbException ( ex );
402
428
}
403
429
}
404
- catch (JAXBException ex ) {
405
- throw convertJaxbException (ex );
406
- }
430
+ return this .jaxbContext ;
407
431
}
408
- return this .jaxbContext ;
409
432
}
410
433
411
434
private JAXBContext createJaxbContextFromContextPath () throws JAXBException {
@@ -417,7 +440,9 @@ private JAXBContext createJaxbContextFromContextPath() throws JAXBException {
417
440
return JAXBContext .newInstance (this .contextPath , this .beanClassLoader , this .jaxbContextProperties );
418
441
}
419
442
else {
420
- return JAXBContext .newInstance (this .contextPath , ClassUtils .getDefaultClassLoader (), this .jaxbContextProperties );
443
+ // analogous to the JAXBContext.newInstance(String) implementation
444
+ return JAXBContext .newInstance (this .contextPath , Thread .currentThread ().getContextClassLoader (),
445
+ this .jaxbContextProperties );
421
446
}
422
447
}
423
448
else {
@@ -492,7 +517,7 @@ public boolean supports(Class<?> clazz) {
492
517
if (this .supportJaxbElementClass && JAXBElement .class .isAssignableFrom (clazz )) {
493
518
return true ;
494
519
}
495
- return supportsInternal (clazz , true );
520
+ return supportsInternal (clazz , this . checkForXmlRootElement );
496
521
}
497
522
498
523
public boolean supports (Type genericType ) {
@@ -521,7 +546,7 @@ else if (JdkVersion.getMajorJavaVersion() <= JdkVersion.JAVA_16 &&
521
546
}
522
547
else if (genericType instanceof Class ) {
523
548
Class <?> clazz = (Class <?>) genericType ;
524
- return supportsInternal (clazz , true );
549
+ return supportsInternal (clazz , this . checkForXmlRootElement );
525
550
}
526
551
return false ;
527
552
}
0 commit comments