Telnet调试Dubbo接口,参数里含有枚举类的执行异常解决

正常如果由于一些网络权限限制导致的无法远程调用dubbo进行测试的时候,可以直接在dubbo服务所在的机器上通过telnet来进行一个invoke的调用执行,今天在测试一个接口的时候,参数传入了一个枚举,结果报了一个错误

如果想要重现,可以直接创建一个dubbo工程,然后进行telnet调用,dubbo工程可参考:http://lihuia.com/dubbo%e8%9e%8d%e5%90%88nacos%e6%b3%a8%e5%86%8c%e4%b8%ad%e5%bf%83/

dubbo服务启动之后,invoke报错

lihui@2019 telnet 127.0.0.1 12345
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

dubbo>ls
PROVIDER:
com.lihuia.DemoService

dubbo>invoke com.lihuia.DemoService.sayHello({"class":"com.lihuia.StudentEnum", "student":"LUCY"})
Failed to invoke method sayHello, cause: java.lang.IllegalArgumentException: Cannot reflectively create enum objects
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at org.apache.dubbo.common.utils.PojoUtils.newInstance(PojoUtils.java:547)
	at org.apache.dubbo.common.utils.PojoUtils.realize0(PojoUtils.java:446)
	at org.apache.dubbo.common.utils.PojoUtils.realize(PojoUtils.java:205)
	at org.apache.dubbo.common.utils.PojoUtils.realize(PojoUtils.java:95)
	at org.apache.dubbo.rpc.protocol.dubbo.telnet.InvokeTelnetHandler.telnet(InvokeTelnetHandler.java:125)
	at org.apache.dubbo.remoting.telnet.support.TelnetHandlerAdapter.telnet(TelnetHandlerAdapter.java:59)
	at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:205)
	at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:51)
	at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.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)

dubbo>

本来想放弃的,随手看了下堆栈,似乎找到了些线索

先看看InvokeTelnetHandler类的telnet方法,这里具体还列出来了invoke用法

public class InvokeTelnetHandler implements TelnetHandler {

public static final String INVOKE_MESSAGE_KEY = "telnet.invoke.method.message";
public static final String INVOKE_METHOD_LIST_KEY = "telnet.invoke.method.list";
public static final String INVOKE_METHOD_PROVIDER_KEY = "telnet.invoke.method.provider";

@Override
@SuppressWarnings("unchecked")
public String telnet(Channel channel, String message) {
if (StringUtils.isEmpty(message)) {
return "Please input method name, eg: \r\ninvoke xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})\r\n" +
"invoke XxxService.xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})\r\n" +
"invoke com.xxx.XxxService.xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})";
}

可以打一个断点,调试得到的异常是这里抛出来的

NewImage

紧接着具体看下realize里面的内容

包org.apache.dubbo.common.utils的PojoUtils类里

public static Object[] realize(Object[] objs, Class<?>[] types, Type[] gtypes) {
if (objs.length != types.length || objs.length != gtypes.length) {
throw new IllegalArgumentException("args.length != types.length");
}
Object[] dests = new Object[objs.length];
for (int i = 0; i < objs.length; i++) {
dests[i] = realize(objs[i], types[i], gtypes[i]);
}
return dests;
}

执行到了for循环里面的realize

同样还是在这个类里

public static Object realize(Object pojo, Class<?> type, Type genericType) {
return realize0(pojo, type, genericType, new IdentityHashMap<Object, Object>());
}

具体realize0这个方法比较长,就不贴了,具体有下面一段

NewImage

invoke执行的sayHello方法,sayHello({“class”:”com.lihuia.StudentEnum”, “student”:”LUCY”})的参数是一个map,第一个传入了参数的class类型,而第二个的键并不是参数变量名,而是写死了一个name,抱着半信半疑的态度试了一下,居然还真正确了

dubbo>invoke com.lihuia.DemoService.sayHello({"class":"com.lihuia.StudentEnum", "name":"LUCY"})
Use default service com.lihuia.DemoService.
result: "Hello! My Name is LUCY"
elapsed: 8 ms.
dubbo>
dubbo>

这里的dubbo版本是2.7.3,第一次进dubbo的实现代码,还好这个问题相对比较直接

发表回复