From cfdcb54711ba073a4a0396d4a9ba397b39671940 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 11 Oct 2012 22:32:42 +0200 Subject: [PATCH] Jaxb2Marshaller has non-synchronized access to the JAXBContext once initialized Issue: SPR-9867 --- .../oxm/jaxb/Jaxb2Marshaller.java | 74 ++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java index 62794636d6..a53bddf3f0 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java +++ b/spring-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,23 +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 boolean checkForXmlRootElement = true; - private LSResourceResolver schemaResourceResolver; + private ClassLoader beanClassLoader; + + private ResourceLoader resourceLoader; + + private final Object jaxbContextMonitor = new Object(); + + private volatile JAXBContext jaxbContext; + + private Schema schema; /** @@ -405,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 { @@ -434,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 {