0

I have a listener to the JMS. Once I read the message then I convert to my custom object

public IntegrationFlow queueProcessorFlow() {
        return IntegrationFlows.from(Jms.inboundAdapter(jmsTemplate)

                        .destination("test_queue"),
                c -> c.poller(Pollers.fixedDelay(5000L)
                        .maxMessagesPerPoll(1)))

                //convert json to our custom object
                .transform(new JsonToQueueEventConverterTransformer(springBeanFactory))

                .transform(new CustomTransformer(springBeanFactory))


                .handle(o -> {


                }).get();
    }

The transformer

public class CustomerTransformer implements GenericTransformer<CustomPojo, CustomPojo> {


    private final QueueDataProcessorSpringBeanFactory factory;


    @Override
    public CustomPojo transform(CustomPojo CustomPojo) {
        try {

           //do something e.g. service call
           throw new Exception("This failed mate !! SOS");
        } catch (Exception e) {            

        //ISSUE here 
        //e contains the original payload in the stack trace 
            throw new RuntimeException(e);
        }
        return CustomPojo;

    }

Now when I throw my custom exception the stack trace contains everything. It even contains the payload. I am not interested in the payload in case of exception.

How do I update not to include payload?

** Update **

After changing as per answer I still see the issue

org.springframework.integration.transformer.MessageTransformationException: Failed to transform Message; nested exception is org.springframework.messaging.MessageHandlingException: nested exception is org.springframework.integration.transformer.MessageTransformationException: Error initiliazing the :; nested exception is CustomException Error lab lab lab  , failedMessage=GenericMessage [payload=

my error handler

 @Bean
    public IntegrationFlow errorHandlingFlow() {
        return IntegrationFlows.from("errorChannel")
                .handle(message -> {
                    try {

                        ErrorMessage e = (ErrorMessage) message;
                        if (e.getPayload() instanceof MessageTransformationException) {
                            String stackTrace = ExceptionUtils.getStackTrace(e.getPayload());
                            LOG.info("Exception trace {} ", stackTrace);
Makky
  • 17,117
  • 17
  • 63
  • 86

2 Answers2

1

Not sure what is the business purpose to lose a payload in the stack trace, but you can achieve that throwing a MessageTransformationException instead of that RuntimeException.

To avoid a message in stack trace with the mentioned payload, you need to use one of these constructors:

public MessageTransformationException(String description, Throwable cause) {
    super(description, cause);
}

public MessageTransformationException(String description) {
    super(description);
}

Instead of those based on the Message<?>.

This way a wrapping MessageTransformingHandler will do an appropriate logic:

protected Object handleRequestMessage(Message<?> message) {
    try {
        return this.transformer.transform(message);
    }
    catch (Exception e) {
        if (e instanceof MessageTransformationException) {
            throw (MessageTransformationException) e;
        }
        throw new MessageTransformationException(message, "Failed to transform Message", e);
    }
}

UPDATE

It turned out that MessageTransformationException is not enough since the AbstractMessageHandler checks for the MessageHandlingException for wrapping in the IntegrationUtils.wrapInHandlingExceptionIfNecessary(). Therefore I suggest to throw a MessageHandlingException from your code instead. And use this constructor with the null for the message arg:

MessageHandlingException(Message<?> failedMessage, Throwable cause)
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Its because I already have converted to my custom pojo from the payload so I don't require the payload as later on in the ErrorChannel handler I need to save the stacktrace and the message get really big – Makky Dec 03 '18 at 14:55
  • I am not sure how you suggesting to use MessageTransformingHandler here based on my code ? – Makky Dec 03 '18 at 14:59
  • Even using that constructor I see GenericMessage [payload= in the MessageTransformationException when I catch in "errorChannel" – Makky Dec 03 '18 at 15:15
  • Would you mind to update your code and share stack trace after you throw `MessageTransformationException`? – Artem Bilan Dec 03 '18 at 15:24
  • Hm. OK. Try `MessageHandlingException(Message> failedMessage, Throwable cause)` instead. I see that `IntegrationUtils.wrapInHandlingExceptionIfNecessary()` is used to wrap that exception to the `MessageHandlingException` with the `requestMessage` as failed one. If you throw exactly this one, that function won't have an effect and your error channel will get exactly yours exception. – Artem Bilan Dec 03 '18 at 16:04
  • Can you update the aanswer please for others reference as well. – Makky Dec 03 '18 at 18:26
  • Updated my answer. – Artem Bilan Dec 03 '18 at 18:30
  • How doesn't it work? What is the current stack trace in that error channel? – Artem Bilan Dec 03 '18 at 18:49
  • OK. I see where is the problem. The `MethodInvokingMessageProcessor` doesn't honor an exception and just wrap it into one more `MessageHandlingException`. Please, raise a JIRA on the matter and we will consider what to do on the matter. – Artem Bilan Dec 03 '18 at 19:01
  • Is there any temporary fix I can use – Makky Dec 03 '18 at 19:12
  • No, there is no simple way. You can consider to use a `AbstractReplyProducingMessageHandler` implementation though to bypass all those POJO method wrapping. – Artem Bilan Dec 03 '18 at 19:31
  • I didn't see a JIRA created for this. Currently there is no other method to mask/hide payload that contains private info? – user2673474 Feb 19 '19 at 15:12
  • We don’t have a ticket for that, but here is a PR on the matter: https://github.com/spring-projects/spring-integration/pull/2646 – Artem Bilan Feb 19 '19 at 15:19
0

I had almost the same issue maybe this can help you. If you use the default errorChannel Bean this already has been subscribed to a LoggingHandler which prints the the full message, if you want avoid printing the payload you can create your own errorChannel by this way you'll override the default behavior

    @Bean
    @Qualifier(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)
    public MessageChannel errorChannel() {
        return new PublishSubscribeChannel();
    }

If your problem is when you use the .log() handler you can always use a function to decide which part of the Message you want to show

  @Bean
  public IntegrationFlow errorFlow(IntegrationFlow 
    createOutFileInCaseErrorFlow) {
    return 
    IntegrationFlows.from(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)
   .log(LoggingHandler.Level.ERROR, m -> m.getHeaders())
   .<MessagingException>log(Level.ERROR, p -> p.getPayload().getMessage())
   .get();
  }
Miguel Galindo
  • 111
  • 1
  • 3