diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java b/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java index 3c62934747..61dfcd002b 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,23 @@ package org.springframework.messaging.support; import java.util.Map; +import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; /** * A {@link GenericMessage} with a {@link Throwable} payload. + * The payload is typically a {@link org.springframework.messaging.MessagingException} + * with the message at the point of failure in its {@code failedMessage} property. + * An optional {@code originalMessage} may be provided, which represents the message + * that existed at the point in the stack where the error message is created. + *

Consider some code that starts with a message, invokes some process that performs + * transformation on that message and then fails for some reason, throwing the exception. + * The exception is caught and an error message produced that contains both the original + * message, and the transformed message that failed. * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell * @since 4.0 * @see MessageBuilder */ @@ -32,6 +42,7 @@ public class ErrorMessage extends GenericMessage { private static final long serialVersionUID = -5470210965279837728L; + private final Message originalMessage; /** * Create a new message with the given payload. @@ -39,6 +50,7 @@ public class ErrorMessage extends GenericMessage { */ public ErrorMessage(Throwable payload) { super(payload); + this.originalMessage = null; } /** @@ -49,6 +61,7 @@ public class ErrorMessage extends GenericMessage { */ public ErrorMessage(Throwable payload, Map headers) { super(payload, headers); + this.originalMessage = null; } /** @@ -60,6 +73,72 @@ public class ErrorMessage extends GenericMessage { */ public ErrorMessage(Throwable payload, MessageHeaders headers) { super(payload, headers); + this.originalMessage = null; + } + + /** + * Create a new message with the given payload and original message. + * @param payload the message payload (never {@code null}) + * @param originalMessage the original message (if present) at the point in the stack + * where the ErrorMessage was created + * @since 5.0 + */ + public ErrorMessage(Throwable payload, Message originalMessage) { + super(payload); + this.originalMessage = originalMessage; + } + + /** + * Create a new message with the given payload, headers and original message. + * The content of the given header map is copied. + * @param payload the message payload (never {@code null}) + * @param headers message headers to use for initialization + * @param originalMessage the original message (if present) at the point in the stack + * where the ErrorMessage was created + * @since 5.0 + */ + public ErrorMessage(Throwable payload, Map headers, Message originalMessage) { + super(payload, headers); + this.originalMessage = originalMessage; + } + + /** + * Create a new message with the payload, {@link MessageHeaders} and original message. + *

Note: the given {@code MessageHeaders} instance + * is used directly in the new message, i.e. it is not copied. + * @param payload the message payload (never {@code null}) + * @param headers message headers + * @param originalMessage the original message (if present) at the point in the stack + * where the ErrorMessage was created + * @since 5.0 + */ + public ErrorMessage(Throwable payload, MessageHeaders headers, Message originalMessage) { + super(payload, headers); + this.originalMessage = originalMessage; + } + + /** + * The original message (if present) at the point in the stack where the + * ErrorMessage was created. + * @return the originalMessage + */ + public Message getOriginalMessage() { + return originalMessage; + } + + @Override + public String toString() { + if (this.originalMessage == null) { + return super.toString(); + } + else { + StringBuilder sb = new StringBuilder(super.toString()); + if (sb.length() > 0) { + sb.setLength(sb.length() - 1); + } + sb.append(", originalMessage=").append(this.originalMessage.toString()).append("]"); + return sb.toString(); + } } } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/support/ErrorMessageTests.java b/spring-messaging/src/test/java/org/springframework/messaging/support/ErrorMessageTests.java new file mode 100644 index 0000000000..ce617c7051 --- /dev/null +++ b/spring-messaging/src/test/java/org/springframework/messaging/support/ErrorMessageTests.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.messaging.support; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * + * @author Gary Russell + * @since 5.0 + */ +public class ErrorMessageTests { + + @Test + public void testToString() { + ErrorMessage em = new ErrorMessage(new RuntimeException("foo")); + String emString = em.toString(); + assertThat(emString, not(containsString("originalMessage"))); + em = new ErrorMessage(new RuntimeException("foo"), new GenericMessage<>("bar")); + emString = em.toString(); + assertThat(emString, containsString("}, originalMessage=")); + } + +}