1 /*
2 * Copyright 2006 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.oxm.jaxb;
18
19 import java.util.Iterator;
20 import java.util.Map;
21 import javax.xml.bind.JAXBContext;
22 import javax.xml.bind.JAXBException;
23 import javax.xml.bind.Marshaller;
24 import javax.xml.bind.Unmarshaller;
25 import javax.xml.bind.ValidationEventHandler;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.springframework.beans.factory.InitializingBean;
30 import org.springframework.oxm.XmlMappingException;
31 import org.springframework.util.Assert;
32 import org.springframework.util.StringUtils;
33
34 /**
35 * Abstract base class for implementations of the <code>Marshaller</code> and <code>Unmarshaller</code> interfaces that
36 * use JAXB. This base class is responsible for creating JAXB marshallers from a <code>JAXBContext</code>.
37 * <p/>
38 * JAXB 2.0 added breaking API changes, so specific subclasses must be used for JAXB 1.0 and 2.0
39 * (<code>Jaxb1Marshaller</code> and <code>Jaxb2Marshaller</code> respectivaly).
40 *
41 * @author Arjen Poutsma
42 * @see Jaxb1Marshaller
43 * @see Jaxb2Marshaller
44 * @since 1.0.0
45 */
46 public abstract class AbstractJaxbMarshaller
47 implements org.springframework.oxm.Marshaller, org.springframework.oxm.Unmarshaller, InitializingBean {
48
49 /** Logger available to subclasses. */
50 protected final Log logger = LogFactory.getLog(getClass());
51
52 private String contextPath;
53
54 private Map marshallerProperties;
55
56 private Map unmarshallerProperties;
57
58 private JAXBContext jaxbContext;
59
60 private ValidationEventHandler validationEventHandler;
61
62 /** Returns the JAXB Context path. */
63 protected String getContextPath() {
64 return contextPath;
65 }
66
67 /** Sets the JAXB Context path. */
68 public void setContextPath(String contextPath) {
69 Assert.notNull(contextPath, "'contextPath' must not be null");
70 this.contextPath = contextPath;
71 }
72
73 /**
74 * Sets multiple JAXB Context paths. The given array of context paths is converted to a colon-delimited string, as
75 * supported by JAXB.
76 */
77 public void setContextPaths(String[] contextPaths) {
78 Assert.notEmpty(contextPaths, "'contextPaths' must not be empty");
79 this.contextPath = StringUtils.arrayToDelimitedString(contextPaths, ":");
80 }
81
82 /**
83 * Sets the JAXB <code>Marshaller</code> properties. These properties will be set on the underlying JAXB
84 * <code>Marshaller</code>, and allow for features such as indentation.
85 *
86 * @param properties the properties
87 * @see javax.xml.bind.Marshaller#setProperty(String,Object)
88 * @see javax.xml.bind.Marshaller#JAXB_ENCODING
89 * @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT
90 * @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION
91 * @see javax.xml.bind.Marshaller#JAXB_SCHEMA_LOCATION
92 */
93 public void setMarshallerProperties(Map properties) {
94 this.marshallerProperties = properties;
95 }
96
97 /**
98 * Sets the JAXB <code>Unmarshaller</code> properties. These properties will be set on the underlying JAXB
99 * <code>Unmarshaller</code>.
100 *
101 * @param properties the properties
102 * @see javax.xml.bind.Unmarshaller#setProperty(String,Object)
103 */
104 public void setUnmarshallerProperties(Map properties) {
105 this.unmarshallerProperties = properties;
106 }
107
108 /**
109 * Sets the JAXB validation event handler. This event handler will be called by JAXB if any validation errors are
110 * encountered during calls to any of the marshal API's.
111 *
112 * @param validationEventHandler the event handler
113 */
114 public void setValidationEventHandler(ValidationEventHandler validationEventHandler) {
115 this.validationEventHandler = validationEventHandler;
116 }
117
118 /** Returns the {@link JAXBContext} created in {@link #afterPropertiesSet()}. */
119 public JAXBContext getJaxbContext() {
120 return jaxbContext;
121 }
122
123 public final void afterPropertiesSet() throws Exception {
124 try {
125 jaxbContext = createJaxbContext();
126 }
127 catch (JAXBException ex) {
128 throw convertJaxbException(ex);
129 }
130 }
131
132 /**
133 * Convert the given <code>JAXBException</code> to an appropriate exception from the
134 * <code>org.springframework.oxm</code> hierarchy.
135 * <p/>
136 * The default implementation delegates to <code>JaxbUtils</code>. Can be overridden in subclasses.
137 *
138 * @param ex <code>JAXBException</code> that occured
139 * @return the corresponding <code>XmlMappingException</code> instance
140 * @see JaxbUtils#convertJaxbException
141 */
142 protected XmlMappingException convertJaxbException(JAXBException ex) {
143 return JaxbUtils.convertJaxbException(ex);
144 }
145
146 /** Returns a newly created JAXB marshaller. JAXB marshallers are not necessarily thread safe. */
147 protected Marshaller createMarshaller() {
148 try {
149 Marshaller marshaller = jaxbContext.createMarshaller();
150 if (marshallerProperties != null) {
151 for (Iterator iterator = marshallerProperties.keySet().iterator(); iterator.hasNext();) {
152 String name = (String) iterator.next();
153 marshaller.setProperty(name, marshallerProperties.get(name));
154 }
155 }
156 if (validationEventHandler != null) {
157 marshaller.setEventHandler(validationEventHandler);
158 }
159 initJaxbMarshaller(marshaller);
160 return marshaller;
161 }
162 catch (JAXBException ex) {
163 throw convertJaxbException(ex);
164 }
165 }
166
167 /** Returns a newly created JAXB unmarshaller. JAXB unmarshallers are not necessarily thread safe. */
168 protected Unmarshaller createUnmarshaller() {
169 try {
170 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
171 if (unmarshallerProperties != null) {
172 for (Iterator iterator = unmarshallerProperties.keySet().iterator(); iterator.hasNext();) {
173 String name = (String) iterator.next();
174 unmarshaller.setProperty(name, unmarshallerProperties.get(name));
175 }
176 }
177 if (validationEventHandler != null) {
178 unmarshaller.setEventHandler(validationEventHandler);
179 }
180 initJaxbUnmarshaller(unmarshaller);
181 return unmarshaller;
182 }
183 catch (JAXBException ex) {
184 throw convertJaxbException(ex);
185 }
186 }
187
188 /**
189 * Template method that can be overridden by concrete JAXB marshallers for custom initialization behavior. Gets
190 * called after creation of JAXB <code>Marshaller</code>, and after the respective properties have been set.
191 * <p/>
192 * Default implementation does nothing.
193 */
194 protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException {
195 }
196
197 /**
198 * Template method that can overridden by concrete JAXB marshallers for custom initialization behavior. Gets called
199 * after creation of JAXB <code>Unmarshaller</code>, and after the respective properties have been set.
200 * <p/>
201 * Default implementation does nothing.
202 */
203 protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException {
204 }
205
206 /** Template method that returns a newly created JAXB context. Called from <code>afterPropertiesSet()</code>. */
207 protected abstract JAXBContext createJaxbContext() throws Exception;
208 }