Spring AMQP RabbitMQ InboundChannelAdapter和OutboundEndpoint不同的序列化/反序列化策略
我有一门课:Spring AMQP RabbitMQ InboundChannelAdapter和OutboundEndpoint不同的序列化/反序列化策略,spring,spring-integration,spring-amqp,spring-rabbit,Spring,Spring Integration,Spring Amqp,Spring Rabbit,我有一门课: public类SomeClass实现可序列化{ 私有字符串名称; 公共静态SomeClass值(字符串值){ //这里验证并返回SomeClass } } 它的序列化程序/反序列化程序: 公共类SomeClassSerializer扩展JsonSerializer{ @凌驾 公共void序列化(SomeClass SomeClass、JsonGenerator生成器、SerializerProvider提供程序)引发IOException{ generator.writeStri
public类SomeClass实现可序列化{
私有字符串名称;
公共静态SomeClass值(字符串值){
//这里验证并返回SomeClass
}
}
它的序列化程序/反序列化程序:
公共类SomeClassSerializer扩展JsonSerializer{
@凌驾
公共void序列化(SomeClass SomeClass、JsonGenerator生成器、SerializerProvider提供程序)引发IOException{
generator.writeString(someClass.getName());
}
}
公共类SomeClassDeserializer扩展JsonDeserializer{
@凌驾
公共SomeClass反序列化(JsonParser解析器,反序列化上下文)引发IOException{
最终字符串名称=((TextNode)parser.getCodec().readTree(parser)).textValue();
返回SomeClass.valueOf(name);
}
}
在myJackson2ObjectMapperBuilder
配置中:
builder.serializerByType(SomeClass.class,新的SomeClassSerializer());
反序列化器ByType(SomeClass.class,新的SomeClassDeserializer());
当SomeClass
位于POST
/GET
请求的主体中时,一切都会顺利进行。但是,通过Spring集成,我有:
返回Amqp
.内置适配器(容器)
.outputChannel(someClassChannel)
.messageConverter(新的Jackson2JsonMessageConverter(objectMapperBuilder.build()))
.get();
至于离港旅客:
@ServiceActivator(inputChannel=“someChannel”)
公共AMQOutboundEndpoint someOutboundEndpoint(RabbitTemplate RabbitTemplate,
FanoutExchange(交换机){
返回Amqp
.outboundAdapter(rabbitTemplate)
.exchangeName(exchange.getName())
.get();
}
使用myRabbitTemplate
config:
@Bean
公共RabbitTemplate RabbitTemplate(Jackson2对象映射生成器对象映射生成器){
最终RabbitTemplate RabbitTemplate=新RabbitTemplate(连接工厂);
rabbitTemplate.setMessageConverter(新Jackson2JsonMessageConverter(objectMapperBuilder
.serializerByType(SomeClass.class,新的SomeClassSerializer())
.build());
返回兔模板;
}
和我的网关
:
网关(requestChannel=“someChannel”)
void publishEvent(@Header(value=“someClass”)someClass-someClass,@Payload-Object-Payload);
当我发送消息时,我在调用SomeClass
的valueOf
方法SomeClass
(我抛出InvalidArgumentException
)的SomeClassDeserializer中遇到异常:
完整堆栈跟踪:
org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor@43a251c4]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.messaging.handler.annotation.Header com.company.project.domain.package.SomeClass] for value 'com.company.project.domain.package.SomeClass@ec7887e4'; nested exception is java.lang.IllegalArgumentException: Couldn't convert value : com.company.project.domain.package.SomeClass@ec7887e4 into a valid com.company.project.domain.package.SomeClass object, failedMessage=GenericMessage [payload=com.company.project.security.domain.client.Client@55095ce3, headers={amqp_receivedDeliveryMode=PERSISTENT, amqp_receivedExchange=com.company, amqp_deliveryTag=1, amqp_consumerQueue=com.company.web.192.168.1.34, amqp_redelivered=false, amqp_contentEncoding=UTF-8, json__TypeId__=com.company.project.security.domain.client.Client, amqp_timestamp=Fri Oct 30 12:13:00 EET 2020, amqp_messageId=1dffe404-2235-4f79-4a14-315c896c3c4e, id=bcaa71d5-b454-e65c-6939-b9f07b7cc47b, event=com.company.project.domain.package.SomeClass@ec7887e4, amqp_consumerTag=amq.ctag-ImFjO9LBGoks9Lm3E0EkbQ, contentType=application/json, __TypeId__=com.company.project.security.domain.client.Client, timestamp=1604049180277}]
at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:191)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:111)
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:95)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:127)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:170)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:224)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.access$000(BroadcastingDispatcher.java:56)
at org.springframework.integration.dispatcher.BroadcastingDispatcher$1.run(BroadcastingDispatcher.java:204)
at org.springframework.integration.util.ErrorHandlingTaskExecutor.lambda$execute$0(ErrorHandlingTaskExecutor.java:57)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.messaging.handler.annotation.Header com.company.project.domain.package.SomeClass] for value 'com.company.project.domain.package.SomeClass@ec7887e4'; nested exception is java.lang.IllegalArgumentException: Couldn't convert value : com.company.project.domain.package.SomeClass@ec7887e4 into a valid com.company.project.domain.package.SomeClass object
at org.springframework.core.convert.support.ObjectToObjectConverter.convert(ObjectToObjectConverter.java:112)
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191)
at org.springframework.messaging.handler.annotation.support.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:111)
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:117)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:148)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper$HandlerMethod.invoke(MessagingMethodInvokerHelper.java:1096)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.invokeHandlerMethod(MessagingMethodInvokerHelper.java:580)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.processInternal(MessagingMethodInvokerHelper.java:476)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.process(MessagingMethodInvokerHelper.java:355)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:108)
... 10 more
Caused by: java.lang.IllegalArgumentException: Couldn't convert value : com.company.project.domain.package.SomeClass@ec7887e4 into a valid com.company.project.domain.package.SomeClass object
at com.company.project.domain.package.SomeClass.valueOf(SomeClass.java:148)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.core.convert.support.ObjectToObjectConverter.convert(ObjectToObjectConverter.java:102)
通过尝试使用valueOf
方法反序列化SomeClass
,我发现反序列化程序使用的是正确的反序列化程序。但是,它试图反序列化的值是,com.company.project。SomeClass@ec7887e4
不是我提供的序列化程序的结果(尽管我在rabbitmplate
配置中向Jackson2ObjectMapperBuilder
提供了所需的序列化程序)。可能是虫子,或者我做错了什么
更新:
下面是另一个意外行为:
我已临时将SomeClassDeserializer
切换到:
公共类SomeClassDeserializer扩展JsonDeserializer{
@凌驾
公共SomeClass反序列化(JsonParser解析器,反序列化上下文)引发IOException{
最终字符串名称=((TextNode)parser.getCodec().readTree(parser)).textValue();
返回新的SomeClass(名称);
}
}
而SomeClass
上的valueOf
方法一直在调用,而不是新SomeClass反序列化器上的newsomeclass(name)
。此时,我将静态方法的名称从valueOf
切换到valueOfName
我的实际新实现开始被调用
由于没有对SomeClass
的构造函数进行验证,因此出现了异常,尽管这次它开始反序列化为
newsomeclass(“com.company.project.domain.package。SomeClass@ec7887e4")
而不是
newsomeclass(“myActualValue”)
无法转换值:com.company.project.domain.package。SomeClass@ec7887e4进入有效的com.company.project.domain.package.SomeClass
看起来我们只是将类名作为字符串发送
com.company.project.domain.package。SomeClass@ec7887e4
这是对象上的默认toString()
实现
i、 e.SomeClass.getName()
而不是SomeClass.getName()
(假设类上有一个getName()
方法)
编辑
对不起,我没注意到是头球
消息转换器仅对有效负载执行转换
对于头文件,您需要实现一个自定义的HeaderMapper
——Spring只是将头文件传递给amqp客户机,而amqp客户机对它不知道的类型执行toString()
子类化DefaultAmqpHeaderMapper
并覆盖出站端的populateUserDefinedHeader
,以及入站端的extractUserDefinedHeaders
。显示完整堆栈跟踪。@GaryRussell更新了问题。@GaryRussell我添加了另一个我不期望的行为,如果有帮助的话。谢谢。Tha这是我的观点。SomeClassSerializer
不应该被使用吗,就像我的SomeClassDeserializer
被使用一样?或者,我的反序列化器没有被使用,而只是带有SomeClass(字符串名)的构造函数吗正在调用
,即不支持对@标头
进行自定义序列化/反序列化