View Javadoc

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 }