Skip to content

方法返回InputStream时expected map/object at java.lang.String异常 #75

@mcck

Description

@mcck

dubbo版本:3.2.14
hessian版本:3.2.13

示例代码

  • NatureReserveSliceService.java
public InputStream test() {
    System.out.println("被调用了 返回 InputStream");
    return new ByteArrayInputStream(new byte[]{21});
}
  • 调用
InputStream test = sliceService.test();
  • 错误信息
Caused by: org.apache.dubbo.remoting.RemotingException: com.alibaba.com.caucho.hessian.io.HessianProtocolException: expected map/object at java.lang.String
com.alibaba.com.caucho.hessian.io.HessianProtocolException: expected map/object at java.lang.String
	at com.alibaba.com.caucho.hessian.io.AbstractDeserializer.error(AbstractDeserializer.java:131)
	at com.alibaba.com.caucho.hessian.io.AbstractMapDeserializer.readObject(AbstractMapDeserializer.java:70)
	at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2297)
	at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2104)
	at org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput.readObject(Hessian2ObjectInput.java:117)
	at org.apache.dubbo.common.serialize.ObjectInput.readAttachments(ObjectInput.java:85)
	at org.apache.dubbo.common.serialize.DefaultSerializationExceptionWrapper$ProxyObjectInput.readAttachments(DefaultSerializationExceptionWrapper.java:197)
	at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.handleAttachment(DecodeableRpcResult.java:194)
	at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:111)
	at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:153)
	at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:61)
	at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:49)
	at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:64)
	at org.apache.dubbo.common.threadpool.ThreadlessExecutor$RunnableWrapper.run(ThreadlessExecutor.java:151)
	at org.apache.dubbo.common.threadpool.ThreadlessExecutor.waitAndDrain(ThreadlessExecutor.java:77)
	at org.apache.dubbo.rpc.AsyncRpcResult.get(AsyncRpcResult.java:219)
	at org.apache.dubbo.rpc.protocol.AbstractInvoker.waitForResultIfSync(AbstractInvoker.java:292)
	at org.apache.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:194)
	at org.apache.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:71)
	at org.apache.dubbo.rpc.filter.RpcExceptionFilter.invoke(RpcExceptionFilter.java:40)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
	at com.hdi.bhd.dubbo.filter.CallServiceFilter.invoke(CallServiceFilter.java:35)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CallbackRegistrationInvoker.invoke(FilterChainBuilder.java:197)
	at org.apache.dubbo.rpc.protocol.ReferenceCountInvokerWrapper.invoke(ReferenceCountInvokerWrapper.java:106)
	at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invokeWithContext(AbstractClusterInvoker.java:412)
	at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:82)
	at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:366)
	at org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter.invoke(RouterSnapshotFilter.java:46)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
	at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:108)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
	at org.apache.dubbo.rpc.cluster.filter.support.MetricsClusterFilter.invoke(MetricsClusterFilter.java:57)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
	at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:52)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
	at org.apache.dubbo.rpc.cluster.filter.support.ObservationSenderFilter.invoke(ObservationSenderFilter.java:62)
	at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:349)
....

经过debug后大致确定问题

  1. 代码执行到 org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream) 109行
            case DubboCodec.RESPONSE_VALUE_WITH_ATTACHMENTS:
                handleValue(in); // 读取返回值,进入次方法
                handleAttachment(in);  
                break;
  1. 执行到com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.lang.Class, java.lang.Class<?>...) 2297 行 获取InputStreamDeserializer返序列化示例,并调用readObject方法
Object value = findSerializerFactory().getDeserializer(expectedClass).readObject(this);
  1. InputStreamDeserializer.readObject调用了in.readInputStream()
  2. com.alibaba.com.caucho.hessian.io.Hessian2Input#readInputStream方法中读取到的tag值为65,执行case 'b': ,问题可能就在这,在这里只是读取了数据长度,并没有读取数据就结束了
case 'b': //maybe it's a mistype of BC_BINARY_CHUNK
    _isLastChunk = tag == 'B';
    _chunkLength = (read() << 8) + read(); // 获取数据长度
    break; // 结束 switch
  1. 代码执行到com.alibaba.com.caucho.hessian.io.Hessian2Input#readInputStream方法3424行时只返回了ReadInputStream实例,也没用读取数据就返回了
  2. 执行到org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream) 111行handleAttachment方法时,因为前面的数据没有读取,参数in中的_offset值没有变化,所以导致handleAttachment方法读取失败。
  • 以上是debug得到的信息,个人觉得传输InputStream时应该把数据放到末尾,先读取Attachment再读取InputStream,因为可能InputStream比较大

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions