Skip to content

Commit 89d63eb

Browse files
committed
JmsMessagingTemplate exception management
This commit introduces MessagingExceptionTranslator, a messaging exception translation infrastructure similar to what PersistenceExceptionTranslator provides. JmsMessagingTemplate does not throw raw JmsException anymore but translates those to an instance of Spring's MessagingException hierarchy. Issue: SPR-12038
1 parent 8f484d3 commit 89d63eb

File tree

5 files changed

+319
-15
lines changed

5 files changed

+319
-15
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2002-2014 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.jms.core;
18+
19+
import org.springframework.jms.InvalidDestinationException;
20+
import org.springframework.jms.JmsException;
21+
import org.springframework.jms.support.converter.MessageConversionException;
22+
import org.springframework.jms.support.destination.DestinationResolutionException;
23+
import org.springframework.messaging.MessagingException;
24+
import org.springframework.messaging.MessagingExceptionTranslator;
25+
26+
/**
27+
* {@link MessagingExceptionTranslator} capable of translating {@link JmsException}
28+
* instances to Spring's {@link MessagingException} hierarchy.
29+
*
30+
* @author Stephane Nicoll
31+
* @since 4.1
32+
*/
33+
public class JmsMessagingExceptionTranslator implements MessagingExceptionTranslator {
34+
35+
@Override
36+
public MessagingException translateExceptionIfPossible(RuntimeException ex) {
37+
if (ex instanceof JmsException) {
38+
return convertJmsException((JmsException) ex);
39+
}
40+
return null;
41+
}
42+
43+
private MessagingException convertJmsException(JmsException ex) {
44+
if (ex instanceof DestinationResolutionException ||
45+
ex instanceof InvalidDestinationException) {
46+
return new org.springframework.messaging.core.DestinationResolutionException(ex.getMessage(), ex);
47+
}
48+
if (ex instanceof MessageConversionException) {
49+
return new org.springframework.messaging.converter.MessageConversionException(ex.getMessage(), ex);
50+
}
51+
52+
53+
// Fallback
54+
return new MessagingException(ex.getMessage(), ex);
55+
}
56+
}

spring-jms/src/main/java/org/springframework/jms/core/JmsMessagingTemplate.java

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
import javax.jms.Session;
2323

2424
import org.springframework.beans.factory.InitializingBean;
25-
import org.springframework.jms.support.converter.MessageConversionException;
25+
import org.springframework.jms.JmsException;
2626
import org.springframework.jms.support.converter.MessageConverter;
2727
import org.springframework.jms.support.converter.MessagingMessageConverter;
2828
import org.springframework.jms.support.converter.SimpleMessageConverter;
2929
import org.springframework.messaging.Message;
3030
import org.springframework.messaging.MessagingException;
31+
import org.springframework.messaging.MessagingExceptionTranslator;
32+
import org.springframework.messaging.converter.MessageConversionException;
3133
import org.springframework.messaging.core.AbstractMessagingTemplate;
3234
import org.springframework.messaging.core.MessagePostProcessor;
3335
import org.springframework.util.Assert;
@@ -45,6 +47,8 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate<Destination>
4547

4648
private MessageConverter jmsMessageConverter = new MessagingMessageConverter();
4749

50+
private MessagingExceptionTranslator exceptionTranslator = new JmsMessagingExceptionTranslator();
51+
4852
private String defaultDestinationName;
4953

5054

@@ -85,6 +89,14 @@ public void setJmsMessageConverter(MessageConverter jmsMessageConverter) {
8589
this.jmsMessageConverter = jmsMessageConverter;
8690
}
8791

92+
/**
93+
* Set the {@link MessagingExceptionTranslator} to use. Default to
94+
* {@link JmsMessagingExceptionTranslator}.
95+
*/
96+
public void setExceptionTranslator(MessagingExceptionTranslator exceptionTranslator) {
97+
this.exceptionTranslator = exceptionTranslator;
98+
}
99+
88100
/**
89101
* Configure the default destination name to use in send methods that don't have
90102
* a destination argument. If a default destination is not configured, send methods
@@ -271,35 +283,65 @@ public <T> T convertSendAndReceive(String destinationName, Object request, Map<S
271283

272284
@Override
273285
protected void doSend(Destination destination, Message<?> message) {
274-
this.jmsTemplate.send(destination, createMessageCreator(message));
286+
try {
287+
this.jmsTemplate.send(destination, createMessageCreator(message));
288+
}
289+
catch (JmsException ex) {
290+
throw translateIfNecessary(ex);
291+
}
275292
}
276293

277294
protected void doSend(String destinationName, Message<?> message) {
278-
this.jmsTemplate.send(destinationName, createMessageCreator(message));
295+
try {
296+
this.jmsTemplate.send(destinationName, createMessageCreator(message));
297+
}
298+
catch (JmsException ex) {
299+
throw translateIfNecessary(ex);
300+
}
279301
}
280302

281303
@Override
282304
protected Message<?> doReceive(Destination destination) {
283-
javax.jms.Message jmsMessage = this.jmsTemplate.receive(destination);
284-
return doConvert(jmsMessage);
305+
try {
306+
javax.jms.Message jmsMessage = this.jmsTemplate.receive(destination);
307+
return doConvert(jmsMessage);
308+
}
309+
catch (JmsException ex) {
310+
throw translateIfNecessary(ex);
311+
}
285312
}
286313

287314
protected Message<?> doReceive(String destinationName) {
288-
javax.jms.Message jmsMessage = this.jmsTemplate.receive(destinationName);
289-
return doConvert(jmsMessage);
315+
try {
316+
javax.jms.Message jmsMessage = this.jmsTemplate.receive(destinationName);
317+
return doConvert(jmsMessage);
318+
}
319+
catch (JmsException ex) {
320+
throw translateIfNecessary(ex);
321+
}
290322
}
291323

292324
@Override
293325
protected Message<?> doSendAndReceive(Destination destination, Message<?> requestMessage) {
294-
javax.jms.Message jmsMessage = this.jmsTemplate
295-
.sendAndReceive(destination, createMessageCreator(requestMessage));
296-
return doConvert(jmsMessage);
326+
try {
327+
javax.jms.Message jmsMessage = this.jmsTemplate
328+
.sendAndReceive(destination, createMessageCreator(requestMessage));
329+
return doConvert(jmsMessage);
330+
}
331+
catch (JmsException ex) {
332+
throw translateIfNecessary(ex);
333+
}
297334
}
298335

299336
protected Message<?> doSendAndReceive(String destinationName, Message<?> requestMessage) {
300-
javax.jms.Message jmsMessage = this.jmsTemplate
301-
.sendAndReceive(destinationName, createMessageCreator(requestMessage));
302-
return doConvert(jmsMessage);
337+
try {
338+
javax.jms.Message jmsMessage = this.jmsTemplate
339+
.sendAndReceive(destinationName, createMessageCreator(requestMessage));
340+
return doConvert(jmsMessage);
341+
}
342+
catch (JmsException ex) {
343+
throw translateIfNecessary(ex);
344+
}
303345
}
304346

305347
private MessagingMessageCreator createMessageCreator(Message<?> message) {
@@ -325,6 +367,15 @@ protected Message<?> doConvert(javax.jms.Message message) {
325367
catch (JMSException ex) {
326368
throw new MessageConversionException("Could not convert '" + message + "'", ex);
327369
}
370+
catch (JmsException ex) {
371+
throw new MessageConversionException("Could not convert '" + message + "'", ex);
372+
}
373+
}
374+
375+
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
376+
protected RuntimeException translateIfNecessary(RuntimeException rawException) {
377+
MessagingException messagingException = this.exceptionTranslator.translateExceptionIfPossible(rawException);
378+
return (messagingException != null ? messagingException : rawException);
328379
}
329380

330381

@@ -341,7 +392,15 @@ public MessagingMessageCreator(Message<?> message, MessageConverter messageConve
341392

342393
@Override
343394
public javax.jms.Message createMessage(Session session) throws JMSException {
344-
return this.messageConverter.toMessage(this.message, session);
395+
try {
396+
return this.messageConverter.toMessage(this.message, session);
397+
}
398+
catch (JMSException ex) {
399+
throw new MessageConversionException("Could not convert '" + message + "'", ex);
400+
}
401+
catch (JmsException ex) {
402+
throw new MessageConversionException("Could not convert '" + message + "'", ex);
403+
}
345404
}
346405
}
347406

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2002-2014 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.jms.core;
18+
19+
import org.junit.Test;
20+
21+
import static org.junit.Assert.*;
22+
23+
/**
24+
* @author Stephane Nicoll
25+
*/
26+
public class JmsMessagingExceptionTranslatorTests {
27+
28+
private final JmsMessagingExceptionTranslator translator = new JmsMessagingExceptionTranslator();
29+
30+
@Test
31+
public void translateNonJmsException() {
32+
assertNull(translator.translateExceptionIfPossible(new NullPointerException()));
33+
}
34+
}

spring-jms/src/test/java/org/springframework/jms/core/JmsMessagingTemplateTests.java

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.Map;
2222
import javax.jms.Destination;
2323
import javax.jms.JMSException;
24+
import javax.jms.MessageFormatException;
25+
import javax.jms.MessageNotWriteableException;
2426
import javax.jms.Session;
2527
import javax.jms.TextMessage;
2628

@@ -36,11 +38,16 @@
3638
import org.mockito.invocation.InvocationOnMock;
3739
import org.mockito.stubbing.Answer;
3840

41+
import org.springframework.jms.InvalidDestinationException;
42+
import org.springframework.jms.MessageNotReadableException;
3943
import org.springframework.jms.StubTextMessage;
40-
import org.springframework.jms.support.converter.MessageConversionException;
44+
import org.springframework.jms.support.converter.MessageConverter;
4145
import org.springframework.jms.support.converter.SimpleMessageConverter;
46+
import org.springframework.jms.support.destination.DestinationResolutionException;
4247
import org.springframework.messaging.Message;
48+
import org.springframework.messaging.MessagingException;
4349
import org.springframework.messaging.converter.GenericMessageConverter;
50+
import org.springframework.messaging.converter.MessageConversionException;
4451
import org.springframework.messaging.support.MessageBuilder;
4552

4653
import static org.junit.Assert.*;
@@ -443,6 +450,110 @@ public void convertSendAndReceiveNoDefaultSet() throws JMSException {
443450
messagingTemplate.convertSendAndReceive("my Payload", String.class);
444451
}
445452

453+
@Test
454+
public void convertMessageConversionExceptionOnSend() throws JMSException {
455+
Message<String> message = createTextMessage();
456+
MessageConverter messageConverter = mock(MessageConverter.class);
457+
doThrow(org.springframework.jms.support.converter.MessageConversionException.class)
458+
.when(messageConverter).toMessage(eq(message), anyObject());
459+
messagingTemplate.setJmsMessageConverter(messageConverter);
460+
invokeMessageCreator("myQueue");
461+
462+
thrown.expect(org.springframework.messaging.converter.MessageConversionException.class);
463+
messagingTemplate.send("myQueue", message);
464+
}
465+
466+
@Test
467+
public void convertMessageConversionExceptionOnReceive() throws JMSException {
468+
javax.jms.Message message = createJmsTextMessage();
469+
MessageConverter messageConverter = mock(MessageConverter.class);
470+
doThrow(org.springframework.jms.support.converter.MessageConversionException.class)
471+
.when(messageConverter).fromMessage(message);
472+
messagingTemplate.setJmsMessageConverter(messageConverter);
473+
given(jmsTemplate.receive("myQueue")).willReturn(message);
474+
475+
thrown.expect(org.springframework.messaging.converter.MessageConversionException.class);
476+
messagingTemplate.receive("myQueue");
477+
}
478+
479+
@Test
480+
public void convertMessageNotReadableException() throws JMSException {
481+
doThrow(MessageNotReadableException.class).when(jmsTemplate).receive("myQueue");
482+
483+
thrown.expect(MessagingException.class);
484+
messagingTemplate.receive("myQueue");
485+
}
486+
487+
@Test
488+
public void convertDestinationResolutionExceptionOnSend() {
489+
Destination destination = new Destination() {};
490+
doThrow(DestinationResolutionException.class).when(jmsTemplate).send(eq(destination), anyObject());
491+
492+
thrown.expect(org.springframework.messaging.core.DestinationResolutionException.class);
493+
messagingTemplate.send(destination, createTextMessage());
494+
}
495+
496+
@Test
497+
public void convertDestinationResolutionExceptionOnReceive() {
498+
Destination destination = new Destination() {};
499+
doThrow(DestinationResolutionException.class).when(jmsTemplate).receive(destination);
500+
501+
thrown.expect(org.springframework.messaging.core.DestinationResolutionException.class);
502+
messagingTemplate.receive(destination);
503+
}
504+
505+
@Test
506+
public void convertMessageFormatException() throws JMSException {
507+
Message<String> message = createTextMessage();
508+
MessageConverter messageConverter = mock(MessageConverter.class);
509+
doThrow(MessageFormatException.class).when(messageConverter).toMessage(eq(message), anyObject());
510+
messagingTemplate.setJmsMessageConverter(messageConverter);
511+
invokeMessageCreator("myQueue");
512+
513+
thrown.expect(org.springframework.messaging.converter.MessageConversionException.class);
514+
messagingTemplate.send("myQueue", message);
515+
}
516+
517+
@Test
518+
public void convertMessageNotWritableException() throws JMSException {
519+
Message<String> message = createTextMessage();
520+
MessageConverter messageConverter = mock(MessageConverter.class);
521+
doThrow(MessageNotWriteableException.class).when(messageConverter).toMessage(eq(message), anyObject());
522+
messagingTemplate.setJmsMessageConverter(messageConverter);
523+
invokeMessageCreator("myQueue");
524+
525+
thrown.expect(org.springframework.messaging.converter.MessageConversionException.class);
526+
messagingTemplate.send("myQueue", message);
527+
}
528+
529+
@Test
530+
public void convertInvalidDestinationExceptionOnSendAndReceiveWithName() {
531+
doThrow(InvalidDestinationException.class).when(jmsTemplate).sendAndReceive(eq("unknownQueue"), anyObject());
532+
533+
thrown.expect(org.springframework.messaging.core.DestinationResolutionException.class);
534+
messagingTemplate.sendAndReceive("unknownQueue", createTextMessage());
535+
}
536+
537+
@Test
538+
public void convertInvalidDestinationExceptionOnSendAndReceive() {
539+
Destination destination = new Destination() {};
540+
doThrow(InvalidDestinationException.class).when(jmsTemplate).sendAndReceive(eq(destination), anyObject());
541+
542+
thrown.expect(org.springframework.messaging.core.DestinationResolutionException.class);
543+
messagingTemplate.sendAndReceive(destination, createTextMessage());
544+
}
545+
546+
private void invokeMessageCreator(String destinationName) {
547+
doAnswer(new Answer() {
548+
@Override
549+
public Object answer(InvocationOnMock invocation) throws Throwable {
550+
MessageCreator messageCreator = (MessageCreator) invocation.getArguments()[1];
551+
messageCreator.createMessage(null);
552+
return null;
553+
}
554+
}).when(jmsTemplate).send(eq("myQueue"), anyObject());
555+
}
556+
446557

447558
private Message<String> createTextMessage(String payload) {
448559
return MessageBuilder

0 commit comments

Comments
 (0)