diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java index 47f11f5b086..59733dcaaac 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java @@ -60,6 +60,19 @@ private static boolean isMatch(Class[] types, List args) { for (int i = 0; i < types.length; i++) { Class type = types[i]; Object arg = args.get(i); + + if (arg == null) { + // if the type is primitive, the method to invoke will cause NullPointerException definitely + // so we can offer a specified error message to the invoker in advance and avoid unnecessary invoking + if (type.isPrimitive()) { + throw new NullPointerException(String.format( + "The type of No.%d parameter is primitive(%s), but the value passed is null.", i + 1, type.getName())); + } + + // if the type is not primitive, we choose to believe what the invoker want is a null value + continue; + } + if (ReflectUtils.isPrimitive(arg.getClass())) { if (!ReflectUtils.isPrimitive(type)) { return false; diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoService.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoService.java index 182a1e86975..93c48f53206 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoService.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoService.java @@ -57,4 +57,6 @@ public interface DemoService { NonSerialized returnNonSerialized(); + long add(int a, long b); + } \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoServiceImpl.java index 93c97646751..50d98e62924 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/support/DemoServiceImpl.java @@ -103,4 +103,9 @@ public void nonSerializedParameter(NonSerialized ns) { public NonSerialized returnNonSerialized() { return new NonSerialized(); } + + public long add(int a, long b) { + return a + b; + } + } \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokerTelnetHandlerTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokerTelnetHandlerTest.java index 04092d09628..9dfc20f87ac 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokerTelnetHandlerTest.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/com/alibaba/dubbo/rpc/protocol/dubbo/telnet/InvokerTelnetHandlerTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -68,6 +69,41 @@ public void testInvokeDefaultSService() throws RemotingException { assertTrue(result.contains("Use default service com.alibaba.dubbo.rpc.protocol.dubbo.support.DemoService.\r\n\"ok\"\r\n")); } + @SuppressWarnings("unchecked") + @Test + public void testInvokeByPassingNullValue() throws RemotingException { + mockInvoker = mock(Invoker.class); + given(mockInvoker.getInterface()).willReturn(DemoService.class); + given(mockInvoker.getUrl()).willReturn(URL.valueOf("dubbo://127.0.0.1:20883/demo")); + given(mockInvoker.invoke(any(Invocation.class))).willReturn(new RpcResult("ok")); + mockChannel = mock(Channel.class); + given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService"); + given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555")); + given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20883")); + DubboProtocol.getDubboProtocol().export(mockInvoker); + // pass null value to parameter of primitive type + try { + invoke.telnet(mockChannel, "DemoService.add(null, 2)"); + fail("It should cause a NullPointerException by the above code."); + } catch (NullPointerException ex) { + String message = ex.getMessage(); + assertEquals("The type of No.1 parameter is primitive(int), but the value passed is null.", message); + } + try { + invoke.telnet(mockChannel, "DemoService.add(1, null)"); + fail("It should cause a NullPointerException by the above code."); + } catch (NullPointerException ex) { + String message = ex.getMessage(); + assertEquals("The type of No.2 parameter is primitive(long), but the value passed is null.", message); + } + // pass null value to parameter of object type + try { + invoke.telnet(mockChannel, "DemoService.sayHello(null)"); + } catch (NullPointerException ex) { + fail("It shouldn't cause a NullPointerException by the above code."); + } + } + @SuppressWarnings("unchecked") @Test public void testInvokeAutoFindMethod() throws RemotingException {