Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

接口传参中,有null时,处理异常 #73

Closed
chywwq opened this issue Sep 11, 2018 · 8 comments
Closed

接口传参中,有null时,处理异常 #73

chywwq opened this issue Sep 11, 2018 · 8 comments

Comments

@chywwq
Copy link

chywwq commented Sep 11, 2018

@ServiceProvider(group = "demo", name = "helloworld")
public interface HelloService {
    String m1(String arg1, String arg2, List<String> arg3);
}
helloService.m1("arg1", null, Arrays.asList("arg3.1", "arg3.2"))

调用后报错:
Exception in thread "main" org.jupiter.rpc.exception.JupiterBizException: java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
at org.jupiter.rpc.consumer.future.DefaultInvokeFuture.setException(DefaultInvokeFuture.java:215)
at org.jupiter.rpc.consumer.future.DefaultInvokeFuture.doReceived(DefaultInvokeFuture.java:189)
at org.jupiter.rpc.consumer.future.DefaultInvokeFuture.received(DefaultInvokeFuture.java:243)
at org.jupiter.rpc.consumer.processor.task.MessageTask.run(MessageTask.java:81)
at org.jupiter.rpc.executor.CallerRunsExecutorFactory$1.execute(CallerRunsExecutorFactory.java:36)
at org.jupiter.rpc.consumer.processor.DefaultConsumerProcessor.handleResponse(DefaultConsumerProcessor.java:52)
at org.jupiter.transport.netty.handler.connector.ConnectorHandler.channelRead(ConnectorHandler.java:52)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at org.jupiter.transport.netty.handler.IdleStateChecker.channelRead(IdleStateChecker.java:186)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:141)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:451)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)

@fengjiachun
Copy link
Owner

序列化框架的问题 kryo/protostuff都有这个问题, protostuff的ArraySchemas.java类对pojos以及基本类型都有支持, 唯独Object[] 不支持包含null元素
目前思路是在序列化框架上层workaround, 这样就同时解决kryo/protostuff的问题, 我要先测下改动有没有性能损失, 晚点提交下代码

@fengjiachun
Copy link
Owner

fengjiachun commented Sep 11, 2018

@chywwq 已经workaround, 请先下载最新代码, 需要设置一个参数(默认为false):
SystemPropertyUtil.setProperty("jupiter.message.args.allow_null_array_arg", "true")
或者 system property: -Djupiter.message.args.allow_null_array_arg=true
参考的protostuff作者提供的思路: protostuff/protostuff#165

@chywwq
Copy link
Author

chywwq commented Sep 11, 2018

1、需要在服务端和客户端同时加上该参数
2、处理有问题,参数都是null

arg1:null
arg2:null
arg3:null

@fengjiachun
Copy link
Owner

@chywwq 1. 是的, 两端都要设置, 默认是不支持的 2. 请详细说下什么问题, 最好给下你的测试条件, 我没测出来

@fengjiachun
Copy link
Owner

@chywwq 我补充了测试用例, 你可以帮忙看下什么条件没覆盖, 没出现你说的情况2

@fengjiachun
Copy link
Owner

fengjiachun commented Sep 17, 2018

@fengjiachun
Copy link
Owner

关于protostuff的bug, 我提交了一个PR: protostuff/protostuff#253
待protostuff新版本发布, jupiter会跟进更新版本并移除现有的workaround的相关代码

@fengjiachun
Copy link
Owner

fengjiachun commented Sep 21, 2018

简单总结下, 这个issue其实包含两个问题:

  1. 对于rpc调用, 有几个重要参数是必须参与序列化/反序列化的(接口名, 方法名, 方法调用的参数值列表), 其中参数值列表肯定是一个Object[],
    对于Object[]中包含null元素的的场景, protostuff和kryo是不支持的, 并且我了解到protostuff作者也不认为这是一个bug, 不会修复, 但是他提过一个
    workaround的办法, 就是用一个标记来标记null元素, jupiter采用一个枚举(NullArg.NULL) 标记参数值列表中的null元素, 反序列化时再把枚举替换回null,
    这个解决方式是在序列化/反序列化层之上, 自然也就解决了kryo/protostuff共同的问题, 不过需要配置一个参数 -Djupiter.message.args.allow_null_array_arg=true

  2. 第二个问题是 在Object[]中还包含一个数组, 这个数组中包含null元素, 比如 Object[] { obj1, obj2, new String[] { "str1", null, "str3"} },
    这个情况protostuff同样无法序列化/反序列化, 这是个bug, 我已经提交PR, 现在已被merge到protostuff主干, 在protostuff发布新版本之前, 我临时的解决方案是在项目中覆盖
    java.io.protostuff.runtime.IdStrategy, 类加载器会先加载jupiter项目中的IdStrategy类

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants