|
113 | 113 | import org.springframework.messaging.MessagingException; |
114 | 114 | import org.springframework.messaging.SubscribableChannel; |
115 | 115 | import org.springframework.messaging.support.ChannelInterceptor; |
| 116 | +import org.springframework.messaging.support.GenericMessage; |
116 | 117 | import org.springframework.scheduling.TaskScheduler; |
117 | 118 | import org.springframework.scheduling.Trigger; |
118 | 119 | import org.springframework.scheduling.support.CronTrigger; |
@@ -409,12 +410,19 @@ private <T> Message<T> wrapToMessageIfNecessary(T value) { |
409 | 410 | } |
410 | 411 |
|
411 | 412 | private static <P> Message<P> sanitize(Message<P> inputMessage) { |
412 | | - return MessageBuilder |
| 413 | + Message<P> sanitized = MessageBuilder |
413 | 414 | .fromMessage(inputMessage) |
414 | 415 | .removeHeader("spring.cloud.stream.sendto.destination") |
415 | | -// .setHeader(MessageUtils.SOURCE_TYPE, inputMessage.getHeaders().get(MessageUtils.TARGET_PROTOCOL)) |
416 | | -// .removeHeader(MessageUtils.TARGET_PROTOCOL) |
417 | 416 | .build(); |
| 417 | + if (sanitized == inputMessage) { |
| 418 | + // MessageBuilder.build() returns the same instance when no header was |
| 419 | + // actually modified (fast-path in BaseMessageBuilder), which skips the |
| 420 | + // GenericMessage constructor and therefore skips stamping a "timestamp" |
| 421 | + // header. Force a fresh GenericMessage so the header is always present, |
| 422 | + // restoring pre-4.3.3 behavior. See GH-3211. |
| 423 | + sanitized = new GenericMessage<>(inputMessage.getPayload(), inputMessage.getHeaders()); |
| 424 | + } |
| 425 | + return sanitized; |
418 | 426 | } |
419 | 427 |
|
420 | 428 | private static class FunctionToDestinationBinder implements InitializingBean, ApplicationContextAware { |
|
0 commit comments