观察参数类型不匹配 Spring Amqp Remoting With Kotlin
Observing argument type mismatch Spring Amqp Remoting With Kotlin
虽然服务只有 1 个参数,但在将 spring 与 kotlin 组合使用时,我总是遇到参数不匹配。
我也调试过
org.springframework.remoting.support.RemoteInvocation.invoke
方法
我可以看到它正好传递了 1 个参数和正确的 targetObject。但是invoke(targetObject, this.arguments);
导致参数不匹配。
源代码:
https://github.com/c-nnooka/RabbitMqRemotingKotlin
异常
Caused by: **java.lang.Throwable: argument type mismatch**
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_161]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_161]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_161]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_161]
at org.springframework.remoting.support.RemoteInvocation.invoke(RemoteInvocation.java:215) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.DefaultRemoteInvocationExecutor.invoke(DefaultRemoteInvocationExecutor.java:39) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.RemoteInvocationBasedExporter.invoke(RemoteInvocationBasedExporter.java:78) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.RemoteInvocationBasedExporter.invokeAndCreateResult(RemoteInvocationBasedExporter.java:114) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.amqp.remoting.service.AmqpInvokerServiceExporter.onMessage(AmqpInvokerServiceExporter.java:80) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1457) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1348) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1324) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1303) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:785) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:769) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access0(SimpleMessageListenerContainer.java:77) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1010) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_161]
at org.springframework.remoting.support.RemoteInvocationUtils.fillInClientStackTraceIfPossible(RemoteInvocationUtils.java:45) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.RemoteInvocationResult.recreate(RemoteInvocationResult.java:156) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.amqp.remoting.client.AmqpClientInterceptor.invoke(AmqpClientInterceptor.java:78) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at com.sun.proxy.$Proxy108.findJobById(Unknown Source) ~[?:?]
接口详情:
interface IJobQueryService{
fun findJobById(args : QueryJobArgs) : QueryJobResponse
}
interface IJobService : IJobQueryService
服务实现细节:
class JobController(val jobQueryService: IJobQueryService) : IJobService{
override fun findJobById(args: QueryJobArgs): QueryJobResponse {
return jobQueryService.findJobById(args)
}
}
BeanConfiguration:(注意:为简单起见未指定完整配置)
@Bean
fun rmsExporter(rabbitTemplate: RabbitTemplate):AmqpInvokerServiceExporter {
val exporter = AmqpInvokerServiceExporter();
exporter.amqpTemplate = rabbitTemplate;
exporter.service = JobController(JobQueryProvider());
exporter.serviceInterface = IJobService::class.java
exporter.messageConverter = producerJackson2MessageConverter()
return exporter;
}
@Bean
fun rmxProxy(rabbitTemplate: RabbitTemplate) : AmqpProxyFactoryBean {
val proxy = AmqpProxyFactoryBean();
proxy.amqpTemplate = rabbitTemplate;
proxy.serviceInterface = IJobService::class.java
proxy.routingKey = "rms.webservice.api"
return proxy;
}
调用详细信息
val jobservice = applicationContext.getBean(IJobService::class.java)
println("Remoting Is On => " + jobservice.findJobById(QueryJobArgs().apply { job = Job().apply { id = 1 } } ))
您尝试通过网络传输 JSON 的问题。
因此,AmqpClientInterceptor
将您的 QueryJobArgs
包装到 RemoteInvocation
object 中,并且已经将其序列化为 JSON,例如:
(Body:'{"methodName":"findJobById","parameterTypes":["com.example.rabbiitmqremoting.args.job.QueryJobArgs"],"arguments":[{"job":{"id":1,"createdBy":null}}],"attributes":null}' MessageProperties [headers={__TypeId__=org.springframework.remoting.support.RemoteInvocation}, contentType=application/json, contentEncoding=UTF-8, contentLength=167, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])
关注__TypeId__=org.springframework.remoting.support.RemoteInvocation
header。这个用于消费者端将内容反序列化为 RemoteInvocation
。但是由于 arguments
没有(自动)信息被反序列化为 QueryJobArgs
,它们仍然是 LinkedHashMap
。因此Caused by: java.lang.Throwable: argument type mismatch
.
作为解决方法,我建议您返回到 SimpleMessageConverter
,它将使用标准 Java 序列化机制。
更新
好的!你知道我也用 JSON 破解了这个。
所以,我这样做了:
@Autowired
lateinit var objectMapper: ObjectMapper
@PostConstruct
fun init() {
this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
}
并将此 objectMapper
注入到 RabbitConfig
中显示的所有 Jackson
转换器中。现在它按预期工作:
Hellow From RMS
Remoting Is On => com.example.rabbiitmqremoting.response.QueryJobResponse@151bf776
我还删除了所有与messageHandlerMethodFactory
相关的修改。看起来它没有参与 RPC。
但是你可能需要它来做一些其他的事情。不过故事不同...
虽然服务只有 1 个参数,但在将 spring 与 kotlin 组合使用时,我总是遇到参数不匹配。
我也调试过
org.springframework.remoting.support.RemoteInvocation.invoke
方法
我可以看到它正好传递了 1 个参数和正确的 targetObject。但是invoke(targetObject, this.arguments);
导致参数不匹配。
源代码:
https://github.com/c-nnooka/RabbitMqRemotingKotlin
异常
Caused by: **java.lang.Throwable: argument type mismatch**
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_161]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_161]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_161]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_161]
at org.springframework.remoting.support.RemoteInvocation.invoke(RemoteInvocation.java:215) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.DefaultRemoteInvocationExecutor.invoke(DefaultRemoteInvocationExecutor.java:39) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.RemoteInvocationBasedExporter.invoke(RemoteInvocationBasedExporter.java:78) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.RemoteInvocationBasedExporter.invokeAndCreateResult(RemoteInvocationBasedExporter.java:114) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.amqp.remoting.service.AmqpInvokerServiceExporter.onMessage(AmqpInvokerServiceExporter.java:80) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1457) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1348) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1324) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1303) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:785) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:769) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access0(SimpleMessageListenerContainer.java:77) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1010) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_161]
at org.springframework.remoting.support.RemoteInvocationUtils.fillInClientStackTraceIfPossible(RemoteInvocationUtils.java:45) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.remoting.support.RemoteInvocationResult.recreate(RemoteInvocationResult.java:156) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.amqp.remoting.client.AmqpClientInterceptor.invoke(AmqpClientInterceptor.java:78) ~[spring-amqp-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at com.sun.proxy.$Proxy108.findJobById(Unknown Source) ~[?:?]
接口详情:
interface IJobQueryService{
fun findJobById(args : QueryJobArgs) : QueryJobResponse
}
interface IJobService : IJobQueryService
服务实现细节:
class JobController(val jobQueryService: IJobQueryService) : IJobService{
override fun findJobById(args: QueryJobArgs): QueryJobResponse {
return jobQueryService.findJobById(args)
}
}
BeanConfiguration:(注意:为简单起见未指定完整配置)
@Bean
fun rmsExporter(rabbitTemplate: RabbitTemplate):AmqpInvokerServiceExporter {
val exporter = AmqpInvokerServiceExporter();
exporter.amqpTemplate = rabbitTemplate;
exporter.service = JobController(JobQueryProvider());
exporter.serviceInterface = IJobService::class.java
exporter.messageConverter = producerJackson2MessageConverter()
return exporter;
}
@Bean
fun rmxProxy(rabbitTemplate: RabbitTemplate) : AmqpProxyFactoryBean {
val proxy = AmqpProxyFactoryBean();
proxy.amqpTemplate = rabbitTemplate;
proxy.serviceInterface = IJobService::class.java
proxy.routingKey = "rms.webservice.api"
return proxy;
}
调用详细信息
val jobservice = applicationContext.getBean(IJobService::class.java)
println("Remoting Is On => " + jobservice.findJobById(QueryJobArgs().apply { job = Job().apply { id = 1 } } ))
您尝试通过网络传输 JSON 的问题。
因此,AmqpClientInterceptor
将您的 QueryJobArgs
包装到 RemoteInvocation
object 中,并且已经将其序列化为 JSON,例如:
(Body:'{"methodName":"findJobById","parameterTypes":["com.example.rabbiitmqremoting.args.job.QueryJobArgs"],"arguments":[{"job":{"id":1,"createdBy":null}}],"attributes":null}' MessageProperties [headers={__TypeId__=org.springframework.remoting.support.RemoteInvocation}, contentType=application/json, contentEncoding=UTF-8, contentLength=167, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])
关注__TypeId__=org.springframework.remoting.support.RemoteInvocation
header。这个用于消费者端将内容反序列化为 RemoteInvocation
。但是由于 arguments
没有(自动)信息被反序列化为 QueryJobArgs
,它们仍然是 LinkedHashMap
。因此Caused by: java.lang.Throwable: argument type mismatch
.
作为解决方法,我建议您返回到 SimpleMessageConverter
,它将使用标准 Java 序列化机制。
更新
好的!你知道我也用 JSON 破解了这个。
所以,我这样做了:
@Autowired
lateinit var objectMapper: ObjectMapper
@PostConstruct
fun init() {
this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
}
并将此 objectMapper
注入到 RabbitConfig
中显示的所有 Jackson
转换器中。现在它按预期工作:
Hellow From RMS
Remoting Is On => com.example.rabbiitmqremoting.response.QueryJobResponse@151bf776
我还删除了所有与messageHandlerMethodFactory
相关的修改。看起来它没有参与 RPC。
但是你可能需要它来做一些其他的事情。不过故事不同...