Java Spring AMQP-Jackson2JsonMessageConverter设置_TypeId_uu,自版本2.1起,使用接口而不是具体类型 问题
我们已将Spring boot版本从2.0.5升级到2.1.8。Java Spring AMQP-Jackson2JsonMessageConverter设置_TypeId_uu,自版本2.1起,使用接口而不是具体类型 问题,java,spring,spring-amqp,Java,Spring,Spring Amqp,我们已将Spring boot版本从2.0.5升级到2.1.8。 因此,Spring AMQP也从2.0.6升级到了2.1.8 此后,Jackson2JsonMessageConverter无法解析来自@RabbitListener注释方法的应答消息,因为它们返回一个接口(实际上在代码中声明为泛型)。此接口用于设置消息\u TypeId\u属性 在2.0版本中,它用于将TypeId设置为实际的混凝土类 我做了一些挖掘,下面是我对这个问题的理解(代码如下) 当带@RabbitListener注释的
因此,Spring AMQP也从2.0.6升级到了2.1.8 此后,
Jackson2JsonMessageConverter
无法解析来自@RabbitListener注释方法的应答消息,因为它们返回一个接口(实际上在代码中声明为泛型)。此接口用于设置消息\u TypeId\u
属性
在2.0版本中,它用于将TypeId设置为实际的混凝土类
我做了一些挖掘,下面是我对这个问题的理解(代码如下)
当带@RabbitListener注释的方法返回时,将调用MessagingMessageListenerAdapter#onMessage
,并将结果封装在InvocationResult
对象中,该对象包含genericType
属性
这个genericType
是从@RabbitListener注释的方法的返回类型设置的
然后,Jackson2JsonMessageConverter#createMessage
方法使用它来设置\u TypeId
属性
另一方面,Jackson2JsonMessageConverter#fromMessage
可以使用此属性解析Json以找出实际的类型
问题是,由于引入了InvocationResult
和genericType
,我们用@RabbitListener注释的方法被声明为返回一个接口,因此\u TypeId\u
属性是用接口而不是实际的具体类设置的。以下是来自Jackson2JsonMessageConverter#fromMessage
(实际上来自AbstractJackson2MessageConverter
)的代码位,该位已更改(除其他外):
if(getClassMapper()==null){
getJavaTypeMapper().fromJavaType(this.objectMapper.constructType(
genericType==null?objectToConvert.getClass():genericType),messageProperties);
}
否则{
getClassMapper().fromClass(objectToConvert.getClass(),messageProperties);//NOSONAR从不为null
}
由于genericType不为null并且包含interfaceType。。。你可以看到我们的麻烦
在版本2.1之前,我们没有添加任何问题,因为Jackson2JsonMessageConverter#createMessage()始终直接使用objectToConvert.getClass()
:
if(getClassMapper()==null){
getJavaTypeMapper().fromJavaType(this.jsonObjectMapper.constructType(objectToConvert.getClass()),
信息属性);
}
否则{
getClassMapper().fromClass(objectToConvert.getClass(),
信息属性);
}
代码
这是我们的代码:
公共抽象类AWorker{
@RabbitListener(queues=“${rabbit.worker.queue}”
,errorHandler=“workerErrorHandler”
,returnExceptions=“true”)
public O receiveMessage(I inputMessage,@Header(LoggerUtil.LOGGER\u MDC\u ID)字符串mdcId,@Header(RabbitConstants.CONTEXT\u INFO\u Header\u KEY)字符串contextInfoStr){
if(requestdTofIrTimImplementation.class的inputMessage实例){
返回新的ResponseDtoFirstImplementation();
}否则{
返回新的ResponseDtoSecondImplementation();
}
}
}
当然,receiveMessage
方法的内容得到了简化,关键是实际实现可以根据输入的具体类型返回不同的具体类型
可能的解决办法
我想有两种可能的解决方法,但没有一种是真正好的或易于维护的
第一种方法是使用RemoteInvocationAwareMessageConverterAdapter
封装Jackson2jsonMessageConverter
。
如果我这样做,就会调用MessageConverter#toMessaget(Object-Object,MessageProperties-MessageProperties)
,而不是MessageConverter#toMessage(Object-Object,MessageProperties-MessageProperties,@Nullable-Type-genericype)
,因此我们回到原来的方式。但这听起来更像是一种黑客行为,而不是一个恰当的解决方案。如果
RemoteInvocationAwareMessageConverter
改变了它的行为,我们就回到了最初的问题
第二种方法是使用现有的类映射器,但即使它可以工作,维护起来也比较困难(特别是当涉及到trustedPackages时,如果我们有很多来自不同包的类需要序列化)。或者实现一个customClassMapper,这也增加了一些工作要做
由于它在2.1版之前工作正常,我不确定是否绝对有必要重新实现ClassMapper
但我找不到任何简单的方法来使用具体类型设置genericType,这似乎是一种回归,因为。请打开一个。谢谢@GaryRussell,我这样做了。这似乎是由于。请打开一个。谢谢@GaryRussell,我会的。