Skip to content

Commit 439be91

Browse files
committed
MarshallingMessageConverter is more open to subclassing.
1 parent 684013e commit 439be91

File tree

3 files changed

+168
-131
lines changed

3 files changed

+168
-131
lines changed

oxm/src/main/java/org/springframework/oxm/support/MarshallingMessageConverter.java

Lines changed: 158 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616

1717
package org.springframework.oxm.support;
1818

19+
import java.io.ByteArrayInputStream;
20+
import java.io.ByteArrayOutputStream;
1921
import java.io.IOException;
20-
import java.io.InputStream;
21-
import java.io.OutputStream;
2222
import javax.jms.BytesMessage;
2323
import javax.jms.JMSException;
2424
import javax.jms.Message;
25-
import javax.jms.MessageEOFException;
2625
import javax.jms.Session;
2726
import javax.jms.TextMessage;
27+
import javax.xml.transform.Result;
2828
import javax.xml.transform.Source;
2929
import javax.xml.transform.stream.StreamResult;
3030
import javax.xml.transform.stream.StreamSource;
@@ -42,19 +42,27 @@
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
*/
5153
public 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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<html>
22
<body>
33
Provides generic support classes for using Spring's O/X Mapping integration within various scenario's. Includes the
4-
MarshallingSource for compatibility with TrAX.
5-
4+
MarshallingSource for compatibility with TrAX, MarshallingView for use withing Spring Web MVC, and the
5+
MarshallingMessageConverter for use within Spring's JMS support.
66
</body>
77
</html>

0 commit comments

Comments
 (0)