diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
index dbfb260db2..a53bddf3f0 100644
--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
+++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
@@ -101,11 +101,12 @@ import org.springframework.util.xml.StaxUtils;
/**
* Implementation of the Marshaller interface for JAXB 2.0.
*
- *
The typical usage will be to set either the contextPath or the classesToBeBound property
- * on this bean, possibly customize the marshaller and unmarshaller by setting properties, schemas, adapters, and
- * listeners, and to refer to it.
+ *
The typical usage will be to set either the "contextPath" or the "classesToBeBound" + * property on this bean, possibly customize the marshaller and unmarshaller by setting + * properties, schemas, adapters, and listeners, and to refer to it. * * @author Arjen Poutsma + * @author Juergen Hoeller * @since 3.0 * @see #setContextPath(String) * @see #setClassesToBeBound(Class[]) @@ -125,9 +126,7 @@ public class Jaxb2Marshaller private static final String CID = "cid:"; - /** - * Logger available to subclasses. - */ + /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); private String contextPath; @@ -154,21 +153,25 @@ public class Jaxb2Marshaller private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI; + private LSResourceResolver schemaResourceResolver; + private boolean mtomEnabled = false; - private ClassLoader beanClassLoader; - - private ResourceLoader resourceLoader; - - private JAXBContext jaxbContext; - - private Schema schema; - private boolean lazyInit = false; private boolean supportJaxbElementClass = false; - private LSResourceResolver schemaResourceResolver; + private boolean checkForXmlRootElement = true; + + private ClassLoader beanClassLoader; + + private ResourceLoader resourceLoader; + + private final Object jaxbContextMonitor = new Object(); + + private volatile JAXBContext jaxbContext; + + private Schema schema; /** @@ -358,6 +361,21 @@ public class Jaxb2Marshaller this.supportJaxbElementClass = supportJaxbElementClass; } + /** + * Specify whether the {@link #supports(Class)} should check for + * {@link XmlRootElement @XmlRootElement} annotations. + *
Default is {@code true}, meaning that {@code supports(Class)} will check for + * this annotation. However, some JAXB implementations (i.e. EclipseLink MOXy) allow + * for defining the bindings in an external definition file, thus keeping the classes + * annotations free. Setting this property to {@code false} supports these + * JAXB implementations. + * @see #supports(Class) + * @see #supports(Type) + */ + public void setCheckForXmlRootElement(boolean checkForXmlRootElement) { + this.checkForXmlRootElement = checkForXmlRootElement; + } + public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } @@ -388,24 +406,29 @@ public class Jaxb2Marshaller } } - protected synchronized JAXBContext getJaxbContext() { - if (this.jaxbContext == null) { - try { - if (StringUtils.hasLength(this.contextPath)) { - this.jaxbContext = createJaxbContextFromContextPath(); - } - else if (!ObjectUtils.isEmpty(this.classesToBeBound)) { - this.jaxbContext = createJaxbContextFromClasses(); - } - else if (!ObjectUtils.isEmpty(this.packagesToScan)) { - this.jaxbContext = createJaxbContextFromPackages(); - } - } - catch (JAXBException ex) { - throw convertJaxbException(ex); - } + protected JAXBContext getJaxbContext() { + if (this.jaxbContext != null) { + return this.jaxbContext; + } + synchronized (this.jaxbContextMonitor) { + if (this.jaxbContext == null) { + try { + if (StringUtils.hasLength(this.contextPath)) { + this.jaxbContext = createJaxbContextFromContextPath(); + } + else if (!ObjectUtils.isEmpty(this.classesToBeBound)) { + this.jaxbContext = createJaxbContextFromClasses(); + } + else if (!ObjectUtils.isEmpty(this.packagesToScan)) { + this.jaxbContext = createJaxbContextFromPackages(); + } + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + return this.jaxbContext; } - return this.jaxbContext; } private JAXBContext createJaxbContextFromContextPath() throws JAXBException { @@ -417,7 +440,9 @@ public class Jaxb2Marshaller return JAXBContext.newInstance(this.contextPath, this.beanClassLoader, this.jaxbContextProperties); } else { - return JAXBContext.newInstance(this.contextPath, ClassUtils.getDefaultClassLoader(), this.jaxbContextProperties); + // analogous to the JAXBContext.newInstance(String) implementation + return JAXBContext.newInstance(this.contextPath, Thread.currentThread().getContextClassLoader(), + this.jaxbContextProperties); } } else { @@ -492,7 +517,7 @@ public class Jaxb2Marshaller if (this.supportJaxbElementClass && JAXBElement.class.isAssignableFrom(clazz)) { return true; } - return supportsInternal(clazz, true); + return supportsInternal(clazz, this.checkForXmlRootElement); } public boolean supports(Type genericType) { @@ -521,7 +546,7 @@ public class Jaxb2Marshaller } else if (genericType instanceof Class) { Class> clazz = (Class>) genericType; - return supportsInternal(clazz, true); + return supportsInternal(clazz, this.checkForXmlRootElement); } return false; }