1616
1717package org .springframework .oxm .support ;
1818
19+ import java .io .ByteArrayInputStream ;
20+ import java .io .ByteArrayOutputStream ;
1921import java .io .IOException ;
20- import java .io .InputStream ;
21- import java .io .OutputStream ;
2222import javax .jms .BytesMessage ;
2323import javax .jms .JMSException ;
2424import javax .jms .Message ;
25- import javax .jms .MessageEOFException ;
2625import javax .jms .Session ;
2726import javax .jms .TextMessage ;
27+ import javax .xml .transform .Result ;
2828import javax .xml .transform .Source ;
2929import javax .xml .transform .stream .StreamResult ;
3030import javax .xml .transform .stream .StreamSource ;
4242
4343/**
4444 * Spring JMS {@link MessageConverter} that uses a {@link Marshaller} and {@link Unmarshaller}. Marshals an object to a
45- * {@link BytesMessage}, or to a {@link TextMessage} if the {@link #setMarshalToTextMessage(boolean)
46- * marshalToTextMessage} is <code>true</code>. Unmarshals from a {@link TextMessage} or {@link BytesMessage} to an
47- * object.
45+ * {@link BytesMessage}, or to a {@link TextMessage} if the {@link #setMarshalTo marshalTo} is set to {@link
46+ * #MARSHAL_TO_TEXT_MESSAGE}. Unmarshals from a {@link TextMessage} or {@link BytesMessage} to an object.
4847 *
4948 * @author Arjen Poutsma
49+ * @see org.springframework.jms.core.JmsTemplate#convertAndSend
50+ * @see org.springframework.jms.core.JmsTemplate#receiveAndConvert
51+ * @since 1.5.1
5052 */
5153public class MarshallingMessageConverter implements MessageConverter , InitializingBean {
5254
55+ /** Constant that indicates that {@link #toMessage(Object, Session)} should marshal to a {@link BytesMessage}. */
56+ public static final int MARSHAL_TO_BYTES_MESSAGE = 1 ;
57+
58+ /** Constant that indicates that {@link #toMessage(Object, Session)} should marshal to a {@link TextMessage}. */
59+ public static final int MARSHAL_TO_TEXT_MESSAGE = 2 ;
60+
5361 private Marshaller marshaller ;
5462
5563 private Unmarshaller unmarshaller ;
5664
57- private boolean marshalToTextMessage = false ;
65+ private int marshalTo = MARSHAL_TO_BYTES_MESSAGE ;
5866
5967 /**
6068 * Constructs a new <code>MarshallingMessageConverter</code> with no {@link Marshaller} set. The marshaller must be
@@ -102,19 +110,23 @@ public MarshallingMessageConverter(Marshaller marshaller, Unmarshaller unmarshal
102110 }
103111
104112 /**
105- * Indicates whether {@link #toMessage(Object,Session)} should marshal to a {@link TextMessage} or a {@link
106- * BytesMessage}. The default is <code>false</code>, i.e. this converter marshals to a {@link BytesMessage}.
113+ * Indicates whether {@link #toMessage(Object,Session)} should marshal to a {@link BytesMessage} or a {@link
114+ * TextMessage}. The default is {@link #MARSHAL_TO_BYTES_MESSAGE}, i.e. this converter marshals to a {@link
115+ * BytesMessage}.
116+ *
117+ * @see #MARSHAL_TO_BYTES_MESSAGE
118+ * @see #MARSHAL_TO_TEXT_MESSAGE
107119 */
108- public void setMarshalToTextMessage ( boolean marshalToTextMessage ) {
109- this .marshalToTextMessage = marshalToTextMessage ;
120+ public void setMarshalTo ( int marshalTo ) {
121+ this .marshalTo = marshalTo ;
110122 }
111123
112124 /** Sets the {@link Marshaller} to be used by this message converter. */
113125 public void setMarshaller (Marshaller marshaller ) {
114126 this .marshaller = marshaller ;
115127 }
116128
117- /** Sets the {@link Marshaller } to be used by this message converter. */
129+ /** Sets the {@link Unmarshaller } to be used by this message converter. */
118130 public void setUnmarshaller (Unmarshaller unmarshaller ) {
119131 this .unmarshaller = unmarshaller ;
120132 }
@@ -124,150 +136,170 @@ public void afterPropertiesSet() throws Exception {
124136 Assert .notNull (unmarshaller , "Property 'unmarshaller' is required" );
125137 }
126138
139+ /**
140+ * Marshals the given object to a {@link TextMessage} or {@link javax.jms.BytesMessage}. The desired message type
141+ * can be defined by setting the {@link #setMarshalTo(int) marshalTo} property.
142+ *
143+ * @see #marshalToTextMessage
144+ * @see #marshalToBytesMessage
145+ */
127146 public Message toMessage (Object object , Session session ) throws JMSException , MessageConversionException {
128147 try {
129- if (marshalToTextMessage ) {
130- TextMessage message = session .createTextMessage ();
131- StringResult result = new StringResult ();
132- marshaller .marshal (object , result );
133- message .setText (result .toString ());
134- return message ;
135- }
136- else {
137- BytesMessage message = session .createBytesMessage ();
138- StreamResult result = new StreamResult (new BytesMessageOutputStream (message ));
139- marshaller .marshal (object , result );
140- return message ;
148+ switch (marshalTo ) {
149+ case MARSHAL_TO_TEXT_MESSAGE :
150+ return marshalToTextMessage (object , session , marshaller );
151+ case MARSHAL_TO_BYTES_MESSAGE :
152+ return marshalToBytesMessage (object , session , marshaller );
153+ default :
154+ return marshalToMessage (object , session , marshaller );
141155 }
142156 }
143157 catch (MarshallingFailureException ex ) {
144158 throw new MessageConversionException ("Could not marshal [" + object + "]" , ex );
145159 }
146- catch (MessageConversionException ex ) {
147- handleMessageConversionException (ex );
148- throw ex ;
149- }
150160 catch (IOException ex ) {
151161 throw new MessageConversionException ("Could not marshal [" + object + "]" , ex );
152162 }
153163 }
154164
165+ /**
166+ * Unmarshals the given {@link Message} into an object.
167+ *
168+ * @see #unmarshalFromTextMessage
169+ * @see #unmarshalFromBytesMessage
170+ */
155171 public Object fromMessage (Message message ) throws JMSException , MessageConversionException {
156- Source source ;
157- if (message instanceof TextMessage ) {
158- source = new StringSource (((TextMessage ) message ).getText ());
159- }
160- else if (message instanceof BytesMessage ) {
161- source = new StreamSource (new BytesMessageInputStream ((BytesMessage ) message ));
162- }
163- else {
164- throw new MessageConversionException (
165- "MarshallingMessageConverter only supports TextMessages and BytesMessages" );
166- }
167172 try {
168- return unmarshaller .unmarshal (source );
173+ if (message instanceof TextMessage ) {
174+ TextMessage textMessage = (TextMessage ) message ;
175+ return unmarshalFromTextMessage (textMessage , unmarshaller );
176+ }
177+ else if (message instanceof BytesMessage ) {
178+ BytesMessage bytesMessage = (BytesMessage ) message ;
179+ return unmarshalFromBytesMessage (bytesMessage , unmarshaller );
180+ }
181+ else {
182+ return unmarshalFromMessage (message , unmarshaller );
183+ }
169184 }
170185 catch (UnmarshallingFailureException ex ) {
171186 throw new MessageConversionException ("Could not unmarshal message [" + message + "]" , ex );
172187 }
173- catch (MessageConversionException ex ) {
174- handleMessageConversionException (ex );
175- throw ex ;
176- }
177188 catch (IOException ex ) {
178189 throw new MessageConversionException ("Could not unmarshal message [" + message + "]" , ex );
179190 }
180191 }
181192
182- private void handleMessageConversionException (MessageConversionException ex ) throws JMSException {
183- if (ex .getCause () instanceof JMSException ) {
184- throw (JMSException ) ex .getCause ();
185- }
186- else {
187- throw ex ;
188- }
193+ /**
194+ * Marshals the given object to a {@link TextMessage}.
195+ *
196+ * @param object the object to be marshalled
197+ * @param session current JMS session
198+ * @param marshaller the marshaller to use
199+ * @return the resulting message
200+ * @throws JMSException if thrown by JMS methods
201+ * @throws IOException in case of I/O errors
202+ * @see Session#createTextMessage
203+ * @see Marshaller#marshal(Object, Result)
204+ */
205+ protected TextMessage marshalToTextMessage (Object object , Session session , Marshaller marshaller )
206+ throws JMSException , IOException {
207+ StringResult result = new StringResult ();
208+ marshaller .marshal (object , result );
209+ return session .createTextMessage (result .toString ());
189210 }
190211
191- /** Input stream that wraps a {@link BytesMessage}. */
192- private static class BytesMessageInputStream extends InputStream {
193-
194- private BytesMessage message ;
195-
196- BytesMessageInputStream (BytesMessage message ) {
197- this .message = message ;
198- }
199-
200- public int read (byte b []) throws IOException {
201- try {
202- return message .readBytes (b );
203- }
204- catch (JMSException ex ) {
205- throw new MessageConversionException ("Could not read byte array" , ex );
206- }
207- }
208-
209- public int read (byte b [], int off , int len ) throws IOException {
210- if (off == 0 ) {
211- try {
212- return message .readBytes (b , len );
213- }
214- catch (JMSException ex ) {
215- throw new MessageConversionException ("Could not read byte array" , ex );
216- }
217- }
218- else {
219- return super .read (b , off , len );
220- }
221- }
222-
223- public int read () throws IOException {
224- try {
225- return message .readByte ();
226- }
227- catch (MessageEOFException ex ) {
228- return -1 ;
229- }
230- catch (JMSException ex ) {
231- throw new MessageConversionException ("Could not read byte" , ex );
232- }
233- }
212+ /**
213+ * Marshals the given object to a {@link BytesMessage}.
214+ *
215+ * @param object the object to be marshalled
216+ * @param session current JMS session
217+ * @param marshaller the marshaller to use
218+ * @return the resulting message
219+ * @throws JMSException if thrown by JMS methods
220+ * @throws IOException in case of I/O errors
221+ * @see Session#createBytesMessage
222+ * @see Marshaller#marshal(Object, Result)
223+ */
224+ protected BytesMessage marshalToBytesMessage (Object object , Session session , Marshaller marshaller )
225+ throws JMSException , IOException {
226+ ByteArrayOutputStream bos = new ByteArrayOutputStream ();
227+ StreamResult streamResult = new StreamResult (bos );
228+ marshaller .marshal (object , streamResult );
229+ BytesMessage message = session .createBytesMessage ();
230+ message .writeBytes (bos .toByteArray ());
231+ return message ;
234232 }
235233
236- /** Output stream that wraps a {@link BytesMessage}. */
237- private static class BytesMessageOutputStream extends OutputStream {
238-
239- private BytesMessage message ;
240-
241- BytesMessageOutputStream (BytesMessage message ) {
242- this .message = message ;
243- }
234+ /**
235+ * Template method that allows for custom message marshalling. Invoked when {@link #setMarshalTo(int)} is not {@link
236+ * #MARSHAL_TO_TEXT_MESSAGE} or {@link #MARSHAL_TO_BYTES_MESSAGE}.
237+ * <p/>
238+ * Default implemenetation throws a {@link MessageConversionException}.
239+ *
240+ * @param object the object to marshal
241+ * @param session the JMS session
242+ * @param marshaller the marshaller to use
243+ * @return the resulting message
244+ * @throws JMSException if thrown by JMS methods
245+ * @throws IOException in case of I/O errors
246+ */
247+ protected Message marshalToMessage (Object object , Session session , Marshaller marshaller )
248+ throws JMSException , IOException {
249+ throw new MessageConversionException (
250+ "Unknown 'marshalTo' value [" + marshalTo + "]. Cannot convert object to Message" );
251+ }
244252
245- public void write (byte b []) throws IOException {
246- try {
247- message .writeBytes (b );
248- }
249- catch (JMSException ex ) {
250- throw new MessageConversionException ("Could not write byte array" , ex );
251- }
252- }
253+ /**
254+ * Unmarshals the given {@link TextMessage} into an object.
255+ *
256+ * @param message the message
257+ * @param unmarshaller the unmarshaller to use
258+ * @return the unmarshalled object
259+ * @throws JMSException if thrown by JMS methods
260+ * @throws IOException in case of I/O errors
261+ * @see Unmarshaller#unmarshal(Source)
262+ */
263+ protected Object unmarshalFromTextMessage (TextMessage message , Unmarshaller unmarshaller )
264+ throws JMSException , IOException {
265+ StringSource source = new StringSource (message .getText ());
266+ return unmarshaller .unmarshal (source );
267+ }
253268
254- public void write (byte b [], int off , int len ) throws IOException {
255- try {
256- message .writeBytes (b , off , len );
257- }
258- catch (JMSException ex ) {
259- throw new MessageConversionException ("Could not write byte array" , ex );
260- }
261- }
269+ /**
270+ * Unmarshals the given {@link BytesMessage} into an object.
271+ *
272+ * @param message the message
273+ * @param unmarshaller the unmarshaller to use
274+ * @return the unmarshalled object
275+ * @throws JMSException if thrown by JMS methods
276+ * @throws IOException in case of I/O errors
277+ * @see Unmarshaller#unmarshal(Source)
278+ */
279+ protected Object unmarshalFromBytesMessage (BytesMessage message , Unmarshaller unmarshaller )
280+ throws JMSException , IOException {
281+ byte [] bytes = new byte [(int ) message .getBodyLength ()];
282+ message .readBytes (bytes );
283+ ByteArrayInputStream bis = new ByteArrayInputStream (bytes );
284+ StreamSource source = new StreamSource (bis );
285+ return unmarshaller .unmarshal (source );
286+ }
262287
263- public void write (int b ) throws IOException {
264- try {
265- message .writeByte ((byte ) b );
266- }
267- catch (JMSException ex ) {
268- throw new MessageConversionException ("Could not write byte" , ex );
269- }
270- }
288+ /**
289+ * Template method that allows for custom message unmarshalling. Invoked when {@link #fromMessage(Message)} is
290+ * invoked with a message that is not a {@link TextMessage} or {@link BytesMessage}.
291+ * <p/>
292+ * Default implemenetation throws a {@link MessageConversionException}.
293+ *
294+ * @param message the message
295+ * @param unmarshaller the unmarshaller to use
296+ * @return the unmarshalled object
297+ * @throws JMSException if thrown by JMS methods
298+ * @throws IOException in case of I/O errors
299+ */
300+ protected Object unmarshalFromMessage (Message message , Unmarshaller unmarshaller ) throws JMSException , IOException {
301+ throw new MessageConversionException (
302+ "MarshallingMessageConverter only supports TextMessages and BytesMessages" );
271303 }
272304}
273305
0 commit comments