From e4acdf72f644c0f4f1adad0257615567ef2bb649 Mon Sep 17 00:00:00 2001 From: zhaixiaoxiang Date: Tue, 18 Dec 2018 10:59:53 +0800 Subject: [PATCH] [Dubbo-619] Fix consumer will generate wrong stackTrace (#2956) * [Dubbo-619] Fix consumer will generate wrong stackTrace when provider throws exception with empty stackTrace * add license --- .../java/org/apache/dubbo/rpc/RpcResult.java | 19 +++++ .../org/apache/dubbo/rpc/RpcResultTest.java | 77 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcResultTest.java diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java index 3f27420021d..dfec74c4fff 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java @@ -16,6 +16,8 @@ */ package org.apache.dubbo.rpc; +import java.lang.reflect.Field; + /** * RPC Result. * @@ -39,6 +41,23 @@ public RpcResult(Throwable exception) { @Override public Object recreate() throws Throwable { if (exception != null) { + // fix issue#619 + try { + // get Throwable class + Class clazz = exception.getClass(); + while (!clazz.getName().equals(Throwable.class.getName())) { + clazz = clazz.getSuperclass(); + } + // get stackTrace value + Field stackTraceField = clazz.getDeclaredField("stackTrace"); + stackTraceField.setAccessible(true); + Object stackTrace = stackTraceField.get(exception); + if (stackTrace == null) { + exception.setStackTrace(new StackTraceElement[0]); + } + } catch (Exception e) { + // ignore + } throw exception; } return result; diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcResultTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcResultTest.java new file mode 100644 index 00000000000..8083a604ea0 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcResultTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc; + + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.fail; + +public class RpcResultTest { + @Test + public void testRecreateWithNormalException() { + NullPointerException npe = new NullPointerException(); + RpcResult rpcResult = new RpcResult(npe); + try { + rpcResult.recreate(); + fail(); + } catch (Throwable throwable) { + StackTraceElement[] stackTrace = throwable.getStackTrace(); + Assert.assertNotNull(stackTrace); + Assert.assertTrue(stackTrace.length > 1); + } + } + + /** + * please run this test in Run mode + */ + @Test + public void testRecreateWithEmptyStackTraceException() { + // begin to construct a NullPointerException with empty stackTrace + Throwable throwable = null; + Long begin = System.currentTimeMillis(); + while (System.currentTimeMillis() - begin < 60000) { + try { + ((Object) null).getClass(); + } catch (Exception e) { + if (e.getStackTrace().length == 0) { + throwable = e; + break; + } + } + } + /** + * may be there is -XX:-OmitStackTraceInFastThrow or run in Debug mode + */ + if (throwable == null) { + System.out.println("###testRecreateWithEmptyStackTraceException fail to construct NPE"); + return; + } + // end construct a NullPointerException with empty stackTrace + + RpcResult rpcResult = new RpcResult(throwable); + try { + rpcResult.recreate(); + fail(); + } catch (Throwable t) { + StackTraceElement[] stackTrace = t.getStackTrace(); + Assert.assertNotNull(stackTrace); + Assert.assertTrue(stackTrace.length == 0); + } + } +}