Spring JMS MappingJackson2MessageConverter – 没有处理错误的方法

huangapple go评论75阅读模式
英文:

Spring JMS MappingJackson2MessageConverter - No way to handle errors

问题

我正在使用Spring JMS与ActiveMQ,并且正在使用MappingJackson2MessageConverter在各个组件之间传递消息。

我的核心问题是,当MappingJackson2MessageConverter在将String反序列化为某个对象时遇到内部反序列化错误时,这些异常没有以任何我可以响应的方式被引发出来。我的错误处理逻辑从未被调用过,我也无法访问任何异常。这些反序列化错误似乎被完全吞没了,尽管它们在控制台中被记录下来,但我没有任何机会根据它们执行自定义逻辑。

我如下所示定义了我的MappingJackson2MessageConverter bean:

  @Bean
  public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName("type");
    return converter;
  }

我如下所示定义了一个JMS监听器工厂:

  @Bean
  public JmsListenerContainerFactory<?> jmsListenerQueueFactory(ConnectionFactory connectionFactory,
      DefaultJmsListenerContainerFactoryConfigurer configurer, JmsErrorHandler jmsErrorHandler) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setErrorHandler(jmsErrorHandler); // <-- 我希望这个会被使用
    configurer.configure(factory, connectionFactory);

    return factory;
  }

在上面的代码中,setErrorHandler 调用是重要的。我定义了一个简单的 ErrorHandler 对象,试图捕获 @JmsListener 方法可能抛出的错误。这个简单的错误处理程序如下:

public class JmsErrorHandler implements ErrorHandler {

  @Override
  public void handleError(Throwable t) {
    System.out.println("我们有错误!");
  }
}

我的监听器也很简单,如下所示:

@JmsListener(id = MY_ID, destination = MY_DEST)
public void processMessage(MyPojoMessage myPojoMessage) {
     // 这段代码显然永远不会被执行,因为发生了序列化错误。
}

总体来说,这是一个非常简单和基本的设置。现在,当我发送一个无效的消息,Jackson无法解析时,我在控制台中得到以下错误:

19-10-2020 09:05:33.933 [DefaultMessageListenerContainer-1] WARN o.s.j.l.DefaultMessageListenerContainer.invokeErrorHandler - Execution of JMS message listener failed, and no ErrorHandler has been set.

org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void com.example.processMessage(com.example.MyPojoMessage)' threw exception; nested exception is org.springframework.jms.support.converter.MessageConversionException: Failed to convert JSON message content; nested exception is com.fasterxml.jackson.databind.JsonMappingException

这个异常是预期的,因为我提供了一个Jackson无法序列化的无效载荷。然而,似乎没有任何方法可以配置代码以实际捕获这个异常,以便我可以对其进行响应。我在上面的代码中设置了错误处理程序。然而,日志抱怨没有设置ErrorHandler,这似乎是错误的。

我看不到其他获取这个Jackson内部异常引用的方法。有没有任何办法?

英文:

I am using Spring JMS with ActiveMQ, and I am using the MappingJackson2MessageConverter to pass along messages between various components.

My core problem is that when the MappingJackson2MessageConverter experiences an internal deserialization error, when deserializing a String into some Object, these exceptions are not raised in any way that I can respond to them. My Error Handler logic never gets called, and no exceptions are thrown that I have access to. These deserialization errors appear to be completely swallowed and, while they are logged in the console, I am offered no chance to perform custom logic in response to them.

I define my MappingJackson2MessageConverter bean as follows:

  @Bean
  public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName(&quot;_type&quot;);
    return converter;
  }

I define a JMS Listener factory as follows:

  @Bean
  public JmsListenerContainerFactory&lt;?&gt; jmsListenerQueueFactory(ConnectionFactory connectionFactory,
      DefaultJmsListenerContainerFactoryConfigurer configurer, JmsErrorHandler jmsErrorHandler) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setErrorHandler(jmsErrorHandler); // &lt;-- I expect this to be used
    configurer.configure(factory, connectionFactory);

    return factory;
  }

Of importance in the above line is the setErrorHandler call. I have defined a simple ErrorHandler object that is attempting to catch errors that my @JmsListener methods may throw. This simple error handler looks like this:

  public class JmsErrorHandler implements ErrorHandler {

  @Override
  public void handleError(Throwable t) {
    System.out.println(&quot;WE HAVE THE ERROR!&quot;);
  }
}

My listener is also simple, as follows:

  @JmsListener(id = MY_ID, destination = MY_DEST)
  public void processMessage(MyPojoMessage myPojoMessage) {
     // This code is obviously never reached, since the serialization error occurs. 

Overall, this is a very simple and basic setup. Now when I send an invalid message, that Jackson will fail to parse, I get the following errors in my console:

19-10-2020 09:05:33.933 [DefaultMessageListenerContainer-1] WARN  o.s.j.l.DefaultMessageListenerContainer.invokeErrorHandler - Execution of JMS message listener failed, and no ErrorHandler has been set.

org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method &#39;public void com.example.processMessage(com.example.MyPojoMessage)&#39; threw exception; nested exception is org.springframework.jms.support.converter.MessageConversionException: Failed to convert JSON message content; nested exception is com.fasterxml.jackson.databind.JsonMappingException

This exception is expected - since I provide an invalid payload that Jackson cannot serialize. However, there is seemingly no way for me to configure the code to actually catch this exception in a way I can respond to it. I am setting the Error Handler in the above code. Yet the logs complain that no ErrorHandler has been set which seems wrong.

I see no other ways to get a reference to this Jackson inner exception. Is there any way?

答案1

得分: 3

看起来 ConditionalOnMissingBean 自动配置已经开启,针对 bean name

所以你应该有类似以下的代码:

@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory(ConnectionFactory connectionFactory,
    DefaultJmsListenerContainerFactoryConfigurer configurer, JmsErrorHandler jmsErrorHandler) {
  DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
  factory.setErrorHandler(jmsErrorHandler); // <-- 我期望这部分会被使用
  configurer.configure(factory, connectionFactory);
  return factory;
}
英文:

Looks like ConditionalOnMissingBean autoconfiguration is on bean name

So you should have something like this.

@Bean
  public JmsListenerContainerFactory&lt;?&gt; jmsListenerContainerFactory(ConnectionFactory connectionFactory,
      DefaultJmsListenerContainerFactoryConfigurer configurer, JmsErrorHandler jmsErrorHandler) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setErrorHandler(jmsErrorHandler); // &lt;-- I expect this to be used
    configurer.configure(factory, connectionFactory);
    return factory;
  }

huangapple
  • 本文由 发表于 2020年10月19日 21:12:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/64428070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定