Skip to content

Commit 58d3e70

Browse files
committed
SPR-5745 - Support lazy initialization within Jaxb2 OXM classes
1 parent 1dc346a commit 58d3e70

File tree

2 files changed

+55
-20
lines changed

2 files changed

+55
-20
lines changed

org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, BeanCl
140140

141141
private Schema schema;
142142

143+
private boolean lazyInit = false;
144+
143145

144146
/**
145147
* Set a JAXB context path.
@@ -259,33 +261,55 @@ public void setMtomEnabled(boolean mtomEnabled) {
259261
this.mtomEnabled = mtomEnabled;
260262
}
261263

264+
/**
265+
* Set whether to lazily initialize the {@link JAXBContext} for this marshaller.
266+
* Default is {@code false} to initialize on startup; can be switched to
267+
* {@code true}.
268+
* <p>Early initialization just applies if <code>afterPropertiesSet()</code> is called.
269+
* @see #afterPropertiesSet()
270+
*/
271+
public void setLazyInit(boolean lazyInit) {
272+
this.lazyInit = lazyInit;
273+
}
274+
275+
262276
public void setBeanClassLoader(ClassLoader classLoader) {
263277
this.beanClassLoader = classLoader;
264278
}
265279

266280

267281
public final void afterPropertiesSet() throws Exception {
268-
this.jaxbContext = createJaxbContext();
269-
if (!ObjectUtils.isEmpty(this.schemaResources)) {
270-
this.schema = loadSchema(this.schemaResources, this.schemaLanguage);
271-
}
272-
}
273-
274-
protected JAXBContext createJaxbContext() throws Exception {
275282
if (StringUtils.hasLength(this.contextPath) && !ObjectUtils.isEmpty(this.classesToBeBound)) {
276283
throw new IllegalArgumentException("Specify either 'contextPath' or 'classesToBeBound property'; not both");
277284
}
278-
if (StringUtils.hasLength(this.contextPath)) {
279-
return createJaxbContextFromContextPath();
285+
else if (!StringUtils.hasLength(this.contextPath) && ObjectUtils.isEmpty(this.classesToBeBound)) {
286+
throw new IllegalArgumentException("Setting either 'contextPath' or 'classesToBeBound' is required");
280287
}
281-
else if (!ObjectUtils.isEmpty(this.classesToBeBound)) {
282-
return createJaxbContextFromClasses();
288+
if (!lazyInit) {
289+
getJaxbContext();
283290
}
284-
else {
285-
throw new IllegalArgumentException("setting either contextPath or classesToBeBound is required");
291+
if (!ObjectUtils.isEmpty(this.schemaResources)) {
292+
this.schema = loadSchema(this.schemaResources, this.schemaLanguage);
286293
}
287294
}
288295

296+
protected synchronized JAXBContext getJaxbContext() {
297+
if (this.jaxbContext == null) {
298+
try {
299+
if (StringUtils.hasLength(this.contextPath)) {
300+
this.jaxbContext = createJaxbContextFromContextPath();
301+
}
302+
else if (!ObjectUtils.isEmpty(this.classesToBeBound)) {
303+
this.jaxbContext = createJaxbContextFromClasses();
304+
}
305+
}
306+
catch (JAXBException ex) {
307+
throw convertJaxbException(ex);
308+
}
309+
}
310+
return jaxbContext;
311+
}
312+
289313
private JAXBContext createJaxbContextFromContextPath() throws JAXBException {
290314
if (logger.isInfoEnabled()) {
291315
logger.info("Creating JAXBContext with context path [" + this.contextPath + "]");
@@ -364,7 +388,6 @@ else if (!ObjectUtils.isEmpty(this.classesToBeBound)) {
364388
return false;
365389
}
366390

367-
368391
// Marshalling
369392

370393
public void marshal(Object graph, Result result) throws XmlMappingException {
@@ -410,7 +433,7 @@ private void marshalStaxResult(Marshaller jaxbMarshaller, Object graph, Result s
410433
*/
411434
protected Marshaller createMarshaller() {
412435
try {
413-
Marshaller marshaller = this.jaxbContext.createMarshaller();
436+
Marshaller marshaller = getJaxbContext().createMarshaller();
414437
initJaxbMarshaller(marshaller);
415438
return marshaller;
416439
}
@@ -495,7 +518,7 @@ private Object unmarshalStaxSource(Unmarshaller jaxbUnmarshaller, Source staxSou
495518
*/
496519
protected Unmarshaller createUnmarshaller() {
497520
try {
498-
Unmarshaller unmarshaller = this.jaxbContext.createUnmarshaller();
521+
Unmarshaller unmarshaller = getJaxbContext().createUnmarshaller();
499522
initJaxbUnmarshaller(unmarshaller);
500523
return unmarshaller;
501524
}
@@ -557,7 +580,6 @@ else if (ex instanceof UnmarshalException) {
557580
}
558581
}
559582

560-
561583
private static class Jaxb2AttachmentMarshaller extends AttachmentMarshaller {
562584

563585
private final MimeContainer mimeContainer;

org.springframework.oxm/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTests.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
import java.util.Collections;
2222
import javax.activation.DataHandler;
2323
import javax.activation.FileDataSource;
24-
import javax.xml.bind.JAXBException;
2524
import javax.xml.transform.Result;
2625
import javax.xml.transform.sax.SAXResult;
2726
import javax.xml.transform.stream.StreamResult;
2827

28+
import static org.custommonkey.xmlunit.XMLAssert.*;
2929
import static org.easymock.EasyMock.*;
30-
import static org.junit.Assert.*;
30+
import static org.junit.Assert.assertTrue;
3131
import org.junit.Test;
3232
import org.xml.sax.Attributes;
3333
import org.xml.sax.ContentHandler;
@@ -37,6 +37,7 @@
3737
import org.springframework.core.io.Resource;
3838
import org.springframework.oxm.AbstractMarshallerTests;
3939
import org.springframework.oxm.Marshaller;
40+
import org.springframework.oxm.UncategorizedMappingException;
4041
import org.springframework.oxm.XmlMappingException;
4142
import org.springframework.oxm.jaxb.test.FlightType;
4243
import org.springframework.oxm.jaxb.test.Flights;
@@ -94,6 +95,18 @@ public void marshalSAXResult() throws Exception {
9495
verify(handlerMock);
9596
}
9697

98+
@Test
99+
public void laxyInit() throws Exception {
100+
marshaller = new Jaxb2Marshaller();
101+
marshaller.setContextPath(CONTEXT_PATH);
102+
marshaller.setLazyInit(true);
103+
marshaller.afterPropertiesSet();
104+
StringWriter writer = new StringWriter();
105+
StreamResult result = new StreamResult(writer);
106+
marshaller.marshal(flights, result);
107+
assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, writer.toString());
108+
}
109+
97110
@Test
98111
public void properties() throws Exception {
99112
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
@@ -110,7 +123,7 @@ public void noContextPathOrClassesToBeBound() throws Exception {
110123
marshaller.afterPropertiesSet();
111124
}
112125

113-
@Test(expected = JAXBException.class)
126+
@Test(expected = UncategorizedMappingException.class)
114127
public void testInvalidContextPath() throws Exception {
115128
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
116129
marshaller.setContextPath("ab");

0 commit comments

Comments
 (0)