From ad958961c978676a543124b50e7ee8d1cb78034c Mon Sep 17 00:00:00 2001 From: walker <15108309406@yeah.net> Date: Thu, 14 May 2020 16:40:02 +0800 Subject: [PATCH 01/16] fix tars define recursive --- .../com/qq/tars/protocol/util/TarsHelper.java | 6 +- .../server/testapp/TestRecursive.java | 90 +++++++++++++++++++ .../com/tencent/tars/TestTarsRecursive.java | 27 ++++++ .../server/testapp/TestRecursive.java | 89 ++++++++++++++++++ .../src/main/resources/TestRecursive.tars | 24 +++++ 5 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 core/src/test/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java create mode 100644 core/src/test/java/com/tencent/tars/TestTarsRecursive.java create mode 100644 examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java create mode 100644 examples/quickstart-server/src/main/resources/TestRecursive.tars diff --git a/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java b/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java index d0b3d8c0..1f3d5f99 100644 --- a/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java +++ b/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java @@ -487,9 +487,9 @@ public static boolean isRoutekey(Annotation[] annotations) { public static boolean isStruct(Class clazz) { boolean isStruct = clazz.isAnnotationPresent(TarsStruct.class); - if (isStruct) { - getStructInfo(clazz); - } +// if (isStruct) { +// getStructInfo(clazz); +// } return isStruct; } diff --git a/core/src/test/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java b/core/src/test/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java new file mode 100644 index 00000000..48a7331a --- /dev/null +++ b/core/src/test/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java @@ -0,0 +1,90 @@ +// ********************************************************************** +// This file was generated by a TARS parser! +// TARS version 1.0.1. +// ********************************************************************** + +package com.qq.tars.quickstart.server.testapp; + +import com.qq.tars.protocol.tars.TarsInputStream; +import com.qq.tars.protocol.tars.TarsOutputStream; +import com.qq.tars.protocol.tars.annotation.TarsStruct; +import com.qq.tars.protocol.tars.annotation.TarsStructProperty; +import com.qq.tars.protocol.util.TarsUtil; + +@TarsStruct +public class TestRecursive { + + @TarsStructProperty(order = 0, isRequire = false) + public int value = 0; + @TarsStructProperty(order = 1, isRequire = false) + public TestRecursive testRecursive = null; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public TestRecursive getTestRecursive() { + return testRecursive; + } + + public void setTestRecursive(TestRecursive testRecursive) { + this.testRecursive = testRecursive; + } + + public TestRecursive() { + } + + public TestRecursive(int value, TestRecursive testRecursive) { + this.value = value; + this.testRecursive = testRecursive; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + TarsUtil.hashCode(value); + result = prime * result + TarsUtil.hashCode(testRecursive); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof TestRecursive)) { + return false; + } + TestRecursive other = (TestRecursive) obj; + return ( + TarsUtil.equals(value, other.value) && + TarsUtil.equals(testRecursive, other.testRecursive) + ); + } + + public void writeTo(TarsOutputStream _os) { + _os.write(value, 0); + if (null != testRecursive) { + _os.write(testRecursive, 1); + } + } + + static TestRecursive cache_testRecursive; + static { + cache_testRecursive = new TestRecursive(); + } + + public void readFrom(TarsInputStream _is) { + this.value = _is.read(value, 0, false); + this.testRecursive = (TestRecursive) _is.read(cache_testRecursive, 1, false); + } + +} diff --git a/core/src/test/java/com/tencent/tars/TestTarsRecursive.java b/core/src/test/java/com/tencent/tars/TestTarsRecursive.java new file mode 100644 index 00000000..a2b4dba0 --- /dev/null +++ b/core/src/test/java/com/tencent/tars/TestTarsRecursive.java @@ -0,0 +1,27 @@ +package com.tencent.tars; + +import com.qq.tars.protocol.tars.TarsOutputStream; +import com.qq.tars.quickstart.server.testapp.TestRecursive; +import org.junit.Test; +import java.util.ArrayList; +import java.util.List; + +public class TestTarsRecursive { + + @Test + public void testRecursiveReproduce() { + + TestRecursive testRecursive = new TestRecursive(); + testRecursive.value = 1; + TestRecursive testRecursive2 = new TestRecursive(); + testRecursive2.value =2; + testRecursive.testRecursive = testRecursive2; +// System.out.println(testRecursive.testRecursive.getValue()); + + TarsOutputStream tafOutputStream = new TarsOutputStream(); + System.out.println("begin to write."); + testRecursive.writeTo(tafOutputStream); + System.out.println("write end."); + + } +} diff --git a/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java b/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java new file mode 100644 index 00000000..8124a828 --- /dev/null +++ b/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/TestRecursive.java @@ -0,0 +1,89 @@ +// ********************************************************************** +// This file was generated by a TARS parser! +// TARS version 1.0.1. +// ********************************************************************** + +package com.qq.tars.quickstart.server.testapp; + +import com.qq.tars.protocol.util.*; +import com.qq.tars.protocol.annotation.*; +import com.qq.tars.protocol.tars.*; +import com.qq.tars.protocol.tars.annotation.*; + +@TarsStruct +public class TestRecursive { + + @TarsStructProperty(order = 0, isRequire = false) + public int value = 0; + @TarsStructProperty(order = 1, isRequire = false) + public TestRecursive testRecursive = null; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public TestRecursive getTestRecursive() { + return testRecursive; + } + + public void setTestRecursive(TestRecursive testRecursive) { + this.testRecursive = testRecursive; + } + + public TestRecursive() { + } + + public TestRecursive(int value, TestRecursive testRecursive) { + this.value = value; + this.testRecursive = testRecursive; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + TarsUtil.hashCode(value); + result = prime * result + TarsUtil.hashCode(testRecursive); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof TestRecursive)) { + return false; + } + TestRecursive other = (TestRecursive) obj; + return ( + TarsUtil.equals(value, other.value) && + TarsUtil.equals(testRecursive, other.testRecursive) + ); + } + + public void writeTo(TarsOutputStream _os) { + _os.write(value, 0); + if (null != testRecursive) { + _os.write(testRecursive, 1); + } + } + + static TestRecursive cache_testRecursive; + static { + cache_testRecursive = new TestRecursive(); + } + + public void readFrom(TarsInputStream _is) { + this.value = _is.read(value, 0, false); + this.testRecursive = (TestRecursive) _is.read(cache_testRecursive, 1, false); + } + +} diff --git a/examples/quickstart-server/src/main/resources/TestRecursive.tars b/examples/quickstart-server/src/main/resources/TestRecursive.tars new file mode 100644 index 00000000..a89729c1 --- /dev/null +++ b/examples/quickstart-server/src/main/resources/TestRecursive.tars @@ -0,0 +1,24 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +module TestApp +{ + struct TestRecursive + { + 0 optional int value; + 1 optional TestRecursive testRecursive; + }; +}; \ No newline at end of file From 4eb9f0145149bd8cab8635aeb36ef327dbe8c78c Mon Sep 17 00:00:00 2001 From: Timmy Date: Fri, 15 May 2020 11:57:20 +0800 Subject: [PATCH 02/16] [issue] setRefreshInterval and reportInterval No effect --- core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java b/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java index eccb6a89..eff5bd4e 100644 --- a/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java +++ b/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java @@ -55,6 +55,8 @@ public ObjectProxy getObjectProxy(Class api, String objName, String se servantProxyConfig.setModuleName(communicator.getCommunicatorConfig().getModuleName(), communicator.getCommunicatorConfig().isEnableSet(), communicator.getCommunicatorConfig().getSetDivision()); servantProxyConfig.setLocator(communicator.getCommunicatorConfig().getLocator()); addSetDivisionInfo(servantProxyConfig, setDivision); + servantProxyConfig.setRefreshInterval(communicator.getCommunicatorConfig().getRefreshEndpointInterval()); + servantProxyConfig.setReportInterval(communicator.getCommunicatorConfig().getReportInterval()); } updateServantEndpoints(servantProxyConfig); @@ -118,6 +120,7 @@ private ServantProxyConfig createServantProxyConfig(String objName, String setDi cfg.setCharsetName(communicatorConfig.getCharsetName()); cfg.setConnections(communicatorConfig.getConnections()); cfg.setRefreshInterval(communicatorConfig.getRefreshEndpointInterval()); + cfg.setReportInterval(communicator.getCommunicatorConfig().getReportInterval()); return cfg; } From b1bff89a48d867c550a16769bb1b01a3c33a257b Mon Sep 17 00:00:00 2001 From: Yuki Date: Thu, 21 May 2020 11:55:32 +0800 Subject: [PATCH 03/16] update printHead Tars version and add CompletableFuture interface with context --- .../qq/tars/maven/gensrc/Tars2JavaMojo.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java index 18b7df4b..b8c9dce1 100644 --- a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java +++ b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java @@ -164,7 +164,7 @@ private void genJava(String nsName, List namespaces, Map promise_" + op.operationName() + "(" + operationParams(null, op.paramList(), null, true, nsMap) + ");"); - - // 3 print sync method with context + // 2 print sync method with context out.println(getDoc(op, "\t")); out.println("\t " + type(op.retType(), nsMap) + " " + op.operationName() + "(" + operationParams(null, op.paramList(), Arrays.asList("@TarsContext java.util.Map ctx"), true, nsMap) + ");"); - // 4 print async method without context + // 3 print async method without context out.println(getDoc(op, "\t")); out.println("\t void async_" + op.operationName() + "(" + operationParams(Arrays.asList("@TarsCallback " + prxClass + "Callback callback"), op.paramList(), null, false, nsMap) + ");"); - // 5 print async method with context + // 4 print async method with context out.println(getDoc(op, "\t")); out.println("\t void async_" + op.operationName() + "(" + operationParams(Arrays.asList("@TarsCallback " + prxClass + "Callback callback"), op.paramList(), Arrays.asList("@TarsContext java.util.Map ctx"), false, nsMap) + ");"); + + // 5 print promise method without context + out.println(getDoc(op, "\t")); + out.println("\t CompletableFuture<" + type(op.retType(), true, nsMap) + "> promise_" + op.operationName() + "(" + operationParams(null, op.paramList(), null, true, nsMap) + ");"); + + // 6 print promise method with context + out.println(getDoc(op, "\t")); + out.println("\t CompletableFuture<" + type(op.retType(), true, nsMap) + "> promise_" + op.operationName() + "(" + operationParams(null, op.paramList(), Arrays.asList("@TarsContext java.util.Map ctx"), true, nsMap) + ");"); } out.println("}"); From 98579592c4e540eea8f571f95207d8a3bfaaa2d8 Mon Sep 17 00:00:00 2001 From: Yuki Date: Mon, 25 May 2020 11:08:57 +0800 Subject: [PATCH 04/16] update tars_java_user_guide --- docs-en/tars_java_user_guide.md | 67 ++++++++++++++++++++++++++++++--- docs/tars_java_user_guide.md | 57 ++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/docs-en/tars_java_user_guide.md b/docs-en/tars_java_user_guide.md index d4a08e5b..3c774547 100644 --- a/docs-en/tars_java_user_guide.md +++ b/docs-en/tars_java_user_guide.md @@ -309,11 +309,11 @@ Asynchronous nesting represents the following: Normally, after receiving the request, B needs to return to A after the interface is processed, so it cannot be implemented if B also initiates an asynchronous request to C in the interface Therefore, it is necessary to declare startup asynchronism in the implementation interface method to achieve asynchronous calls across services. ​ - //Declarations start asynchronous context - AsyncContext context = AsyncContext.startAsync(); - //Interface implementation - ... - +​ //Declarations start asynchronous context +​ AsyncContext context = AsyncContext.startAsync(); +​ //Interface implementation +​ ... +​ //Back packet after asynchronous processing context.writeResult(...); @@ -499,6 +499,32 @@ Note: > * When the server returns, the callback_hello of HelloPrxCallback will be responded. > * If the call returns an exception or timeout, the callback_exception will be called, and the value of RET is defined as follows. +#### Promise invoke + +The asynchronous promise call is a new feature of Tars v1.7.0. This method returns a CompletableFuture object. CompletableFuture is a newly added class in jdk1.8. It implements the Future \ and CompletionStage \ interfaces and provides very powerful asynchronous programming functions. Before jdk1.8, we mainly used Future or registered callback function to complete asynchronous programming. However, these two methods have certain defects. When Future calls get() to get the result, if the operation is not completed, it will wait all the time, which may cause a waste of CPU time. Furthermore, Future cannot complete chained calls, and cannot perform further operations on the results obtained from the previous Future. For the callback method, with the continuous nesting of callback functions, it will cause the phenomenon of callback pyramid. Therefore, CompletableFuture was introduced in Tars v1.7.0, which can perform a series of subsequent operations in a callback manner by registering triggers. + +The API of CompletabileFuture generally has two forms: the one with Async suffix and the one without Async suffix. The method without the Async suffix will be executed by the current calling thread, and the method with the Async suffix is divided into two cases. If Executor is passed in the parameter, a thread will be obtained from the Executor to execute the task. Otherwise, a thread obtained from the global ForkJoinPool.commonPool () will perform these tasks. + +CompletableFuture provides processing operations when the calculation result is completed, and all return a CompletableFuture object, so you can perform chained calls. Common operations are as follows: + +- thenApply:The parameter is the result of the previous CompletableFuture, and it returns the CompletableFuture object holding the new result +- thenRun:No parameters, returns a CompletableFuture object with no results +- thenAccept:The parameter is the result of the last CompletableFuture, and it returns a CompletableFuture object with no result +- handle:The parameters are the result of the last CompletableFuture (null when exception occurs) and throwable (null when operation completes normally), and it returns a CompletableFuture object holding the new result +- whenComplete:The parameters are the result of the last CompletableFuture (null when exception occurs) and throwable (null when operation completes normally) and it returns the same result as the previous CompletableFuture + +A simple example is as follows: + +```java +public static void main(String[] args) throws Exception { + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + return 10; + }); + CompletableFuture result = future.thenApply(i -> i + 10).thenApply(i-> String.valueOf(i)); + System.out.println(result.get()); // 20 + } +``` + #### Set mode invoke At present, the framework has already supported the deployment of business in set mode. After set deployment, the calls between businesses are transparent to the business deveploment. But because some services have special needs, after deploying set, the client can specify the set name to invoke the server, so the framework increases the function of the client to specify the set name to invoke the service on the basis of the set deployment. @@ -662,6 +688,37 @@ Illustration: > - When the dyed log is opened, the parameter passed is recommended to fill in the service name. If it is null, the default name is default. > - The log level and log type of the dyed log are the same as the original log. If the original log is only local, the dyed log is only local, and the original log will be remote to play the long distance dyed log. +Logback is used as the logging system in the new version of TarsJava, so MDC can be used to dye the logs. MDC is a technology provided by Logback to record logs in multiple threads. It holds a ThreadLocal object inside which stores a Map, so users can add key-value pairs to it as needed. By implementing Filter and using MDC, dyeing of logs can be achieved: + +```java +public class MyFilter implements Filter { + private static final String TRACE_ID = "traceId"; + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + ... + boolean success = putMDC(...); + ... + try { + chain.doFilter(request, response); + } finally { + if(success) { + MDC.remove(TRACE_ID); + } + } + } + + private boolean putMDC(...) { + if (...){ + String traceId = ... + MDC.put(TRACE_ID, traceId); + return true; + } + return false; + } +``` + + + - Passive staining: > - When the requesting server presupposes the coloring condition, if the received request satisfies the dyeing condition, the server framework will automatically open the dye switch. diff --git a/docs/tars_java_user_guide.md b/docs/tars_java_user_guide.md index 335c05dd..591f9930 100644 --- a/docs/tars_java_user_guide.md +++ b/docs/tars_java_user_guide.md @@ -497,6 +497,32 @@ prx.async_hello(new HelloPrxCallback() { > * 当接收到服务端返回时,HelloPrxCallback的callback_hello会被响应。 > * 如果调用返回异常或超时,则callback_exception会被调用,ret的值定义如下: +#### promise调用 + +异步的promise调用方式是Tars v1.7.0新增的功能,该方法返回了一个CompletableFuture对象。CompletableFuture是jdk1.8中新加入的类,它实现了Future\, CompletionStage\两个接口,提供了十分强大的异步编程功能。在jdk1.8之前主要采用Future或注册CallBack函数来完成异步编程,这两种方式均存在一定的缺陷。Future在调用get方法获取结果时,若操作尚未完成会一直进行等待,此时可能造成CPU时间的浪费。并且Future无法组合完成链式调用,不能为上一个Future获得的结果执行更进一步的操作。而CallBack方式随着回调函数的不断嵌套,则会造成回调金字塔的现象。因此,在Tars v1.7.0版本中引入了CompletableFuture,可以通过注册触发器以回调的方式执行一系列的后续操作。 + +CompletableFuture的API一般会有带Async后缀和不带Async后缀两种形式,不带Async后缀的方法会由当前的调用线程来执行任务,而带Async后缀的方法则分为两种情况,若在参数中传入了Executor,则会从传入的线程池获取一个线程去执行任务,否则从全局的 ForkJoinPool.commonPool()中获取一个线程中执行这些任务。 + +CompletableFuture提供了对计算结果完成时的处理操作,并都会返回一个CompletableFuture对象,因此可以执行链式调用,常见的操作有: + +- thenApply:参数为上一个CompletableFuture的结果,返回持有新结果的CompletableFuture对象 +- thenRun:无参数,返回无结果的CompletableFuture对象 +- thenAccept:参数为上一个CompletableFuture的结果,返回无结果的CompletableFuture对象 +- handle:参数为上一个CompletableFuture的结果(异常完成时为空)和异常(正常完成时为空),返回持有新结果的CompletableFuture对象 +- whenComplete:参数为上一个CompletableFuture的结果(异常完成时为空)和异常(正常完成时为空),返回和上一个CompletableFuture相同的结果 + +一个简单的结果转换示例如下: + +```Java +public static void main(String[] args) throws Exception { + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + return 10; + }); + CompletableFuture result = future.thenApply(i -> i + 10).thenApply(i-> String.valueOf(i)); + System.out.println(result.get()); // 20 + } +``` + #### set方式调用 目前框架已经支持业务按set方式进行部署,按set部署之后,各个业务之间的调用对开业务发来说是透明的。但是由于有些业务有特殊需求,需要在按set部署之后,客户端可以指定set名称来调用服务端,因此框架则按set部署的基础上增加了客户端可以指定set名称去调用业务服务的功能。 @@ -661,6 +687,37 @@ DyeingSwitch.closeActiveDyeing(); //主动关闭染色开关接口 > - 开启染色日志时传递的参数推荐填写服务名,如果填写为null则默认名称为default; > - 染色日志的日志级别和日志类型与原本日志相同,如果原本日志只打本地,那么染色日志也只打本地,原本日志要打远程染色日志才会打远程; +在新版的TarsJava中使用了Logback作为日志系统,因此可以使用MDC来实现对日志的染色。MDC是Logback提供的在多线程中记录日志的一种技术,它的内部持有一个ThreadLocal对象,其中存储了一个Map,因此用户可以根据需要向其中添加键值对。通过实现Filter,配合MDC可以实现对日志的染色: + +```java +public class MyFilter implements Filter { + private static final String TRACE_ID = "traceId"; + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + ... + boolean success = putMDC(...); + ... + try { + chain.doFilter(request, response); + } finally { + if(success) { + MDC.remove(TRACE_ID); + } + } + } + + private boolean putMDC(...) { + if (...){ + String traceId = ... + MDC.put(TRACE_ID, traceId); + return true; + } + return false; + } +``` + + + - 被动染色: > - 在请求的服务端预设预先设定染色条件,如果接收到的请求满足染色条件,那么服务端框架层会自动打开染色开关; From b107e67d1bb403f5d7105d3c4364f9d54908839a Mon Sep 17 00:00:00 2001 From: Yuki Date: Mon, 25 May 2020 22:08:45 +0800 Subject: [PATCH 05/16] remove CompletableFuture usage --- docs-en/tars_java_user_guide.md | 24 ++---------------------- docs/tars_java_user_guide.md | 20 -------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/docs-en/tars_java_user_guide.md b/docs-en/tars_java_user_guide.md index 3c774547..7a25d6b4 100644 --- a/docs-en/tars_java_user_guide.md +++ b/docs-en/tars_java_user_guide.md @@ -314,8 +314,8 @@ Normally, after receiving the request, B needs to return to A after the interfac ​ //Interface implementation ​ ... ​ - //Back packet after asynchronous processing - context.writeResult(...); +​ //Back packet after asynchronous processing +​ context.writeResult(...); ## Client development @@ -505,26 +505,6 @@ The asynchronous promise call is a new feature of Tars v1.7.0. This method retur The API of CompletabileFuture generally has two forms: the one with Async suffix and the one without Async suffix. The method without the Async suffix will be executed by the current calling thread, and the method with the Async suffix is divided into two cases. If Executor is passed in the parameter, a thread will be obtained from the Executor to execute the task. Otherwise, a thread obtained from the global ForkJoinPool.commonPool () will perform these tasks. -CompletableFuture provides processing operations when the calculation result is completed, and all return a CompletableFuture object, so you can perform chained calls. Common operations are as follows: - -- thenApply:The parameter is the result of the previous CompletableFuture, and it returns the CompletableFuture object holding the new result -- thenRun:No parameters, returns a CompletableFuture object with no results -- thenAccept:The parameter is the result of the last CompletableFuture, and it returns a CompletableFuture object with no result -- handle:The parameters are the result of the last CompletableFuture (null when exception occurs) and throwable (null when operation completes normally), and it returns a CompletableFuture object holding the new result -- whenComplete:The parameters are the result of the last CompletableFuture (null when exception occurs) and throwable (null when operation completes normally) and it returns the same result as the previous CompletableFuture - -A simple example is as follows: - -```java -public static void main(String[] args) throws Exception { - CompletableFuture future = CompletableFuture.supplyAsync(() -> { - return 10; - }); - CompletableFuture result = future.thenApply(i -> i + 10).thenApply(i-> String.valueOf(i)); - System.out.println(result.get()); // 20 - } -``` - #### Set mode invoke At present, the framework has already supported the deployment of business in set mode. After set deployment, the calls between businesses are transparent to the business deveploment. But because some services have special needs, after deploying set, the client can specify the set name to invoke the server, so the framework increases the function of the client to specify the set name to invoke the service on the basis of the set deployment. diff --git a/docs/tars_java_user_guide.md b/docs/tars_java_user_guide.md index 591f9930..b2f9d8c1 100644 --- a/docs/tars_java_user_guide.md +++ b/docs/tars_java_user_guide.md @@ -503,26 +503,6 @@ prx.async_hello(new HelloPrxCallback() { CompletableFuture的API一般会有带Async后缀和不带Async后缀两种形式,不带Async后缀的方法会由当前的调用线程来执行任务,而带Async后缀的方法则分为两种情况,若在参数中传入了Executor,则会从传入的线程池获取一个线程去执行任务,否则从全局的 ForkJoinPool.commonPool()中获取一个线程中执行这些任务。 -CompletableFuture提供了对计算结果完成时的处理操作,并都会返回一个CompletableFuture对象,因此可以执行链式调用,常见的操作有: - -- thenApply:参数为上一个CompletableFuture的结果,返回持有新结果的CompletableFuture对象 -- thenRun:无参数,返回无结果的CompletableFuture对象 -- thenAccept:参数为上一个CompletableFuture的结果,返回无结果的CompletableFuture对象 -- handle:参数为上一个CompletableFuture的结果(异常完成时为空)和异常(正常完成时为空),返回持有新结果的CompletableFuture对象 -- whenComplete:参数为上一个CompletableFuture的结果(异常完成时为空)和异常(正常完成时为空),返回和上一个CompletableFuture相同的结果 - -一个简单的结果转换示例如下: - -```Java -public static void main(String[] args) throws Exception { - CompletableFuture future = CompletableFuture.supplyAsync(() -> { - return 10; - }); - CompletableFuture result = future.thenApply(i -> i + 10).thenApply(i-> String.valueOf(i)); - System.out.println(result.get()); // 20 - } -``` - #### set方式调用 目前框架已经支持业务按set方式进行部署,按set部署之后,各个业务之间的调用对开业务发来说是透明的。但是由于有些业务有特殊需求,需要在按set部署之后,客户端可以指定set名称来调用服务端,因此框架则按set部署的基础上增加了客户端可以指定set名称去调用业务服务的功能。 From d7d2c497ac995478366c89f67892f5d39a9e9a63 Mon Sep 17 00:00:00 2001 From: Timmy Date: Mon, 25 May 2020 22:54:08 +0800 Subject: [PATCH 06/16] [format] format tars code --- core/src/main/resources/AdminF.tars | 10 +- core/src/main/resources/ConfigF.tars | 112 ++++++++++---------- core/src/main/resources/EndpointF.tars | 24 ++--- core/src/main/resources/LogF.tars | 74 +++++++------- core/src/main/resources/QueryF.tars | 32 +++--- core/src/main/resources/StatF.tars | 136 ++++++++++++------------- 6 files changed, 194 insertions(+), 194 deletions(-) diff --git a/core/src/main/resources/AdminF.tars b/core/src/main/resources/AdminF.tars index 6a181ca0..d94f0b52 100644 --- a/core/src/main/resources/AdminF.tars +++ b/core/src/main/resources/AdminF.tars @@ -13,19 +13,19 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ - + module tars { interface AdminF { /** - * Close service - */ + * Close service + */ void shutdown(); /** - * Notification service - */ + * Notification service + */ string notify(string command); }; }; diff --git a/core/src/main/resources/ConfigF.tars b/core/src/main/resources/ConfigF.tars index 463a2001..841084ed 100644 --- a/core/src/main/resources/ConfigF.tars +++ b/core/src/main/resources/ConfigF.tars @@ -13,41 +13,41 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ - + module tars { - struct ConfigInfo - { - //Application name - 0 require string appname; - //Service name - 1 require string servername; - //Profile name - 2 require string filename; - //Whether to only get the application configuration, the default is false, if true, servername can be empty - 3 require bool bAppOnly=false; - //Service node(ip) - 4 optional string host; - //Set group name - 5 optional string setdivision; - }; - - struct GetConfigListInfo - { - //Application name - 0 require string appname; - //Service name - 1 optional string servername; - //Whether to only get the application configuration, the default is false, if true, only pull the application level list, other levels are invalid - 2 optional bool bAppOnly=false; - //Service node(ip),if you want the machine level, please assign a value - 3 optional string host=""; - //Set group name, if you want to pull the set level, please assign a value - 4 optional string setdivision=""; - //Container level, if you want to pull the container level, please assign a value - 5 optional string containername=""; - }; - + struct ConfigInfo + { + //Application name + 0 require string appname; + //Service name + 1 require string servername; + //Profile name + 2 require string filename; + //Whether to only get the application configuration, the default is false, if true, servername can be empty + 3 require bool bAppOnly = false; + //Service node(ip) + 4 optional string host; + //Set group name + 5 optional string setdivision; + }; + + struct GetConfigListInfo + { + //Application name + 0 require string appname; + //Service name + 1 optional string servername; + //Whether to only get the application configuration, the default is false, if true, only pull the application level list, other levels are invalid + 2 optional bool bAppOnly = false; + //Service node(ip),if you want the machine level, please assign a value + 3 optional string host = ""; + //Set group name, if you want to pull the set level, please assign a value + 4 optional string setdivision = ""; + //Container level, if you want to pull the container level, please assign a value + 5 optional string containername = ""; + }; + /** * config obj to load server's system config. **/ @@ -66,7 +66,7 @@ module tars * @param app, app name * @param server, server name * @param filename, config file name - * @param config, Configuration file content + * @param config, Configuration file content **/ int loadConfig(string app, string server, string filename, out string config); @@ -89,30 +89,30 @@ module tars **/ int checkConfig(string appServerName, string filename, string host, out string result); - /** - * Read the configuration file list of the node where the service is located - * - * @param configInfo, ConfigInfo: Profile information. If there is no set group information, please set setdivision is empty "" - * @param vf, config file name - * @return int 0: success, -1:failure - **/ - int ListConfigByInfo(ConfigInfo configInfo, out vector vf); + /** + * Read the configuration file list of the node where the service is located + * + * @param configInfo, ConfigInfo: Profile information. If there is no set group information, please set setdivision is empty "" + * @param vf, config file name + * @return int 0: success, -1:failure + **/ + int ListConfigByInfo(ConfigInfo configInfo, out vector vf); - /** - * Read configuration file - * @param configInfo, ConfigInfo: Profile information - * @param config, Configuration file content - * @return int 0: success, -1:failure - **/ - int loadConfigByInfo(ConfigInfo configInfo, out string config); + /** + * Read configuration file + * @param configInfo, ConfigInfo: Profile information + * @param config, Configuration file content + * @return int 0: success, -1:failure + **/ + int loadConfigByInfo(ConfigInfo configInfo, out string config); - /** - * Check whether the configuration file conforms to the TC_Config format - * @param configInfo, ConfigInfo: Profile information - * @param result, prompt - * @return int 0: valid, -1:invalid - **/ - int checkConfigByInfo(ConfigInfo configInfo, out string result); + /** + * Check whether the configuration file conforms to the TC_Config format + * @param configInfo, ConfigInfo: Profile information + * @param result, prompt + * @return int 0: valid, -1:invalid + **/ + int checkConfigByInfo(ConfigInfo configInfo, out string result); }; }; diff --git a/core/src/main/resources/EndpointF.tars b/core/src/main/resources/EndpointF.tars index 3875d8bd..f2685159 100644 --- a/core/src/main/resources/EndpointF.tars +++ b/core/src/main/resources/EndpointF.tars @@ -21,18 +21,18 @@ module tars */ struct EndpointF { - 0 require string host; - 1 require int port; - 2 require int timeout; - 3 require int istcp; - 4 require int grid; - 5 optional int groupworkid; - 6 optional int grouprealid; - 7 optional string setId; - 8 optional int qos; - 9 optional int bakFlag; - 11 optional int weight; - 12 optional int weightType; + 0 require string host; + 1 require int port; + 2 require int timeout; + 3 require int istcp; + 4 require int grid; + 5 optional int groupworkid; + 6 optional int grouprealid; + 7 optional string setId; + 8 optional int qos; + 9 optional int bakFlag; + 11 optional int weight; + 12 optional int weightType; }; key[EndpointF, host, port, timeout, istcp, grid, qos, weight, weightType]; }; diff --git a/core/src/main/resources/LogF.tars b/core/src/main/resources/LogF.tars index 41d804b6..5b52001e 100644 --- a/core/src/main/resources/LogF.tars +++ b/core/src/main/resources/LogF.tars @@ -16,48 +16,48 @@ module tars { - struct LogInfo - { - //Application name - 0 require string appname; - //Service name - 1 require string servername; - //Log file name - 2 require string sFilename; - //Time format - 3 require string sFormat; - //Set group name - 4 optional string setdivision; - // Whether the log file name has a .log suffix - 5 optional bool bHasSufix=true; - // Whether to allow the framework to add business-related identifiers to log file names - 6 optional bool bHasAppNamePrefix=true; - // Whether the [] symbol added to the date and time part of the framework - 7 optional bool bHasSquareBracket=false; - // The connector between the user-defined character and the date character in the log file name, the default is "_" - 8 optional string sConcatStr="_"; - // The separator between log content items, the default is "|" - 9 optional string sSepar="|"; - // Record type when outputting logs by day / hour / minute, for example, by one day: day or 1day; by two hours: 2hour; by 10 minutes: 10minute - 10 optional string sLogType = ""; - }; + struct LogInfo + { + //Application name + 0 require string appname; + //Service name + 1 require string servername; + //Log file name + 2 require string sFilename; + //Time format + 3 require string sFormat; + //Set group name + 4 optional string setdivision; + // Whether the log file name has a .log suffix + 5 optional bool bHasSufix = true; + // Whether to allow the framework to add business-related identifiers to log file names + 6 optional bool bHasAppNamePrefix = true; + // Whether the [] symbol added to the date and time part of the framework + 7 optional bool bHasSquareBracket = false; + // The connector between the user-defined character and the date character in the log file name, the default is "_" + 8 optional string sConcatStr = "_"; + // The separator between log content items, the default is "|" + 9 optional string sSepar = "|"; + // Record type when outputting logs by day / hour / minute, for example, by one day: day or 1day; by two hours: 2hour; by 10 minutes: 10minute + 10 optional string sLogType = ""; + }; interface Log { /** - * Record remote logs - * @param app, Application Name - * @param server, Service name - * @param file, File name - * @param format, Log time format(%Y%m%d) - * @param buffer, Log content - */ + * Record remote logs + * @param app, Application Name + * @param server, Service name + * @param file, File name + * @param format, Log time format(%Y%m%d) + * @param buffer, Log content + */ void loggerInnerImpl(string app, string server, string file, string format, vector buffer); - /** - * Record remote logs - * @param info, LogInfo - * @param buffer, Log content - */ + /** + * Record remote logs + * @param info, LogInfo + * @param buffer, Log content + */ void loggerbyInfo(LogInfo info, vector buffer); }; }; diff --git a/core/src/main/resources/QueryF.tars b/core/src/main/resources/QueryF.tars index b84572a1..4cee9d59 100644 --- a/core/src/main/resources/QueryF.tars +++ b/core/src/main/resources/QueryF.tars @@ -18,7 +18,7 @@ module tars { - /** + /** * Get the query interface of the object endpoint */ @@ -31,15 +31,15 @@ module tars * @return Returns a list of all active endpoints for this object */ vector findObjectById(string id); - - /**Get all objects by id, including active and inactive objects - * + + /**Get all objects by id, including active and inactive objects + * * @param id Object name * @param activeEp List of live endpoints * @param inactiveEp List of non-live endpoints * @return: 0-success others-failure */ - int findObjectById4Any(string id, out vector activeEp, out vector inactiveEp); + int findObjectById4Any(string id, out vector activeEp, out vector inactiveEp); /** Get all endpoint lists of objects according to id, the function is the same as findObjectByIdInSameGroup * @@ -49,7 +49,7 @@ module tars * @return: 0-success others-failure */ int findObjectById4All(string id, out vector activeEp, out vector inactiveEp); - + /** Get the same group endpoint list of objects according to id * * @param id Object name @@ -68,16 +68,16 @@ module tars * @return: 0-success others-failure */ int findObjectByIdInSameStation(string id, string sStation, out vector activeEp, out vector inactiveEp); - - /** Get the same group endpoint list of objects according to id - * - * @param id Object name - * @param setId The full name of set, the format is setname.setarea.setgroup - * @param activeEp List of live endpoints - * @param inactiveEp List of non-live endpoints - * @return: 0-success others-failure - */ - int findObjectByIdInSameSet(string id, string setId, out vector activeEp, out vector inactiveEp); + + /** Get the same group endpoint list of objects according to id + * + * @param id Object name + * @param setId The full name of set, the format is setname.setarea.setgroup + * @param activeEp List of live endpoints + * @param inactiveEp List of non-live endpoints + * @return: 0-success others-failure + */ + int findObjectByIdInSameSet(string id, string setId, out vector activeEp, out vector inactiveEp); }; diff --git a/core/src/main/resources/StatF.tars b/core/src/main/resources/StatF.tars index c6641f49..0b2298b9 100644 --- a/core/src/main/resources/StatF.tars +++ b/core/src/main/resources/StatF.tars @@ -17,76 +17,76 @@ module tars { -//Calling package headers between modules Mic = module interval call -struct StatMicMsgHead -{ - 0 require string masterName; //Main calling module name - 1 require string slaveName; //The name of the called module - 2 require string interfaceName; //The interface name of the called module - 3 require string masterIp; //Main calling module ip - 4 require string slaveIp; //The ip of the called module - 5 require int slavePort; //The port of the called module - 6 require int returnValue; //return value - 7 optional string slaveSetName; //The set name of the called module - 8 optional string slaveSetArea; //The set area name of the called module - 9 optional string slaveSetID; //The set group name of the called module - 10 optional string tarsVersion; //Main calling module tars version -}; + //Calling package headers between modules Mic = module interval call + struct StatMicMsgHead + { + 0 require string masterName; //Main calling module name + 1 require string slaveName; //The name of the called module + 2 require string interfaceName; //The interface name of the called module + 3 require string masterIp; //Main calling module ip + 4 require string slaveIp; //The ip of the called module + 5 require int slavePort; //The port of the called module + 6 require int returnValue; //return value + 7 optional string slaveSetName; //The set name of the called module + 8 optional string slaveSetArea; //The set area name of the called module + 9 optional string slaveSetID; //The set group name of the called module + 10 optional string tarsVersion; //Main calling module tars version + }; -key[StatMicMsgHead, masterName, slaveName,interfaceName,masterIp,slaveIp,slavePort,returnValue, slaveSetName, slaveSetArea, slaveSetID, tarsVersion]; - -//Inter module call package body protocol -struct StatMicMsgBody -{ - 0 require int count; //Successful call count - 1 require int timeoutCount; //Timeout call count - 2 require int execCount; //Exception call count - //The following fields are used for statistics for successful calls - 3 require map intervalCount; //Call count in time interval - 4 require long totalRspTime; //The total response time is used to calculate the average time - 5 require int maxRspTime; //Maximum response time - 6 require int minRspTime; //Minimum response time -}; + key[StatMicMsgHead, masterName, slaveName, interfaceName, masterIp, slaveIp, slavePort, returnValue, slaveSetName, slaveSetArea, slaveSetID, tarsVersion]; -//Call sampling information between modules -struct StatSampleMsg -{ - 0 require string unid; //Unique id value - 1 require string masterName; //Main calling module name - 2 require string slaveName; //The name of the called module - 3 require string interfaceName; //The interface name of the called module - 4 require string masterIp; //Main calling module ip - 5 require string slaveIp; //The ip of the called module - 6 require int depth; //Depth value - 7 require int width; //Breadth value - 8 require int parentWidth; //Parent node breadth value -}; + //Inter module call package body protocol + struct StatMicMsgBody + { + 0 require int count; //Successful call count + 1 require int timeoutCount; //Timeout call count + 2 require int execCount; //Exception call count + //The following fields are used for statistics for successful calls + 3 require map intervalCount; //Call count in time interval + 4 require long totalRspTime; //The total response time is used to calculate the average time + 5 require int maxRspTime; //Maximum response time + 6 require int minRspTime; //Minimum response time + }; -struct ProxyInfo -{ - 0 require bool bFromClient;//Whether from the client -}; -/** - * - * Interface to the report service - * - **/ -interface StatF -{ - /** - * Report calling information between modules Mic = module interval call - * @param statmsg, Report information - * @param bFromServer, Report source bFromClient: true (Reporting initiated by the client) false (Reporting initiated by the server) - * @return int, Return 0 means success - */ - int reportMicMsg( map msg, bool bFromClient); - - /** - * Report sampling information between modules Mic = module interval call - * @param msg, Report information - * @return int, Return 0 means success - */ - int reportSampleMsg(vector msg); -}; + //Call sampling information between modules + struct StatSampleMsg + { + 0 require string unid; //Unique id value + 1 require string masterName; //Main calling module name + 2 require string slaveName; //The name of the called module + 3 require string interfaceName; //The interface name of the called module + 4 require string masterIp; //Main calling module ip + 5 require string slaveIp; //The ip of the called module + 6 require int depth; //Depth value + 7 require int width; //Breadth value + 8 require int parentWidth; //Parent node breadth value + }; + + struct ProxyInfo + { + 0 require bool bFromClient; //Whether from the client + }; + /** + * + * Interface to the report service + * + **/ + interface StatF + { + /** + * Report calling information between modules Mic = module interval call + * @param statmsg, Report information + * @param bFromServer, Report source bFromClient: true (Reporting initiated by the client) false (Reporting initiated by the server) + * @return int, Return 0 means success + */ + int reportMicMsg(map msg, bool bFromClient); + + /** + * Report sampling information between modules Mic = module interval call + * @param msg, Report information + * @return int, Return 0 means success + */ + int reportSampleMsg(vector msg); + }; }; From dda439834a0025c3e403b2c2b6436079e127c984 Mon Sep 17 00:00:00 2001 From: Timmy Date: Mon, 25 May 2020 22:55:21 +0800 Subject: [PATCH 07/16] add example logback config --- .../tars-spring-boot-server/src/main/resources/logback.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/tars-spring-boot-server/src/main/resources/logback.xml diff --git a/examples/tars-spring-boot-server/src/main/resources/logback.xml b/examples/tars-spring-boot-server/src/main/resources/logback.xml new file mode 100644 index 00000000..e873048c --- /dev/null +++ b/examples/tars-spring-boot-server/src/main/resources/logback.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From b0817d82de9b338f69394ec8ef9b84ffaba157b3 Mon Sep 17 00:00:00 2001 From: Timmy Date: Wed, 27 May 2020 15:31:38 +0800 Subject: [PATCH 08/16] [fix] fix property set report error --- .../property/PropertyReportHelper.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/qq/tars/support/property/PropertyReportHelper.java b/core/src/main/java/com/qq/tars/support/property/PropertyReportHelper.java index 33bddacb..af3b6b20 100644 --- a/core/src/main/java/com/qq/tars/support/property/PropertyReportHelper.java +++ b/core/src/main/java/com/qq/tars/support/property/PropertyReportHelper.java @@ -17,6 +17,8 @@ package com.qq.tars.support.property; import com.qq.tars.client.Communicator; +import com.qq.tars.client.CommunicatorConfig; +import com.qq.tars.net.util.Utils; import com.qq.tars.rpc.exc.TarsException; import com.qq.tars.server.config.ConfigurationManager; import com.qq.tars.support.log.LoggerFactory; @@ -66,8 +68,20 @@ public static class PropertyReporter { private Collection policies; private String propRptName; private String moduleName; + private String ip = ""; + private String setName = ""; + private String setArea = ""; + private String setID = ""; public PropertyReporter(String moduleName, String propRptName, Policy[] policies) { + CommunicatorConfig config = ConfigurationManager.getInstance().getServerConfig().getCommunicatorConfig(); + + this.moduleName = !config.isEnableSet() ? moduleName : String.format("%s.%s%s%s", moduleName, config.getSetName(), config.getSetArea(), config.getSetID()); + if (config.isEnableSet()) { + this.setName = config.getSetName(); + this.setArea = config.getSetArea(); + this.setID = config.getSetID(); + } this.propRptName = propRptName; if (ConfigurationManager.getInstance().getCommunicatorConfig().isEnableSet()) { @@ -76,13 +90,18 @@ public PropertyReporter(String moduleName, String propRptName, Policy[] policies } else { this.moduleName = moduleName; } + this.ip = ConfigurationManager.getInstance().getServerConfig().getLocalIP(); Map map = new HashMap(); for (Policy policy : policies) map.put(policy.desc(), policy); this.policies = map.values(); + + this.ip = Utils.getLocalIp(); + } + public void report(int value) { for (Policy policy : policies) policy.set(value); @@ -90,11 +109,11 @@ public void report(int value) { public ReportData getReportData() { int len = 0; - StatPropMsgHead head = new StatPropMsgHead(moduleName, "", propRptName, null, null, null, null, 1); + StatPropMsgHead head = new StatPropMsgHead(moduleName, this.ip, propRptName, setName, setArea, setID, null, 1); len += moduleName.length() + propRptName.length(); int size = policies.size(); len += PROPERTY_PROTOCOL_LEN + size; - List statPropInfos = new ArrayList(); + List statPropInfos = new ArrayList(policies.size()); for (Policy policy : policies) { String desc = policy.desc(); String value = policy.get(); From 07049088d2302b4c2d67825a9871ab709180f501 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 27 May 2020 16:27:45 +0800 Subject: [PATCH 09/16] add Struct toString method --- .../qq/tars/protocol/util/EncodingUtils.java | 69 +++++++++ .../qq/tars/maven/gensrc/Tars2JavaMojo.java | 144 ++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 core/src/main/java/com/qq/tars/protocol/util/EncodingUtils.java diff --git a/core/src/main/java/com/qq/tars/protocol/util/EncodingUtils.java b/core/src/main/java/com/qq/tars/protocol/util/EncodingUtils.java new file mode 100644 index 00000000..ccdf038e --- /dev/null +++ b/core/src/main/java/com/qq/tars/protocol/util/EncodingUtils.java @@ -0,0 +1,69 @@ +/** + * Tencent is pleased to support the open source community by making Tars available. + * + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.qq.tars.protocol.util; + +public class EncodingUtils { + public EncodingUtils() { + } + + public static final boolean testBit(byte v, int position) { + return testBit((int)v, position); + } + + public static final boolean testBit(short v, int position) { + return testBit((int)v, position); + } + + public static final boolean testBit(int v, int position) { + return (v & 1 << position) != 0; + } + + public static final boolean testBit(long v, int position) { + return (v & 1L << position) != 0L; + } + + public static final byte clearBit(byte v, int position) { + return (byte)clearBit((int)v, position); + } + + public static final short clearBit(short v, int position) { + return (short)clearBit((int)v, position); + } + + public static final int clearBit(int v, int position) { + return v & ~(1 << position); + } + + public static final long clearBit(long v, int position) { + return v & ~(1L << position); + } + + public static final byte setBit(byte v, int position, boolean value) { + return (byte)setBit((int)v, position, value); + } + + public static final short setBit(short v, int position, boolean value) { + return (short)setBit((int)v, position, value); + } + + public static final int setBit(int v, int position, boolean value) { + return value ? v | 1 << position : clearBit(v, position); + } + + public static final long setBit(long v, int position, boolean value) { + return value ? v | 1L << position : clearBit(v, position); + } +} diff --git a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java index b8c9dce1..4d5be3da 100644 --- a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java +++ b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java @@ -61,6 +61,8 @@ public class Tars2JavaMojo extends AbstractMojo { private AtomicInteger var = new AtomicInteger(0); + enum IsSetType {ISSET_NONE, ISSET_PRIMITIVE, ISSET_BITSET} + public void execute() throws MojoExecutionException, MojoFailureException { // 1. check configurations if (!tars2JavaConfig.packagePrefixName.endsWith(".")) { @@ -272,6 +274,27 @@ private void genStruct(String dirPath, String packageName, String namespace, Tar } out.println(); + // isset data + int optionals = 0; + for (TarsStructMember m : struct.memberList()) { + if (!typeCanBeNull(m.memberType(), nsMap)) { + out.println("\tprivate static final int __" + m.memberName().toUpperCase() + "_ISSET_ID = " + optionals + ";"); + optionals++; + } + } + StringBuilder outprimitiveType = new StringBuilder(""); + IsSetType isSetType = needIsSet(struct, outprimitiveType, nsMap); + switch (isSetType){ + case ISSET_NONE: + break; + case ISSET_PRIMITIVE: + out.println("\tprivate " + outprimitiveType.toString() + " __isset_bitfield = 0;"); + break; + case ISSET_BITSET: + out.println("\tprivate java.util.BitSet __isset_bit_vector = new java.util.BitSet(" + optionals + ");"); + } + out.println(); + // 生成 getter setter for (TarsStructMember m : struct.memberList()) { out.println("\tpublic " + type(m.memberType(), nsMap) + " " + fieldGetter(m.memberName(), m.memberType()) + "() {"); @@ -281,6 +304,36 @@ private void genStruct(String dirPath, String packageName, String namespace, Tar out.println("\tpublic void " + fieldSetter(m.memberName(), m.memberType()) + "(" + type(m.memberType(), nsMap) + " " + m.memberName() + ") {"); out.println("\t\tthis." + m.memberName() + " = " + m.memberName() + ";"); + if (!typeCanBeNull(m.memberType(), nsMap)) { + out.println("\t\tset" + firstUpStr(m.memberName()) + "IsSet(true);"); + } + out.println("\t}"); + out.println(); + + // isSet method + out.println("\t/** Returns true if field " + m.memberName() + " is set (has been assigned a value) and false otherwise */"); + out.println("\tpublic boolean isSet" + firstUpStr(m.memberName()) + "() {"); + if (typeCanBeNull(m.memberType(), nsMap)) { + out.println("\t\treturn this." + m.memberName() + " != null;"); + } else if (isSetType == IsSetType.ISSET_PRIMITIVE) { + out.println("\t\treturn EncodingUtils.testBit(__isset_bitfield, __" + m.memberName().toUpperCase() + "_ISSET_ID);"); + } else { + out.println("\t\treturn __isset_bit_vector.get(__" + m.memberName().toUpperCase() + "_ISSET_ID);"); + } + out.println("\t}"); + out.println(); + + // setFieldIsSet method + out.println("\tpublic void set" + firstUpStr(m.memberName()) + "IsSet(boolean value) {"); + if (typeCanBeNull(m.memberType(), nsMap)) { + out.println("\t\tif (!value) {"); + out.println("\t\t\tthis." + m.memberName() + " = null;"); + out.println("\t\t}"); + } else if (isSetType == IsSetType.ISSET_PRIMITIVE) { + out.println("\t\t__isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __" + m.memberName().toUpperCase() + "_ISSET_ID, value);"); + } else { + out.println("\t\t__isset_bit_vector.set(__" + m.memberName().toUpperCase() + "_ISSET_ID, value);"); + } out.println("\t}"); out.println(); } @@ -377,6 +430,53 @@ private void genStruct(String dirPath, String packageName, String namespace, Tar out.println("\t}"); out.println(); + // toString + out.println("\t@Override"); + out.println("\tpublic String toString() {"); + out.println("\t\tStringBuilder sb = new StringBuilder(\"" + struct.structName() + "(\");"); + out.println("\t\tboolean first = true;"); + out.println(); + + boolean first = true; + for (TarsStructMember m : struct.memberList()) { + boolean couldBeUnSet = !m.isRequire(); + if (couldBeUnSet){ + out.println("\t\tif (isSet" + firstUpStr(m.memberName()) + "()) {"); + } + if (!first) { + if (couldBeUnSet) out.print("\t"); + out.println("\t\tif (!first) sb.append(\", \");"); + } + if (couldBeUnSet) out.print("\t"); + out.println("\t\tsb.append(\"" + m.memberName() + ":\");"); + boolean canBeNull = typeCanBeNull(m.memberType(), nsMap); + if (canBeNull) { + if (couldBeUnSet) out.print("\t"); + out.println("\t\tif (this." + m.memberName() + " == null) {"); + if (couldBeUnSet) out.print("\t"); + out.println("\t\t\tsb.append(\"null\");"); + if (couldBeUnSet) out.print("\t"); + out.println("\t\t} else {"); + out.print("\t"); + } + if (couldBeUnSet) out.print("\t"); + out.println("\t\tsb.append(this." + m.memberName() + ");"); + if (canBeNull) { + if (couldBeUnSet) out.print("\t"); + out.println("\t\t}"); + } + if (couldBeUnSet) out.print("\t"); + out.println("\t\tfirst = false;"); + if (couldBeUnSet) { + out.println("\t\t}"); + } + first = false; + } + out.println("\t\tsb.append(\")\");"); + out.println("\t\treturn sb.toString();"); + out.println("\t}"); + out.println(); + //writeTo out.println("\tpublic void writeTo(TarsOutputStream _os) {"); for (TarsStructMember m : struct.memberList()) { @@ -728,6 +828,50 @@ private boolean isEnum(TarsType jt, Map> nsMap) { return false; } + private boolean typeCanBeNull(TarsType jt, Map> nsMap) { + boolean canBeNull = true; + if (jt.isCustom()) { + boolean isEnum = nsMap != null ? isEnum(jt, nsMap) : false; + if (isEnum){ + canBeNull = false; + } + } + if (jt.isPrimitive()) { + TarsPrimitiveType primitiveType = jt.asPrimitive(); + if (primitiveType != null && !primitiveType.primitiveType().equals(PrimitiveType.STRING)) { + canBeNull = false; + } + } + return canBeNull; + } + + private IsSetType needIsSet(TarsStruct struct, StringBuilder outPrimitiveType, Map> nsMap) { + int count = 0; + for (TarsStructMember m : struct.memberList()) { + if (!typeCanBeNull(m.memberType(), nsMap)) { + count++; + } + } + if (count == 0) { + return IsSetType.ISSET_NONE; + } else if (count <= 64){ + if (outPrimitiveType != null) { + if (count <= 8) { + outPrimitiveType.append("byte"); + } else if (count <= 16) { + outPrimitiveType.append("short"); + } else if (count <= 32) { + outPrimitiveType.append("int"); + } else if (count <= 64) { + outPrimitiveType.append("long"); + } + } + return IsSetType.ISSET_PRIMITIVE; + } else { + return IsSetType.ISSET_BITSET; + } + } + private String typeInit(TarsType jt, Map> nsMap, boolean useDefault) { if (!useDefault) { if (jt.isPrimitive()) { From 52baf692b14bd835d1edf3f9f17ff0a2519561f5 Mon Sep 17 00:00:00 2001 From: Yuki Date: Fri, 29 May 2020 10:23:34 +0800 Subject: [PATCH 10/16] add logback usage --- docs-en/tars_java_user_guide.md | 205 ++++++++++++++++++++++++++++++++ docs/images/Logback-config.png | Bin 0 -> 2950 bytes docs/tars_java_user_guide.md | 204 +++++++++++++++++++++++++++++++ 3 files changed, 409 insertions(+) create mode 100644 docs/images/Logback-config.png diff --git a/docs-en/tars_java_user_guide.md b/docs-en/tars_java_user_guide.md index 7a25d6b4..9ef510c8 100644 --- a/docs-en/tars_java_user_guide.md +++ b/docs-en/tars_java_user_guide.md @@ -572,6 +572,211 @@ Illustration: remote log service must be pre applied before long log. > * LogType.REMOTE: Only print remote logs > * LogType.All : Print local and remote logs +### Logback log system + +After TarsJava v1.7, Logback was used as the Tars log system. The configuration of Logback is very flexible and can provide users with more powerful log functions. + +#### Architecture + +Logback log system consists of three parts, namely Logger, Appender, Layout: + +- Logger: Each Logger is attached to a LoggerContext, which is used to generate Loggers and arrange them into a tree-like hierarchy. Logger is a named entity. Their names are case sensitive and follow hierarchical naming rules: + + > Named Hierarchy + > + > A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger. + + Loggers can be assigned different levels, namely TRACE, DEBUG, INFO, WARN and ERROR. If the effective level of the Logger is q and the request level of the log record is p, the log request will be executed only when p≥q. The default effective level of root Logger is DEBUG. + + > Level rules: TRACE < DEBUG < INFO < WARN < ERROR + +If no level is set for the Logger, then it will inherit an assigned level from its closest ancestor. A simple example is as follows: + +| Logger name | Assigned level | Effective level | +| ----------- | -------------- | --------------- | +| root | DEBUG | DEBUG | +| X | INFO | INFO | +| X.Y | none | INFO | +| X.Y.Z | none | INFO | + +- Appender: The component for writing log events, you can specify the log output to the console, files, remote servers, and databases. +- Layout: Format and output log information. + +#### Configuration + +Logback will first look for *logback-test.xml* and *logback.xml* configuration files in the class path. If it is not found, the default *BasicConfigurator* will be used. The basic structure of the configuration file can be described as, \ element, containing zero or more \ elements, followed by zero or more \ elements, followed by at most one \ element. The official document gives the structure of the configuration file as follows: + +![Logback-config](../docs/images/Logback-config.png) + +A typical logback.xml configuration file format is as follows: + +```xml + + + ${Logname} + + + + ··· + + + + ··· + + + + ··· + + +``` + +1. \ + +It provides three configuration options: + +- scan:true means that when the configuration file changes, the configuration file will be reloaded automatically, the default value is true. +- scanPeriod:The time interval for scanning the configuration file for changes. The default time unit is milliseconds. You can set the unit to milliseconds, seconds, minutes, or hours. +- debug:true means to print Logback internal log information, the default value is false. + +```xml + + ... + +``` + +2. \ + +It is used to set the name of LoggerContext. The default context name is "default". Once set, the context name cannot be changed. + +```xml +myAppName +``` + +3. \ + +You can use this variable to define variables in the configuration file, or you can load them in batches from external property files or external resources. The variable can then be used in the form of $ {variable name}. + +```xml + +``` + +4. \ + +The components responsible for writing log events. There are several common types + +- ConsoleAppender: Output log to console + + ```xml + + + %-4relative [%thread] %-5level %logger{35} - %msg %n + + + ``` + +- FileAppender: Output log to file + + ```xml + + + testFile.log + + true + + true + + %-4relative [%thread] %-5level %logger{35} - %msg%n + + + ``` + +- RollingFileAppender: You can first output the log to a specified file, and once a certain condition is met, then log to another file. (extends FileAppender class) + + ```xml + + logFile.log + + + logFile.%d{yyyy-MM-dd}.log + + + 30 + 3GB + + + + + %-4relative [%thread] %-5level %logger{35} - %msg%n + + + ``` + + In addition to the above time rolling strategy, there is also a **FixedWindowRollingPolicy**。 + +5. \ + +You can set the log printing level of a certain package or a specific class, and add appender. + +- name:Make a package or a class of logger constraints +- level:Assign print level +- addtivity:Whether to pass the print information to the superior logger, the default is true +- \:Add this appender to logger + +```xml + + + +``` + +6. \ + +It is also the \ element. Only the level attribute is used to set the print level, and you can also use to add appenders. + +```xml + + + +``` + +A complete logback.xml configuration is as follows: + +```xml + + + + myApp.log + + %date %level [%thread] %logger{10} [%file:%line] %msg%n + + + + + + %msg%n + + + + + + + + + + + +``` + +#### Logback usage + +You can obtain the corresponding logger by calling the LoggerFactory.getLogger method, and then use the logger to complete the log recording. + +```java +Logger logger = LoggerFactory.getLogger("name"); +logger.info("Hello World!"); +``` + +For more information on the use of Logback, please refer to [Logback Official Document](http://logback.qos.ch/manual/index.html). + ## Service management The service framework can support dynamic receiving commands to handle related business logic, such as dynamic update configuration, etc. diff --git a/docs/images/Logback-config.png b/docs/images/Logback-config.png new file mode 100644 index 0000000000000000000000000000000000000000..9e88c644bcc2199651f4f5cdeef7fd04dbc7937b GIT binary patch literal 2950 zcmb_eeN+W;y>lm(>1j*(Trn2_z)!}L^Z+1o*#8)1!r$6$cVEJW_1nbML;%j#l>C&j3yvl0 zaD6HO#j^k)$^iIr9JY@D*ft-4#|8ir_5m<`^S)#I`vG8r^yQg4xCVaX&lXfzV0h|nl z0k_B6(XKgB(>R>usQLbLd@?aVuDrf!w=naqK8!6;cSTa_;YjX(F1M-5c#b-QAcXU8 zv#qpHDM{p5n^em^EbUuV!MT$UyAKnKNT6iL9Nxn1bXfO{S~Xk=QN9XqM*j3bC!)@> zxJmq&M02b?c_lzpi!@cGiJ}?2v0LqWG$mQtt5u5Q4YE*kZijG0Vx~5-nO4>up?h?oA1a|{}(QL_Vhs86$%TJ8*- zcT`Fv)gvT>6U=OY`6N(BCQvRWcQd`0i+ik;1x*+0yXjbEVY;jBOt%83>l|;l2!ZT( zC`s&s?u{I@DIiSGb79+^3z+muITtC$6}5r1>rQPIrGj2Z#!-085tt$toAB^yn_oDY zD}cM7B%Q1`xn;5St38=vLf~Y%@GNjgi%)Gt=;X4q-&mB5Eg<3S5^dG{Z&I~6SkD~I zcIVa<4KjdADALptcg7L%(^y903gUz=MZo!@|Z{^-T*KJB|gnrKWK%?($3ce9kQP;5`1WrF~W-`)ka$ zY-jt@wT<+(9wBo z&5V`o42*p)^s#!5u7i`$gO&^&zbX=bsjbv_1Nr zWJ|oDaX=BSHNn&nJj84pFR1kR@aK*?l`aX#iqK};Njk_$Ba6)^N{?kn;FU_WONj+- zx}e(dG!moGi;knDW@K@Zb)kHqsoLYDEo0f%5pw4TC7ko2-A0V|O<21$rY|o@AAeh# zvenL%-*a>AvYuE)<+a$W$X~+tuX0H!*8wu!=l<5&b;o4%1*jG2Tcz#d)%CJ4%fOO~ z=&t+fgHMx`d%EFukOXS0HmQp*```JDd84q(@xiq1F9mdB8!(+^F7o6B&p|R)zwF=Q zkHM2*PS^kN(ai6{vRbUdtQw>A(kK2*m;|6)_?2RX>HMqoAyJf)E&}N}go-t=rhK&` zW35r0-xjp2E(oT(HRR05W)R6S45S?|-uZNPcIfCs`i5@8hcA4L`tN$O!o8XkPd&@R zt$*w=b>}8p8rC?h06$TKMuC)-EE2q@OBShho5B9e;4xr@3WB!KFh`z7@w(1p)928d+$6<*{gd~5&81THLnEk * LogType.REMOTE只打远程日志 > * LogType.All 打本地和远程日志 +#### Logback日志系统 + +TarsJava 1.7版本之后使用了Logback作为日志系统,Logback提供了十分灵活的配置项,可以为用户提供更加强大的日志功能。 + +##### 日志系统结构 + +Logback日志系统由三部分组成,分别是Logger, Appender, Layout: + +- Logger:日志记录器,每个Logger会附加到一个LoggerContext中,后者用于生成Logger,并将它们排列成树状层次结构。Logger是命名实体。它们的名称区分大小写,并且遵循分层命名规则: + + > 命名层次结构:如果一个记录器的名称后有一个点,则该记录器是另一个记录器的祖先,该记录器的名称是该子记录器名称的前缀。如果记录器与子记录器之间没有祖先,则称该记录器为子记录器的父级 + + Logger可以设置不同级别,分别是TRACE、DEBUG、INFO、WARN 和 ERROR。若Logger的有效级别为q,日志记录的请求级别为p,只有当p≥q时,该日志请求才会被执行。(root Logger 默认有效级别是 DEBUG) + + > 级别排序规则: TRACE < DEBUG < INFO < WARN < ERROR + + 如果没有为Logger设置一个级别,那么它将从其最接近的祖先那里继承一个已分配的级别,一个简单的示例如下: + + | Logger name | Assigned level | Effective level | + | ----------- | -------------- | --------------- | + | root | DEBUG | DEBUG | + | X | INFO | INFO | + | X.Y | none | INFO | + | X.Y.Z | none | INFO | + +- Appender:用于编写日志事件的组件,可以指定日志输出到控制台、文件、远程服务器以及数据库等。 + +- Layout:将日志信息进行格式化输出 + +##### 配置文件 + +Logback会首先会在类路径下寻找*logback-test.xml*和*logback.xml*配置文件,若没有找到,则会使用默认的*BasicConfigurator*。配置文件的基本结构为\元素中包含多个\和\元素和最多一个\元素,官方文档中给出了配置文件的结构图如下: + +![Logback-config](images/Logback-config.png) + +一个典型的logback.xml配置文件格式如下: + +```xml + + + ${Logname} + + + + ··· + + + + ··· + + + + ··· + + +``` + +1. \ + +\标签提供了三个配置选项: + +- scan:true表示当配置文件更改时,会自动重新加载配置文件,默认值为true +- scanPeriod:扫描配置文件是否发生更改的时间间隔,默认时间单位为毫秒,可以自行设置单位为毫秒、秒、分钟或者小时 +- debug:true表示打印Logback内部日志信息,默认值为false + +```xml + + ... + +``` + +2. \ + +用于设置LoggerContext的名称,默认的上下文名称为"default",一旦设置之后,上下文名字不能再被更改。 + +```xml +myAppName +``` + +3. \ + +使用该变量可以在配置文件中定义变量,也可以从外部属性文件或者外部资源中批量加载。之后通过${变量名}的形式可以调用该变量。 + +```xml + +``` + +4. \ + +负责写日志任务的组件,常用的有以下几类: + +- ConsoleAppender:将日志输出到控制台 + + ```xml + + + %-4relative [%thread] %-5level %logger{35} - %msg %n + + + ``` + +- FileAppender:将日志输出到文件 + + ```xml + + + testFile.log + + true + + true + + %-4relative [%thread] %-5level %logger{35} - %msg%n + + + ``` + +- RollingFileAppender:可以先将日志输出到指定文件,一旦满足某个条件时,再将日志记录到另一个文件。(FileAppender的子类) + + ```xml + + logFile.log + + + logFile.%d{yyyy-MM-dd}.log + + + 30 + 3GB + + + + + %-4relative [%thread] %-5level %logger{35} - %msg%n + + + ``` + + 除上述的时间滚动策略以外,还有固定窗口滚动策略**FixedWindowRollingPolicy**。 + +5. \ + +可以设置某一个包或者具体的某一个类的日志打印级别,并添加appender。 + +- name:制定logger约束的某一个包或某一个类 +- level:设置打印级别 +- addtivity:是否向上级logger传递打印信息,默认为true +- \:添加这个appender到logger + +```xml + + + +``` + +6. \ + +也是\元素,是根logger,仅有level一个属性用于设置打印级别,同时也可以使用来添加appender。 + +```xml + + + +``` + +一个完整的logback.xml配置如下: + +```xml + + + + myApp.log + + %date %level [%thread] %logger{10} [%file:%line] %msg%n + + + + + + %msg%n + + + + + + + + + + + +``` + +##### 日志使用 + +通过调用LoggerFactory.getLogger方法即可获取相应的日志记录器,之后使用记录器来完成来完成日志的记录。 + +```java +Logger logger = LoggerFactory.getLogger("name"); +logger.info("Hello World!"); +``` + +更多关于Logback的使用,请参考[Logback官方文档](http://logback.qos.ch/manual/index.html)。 + ## 服务管理 服务框架可以支持动态接收命令,来处理相关的业务逻辑,例如:动态更新配置等。 From 3506230fc171063fce08a6b4d1f32f8a9bf0b6e4 Mon Sep 17 00:00:00 2001 From: Timmy Date: Sun, 31 May 2020 16:42:08 +0800 Subject: [PATCH 11/16] [change] Use gson instead of fastjson --- core/client.pom.xml | 5 +++ core/pom.xml | 8 ++--- .../java/com/qq/tars/common/util/JSON.java | 30 +++++++++++++++++ .../qq/tars/rpc/protocol/tars/TarsCodec.java | 32 ++++++++++--------- 4 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 core/src/main/java/com/qq/tars/common/util/JSON.java diff --git a/core/client.pom.xml b/core/client.pom.xml index fc544ba5..a39293b9 100644 --- a/core/client.pom.xml +++ b/core/client.pom.xml @@ -68,6 +68,11 @@ ${maven_junit_version} test + + com.google.code.gson + gson + 2.8.2 + diff --git a/core/pom.xml b/core/pom.xml index 51abe338..22286e68 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -18,7 +18,7 @@ 0.31.1 2.7.4 1.2.3 - 1.2.62 + 2.8.6 @@ -70,9 +70,9 @@ - com.alibaba - fastjson - ${fastjson.version} + com.google.code.gson + gson + ${gson.version} diff --git a/core/src/main/java/com/qq/tars/common/util/JSON.java b/core/src/main/java/com/qq/tars/common/util/JSON.java new file mode 100644 index 00000000..060f8b56 --- /dev/null +++ b/core/src/main/java/com/qq/tars/common/util/JSON.java @@ -0,0 +1,30 @@ +package com.qq.tars.common.util; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; + +import java.lang.reflect.Type; + +public class JSON { + private static final Gson gson = new Gson(); + + + public static String toJson(final Object obj) { + return gson.toJson(obj); + } + + public static T fromJson(final String str, Class cls) { + return gson.fromJson(str, cls); + } + + + public static JsonElement toJsonTree(final Object obj) { + return gson.toJsonTree(obj); + } + + + public static T fromJson(final String str, Type type) { + return gson.fromJson(str, type); + } + +} diff --git a/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java b/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java index 7edcb701..9d18568b 100644 --- a/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java +++ b/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java @@ -16,10 +16,13 @@ package com.qq.tars.rpc.protocol.tars; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.qq.tars.common.support.ClassLoaderManager; import com.qq.tars.common.support.Holder; import com.qq.tars.common.util.CollectionUtils; import com.qq.tars.common.util.Constants; +import com.qq.tars.common.util.JSON; import com.qq.tars.common.util.StringUtils; import com.qq.tars.net.core.IoBuffer; import com.qq.tars.net.core.Request; @@ -38,10 +41,6 @@ import com.qq.tars.rpc.protocol.tars.support.AnalystManager; import com.qq.tars.rpc.protocol.tup.UniAttribute; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.alibaba.fastjson.serializer.SerializerFeature; - import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.nio.ByteBuffer; @@ -170,7 +169,9 @@ protected byte[] encodeJsonResult(TarsServantResponse response, String charsetNa } // 服务端接口响应 - JSONObject object = new JSONObject(); + + + JsonObject object = new JsonObject(); int ret = response.getRet(); Map methodInfoMap = AnalystManager.getInstance().getMethodMapByName(request.getServantName()); @@ -179,7 +180,8 @@ protected byte[] encodeJsonResult(TarsServantResponse response, String charsetNa TarsMethodParameterInfo returnInfo = methodInfo.getReturnInfo(); if (returnInfo != null && returnInfo.getType() != Void.TYPE && response.getResult() != null) { try { - object.put(TarsHelper.STAMP_STRING, response.getResult()); + JsonElement jsonElement = JSON.toJsonTree(response.getResult()); + object.add(TarsHelper.STAMP_STRING, jsonElement); } catch (Exception e) { System.err.println("server encode json ret :" + response.getResult() + ", with ex:" + e); } @@ -192,7 +194,7 @@ protected byte[] encodeJsonResult(TarsServantResponse response, String charsetNa value = request.getMethodParameters()[parameterInfo.getOrder() - 1]; if (value != null) { try { - object.put(parameterInfo.getName(), TarsHelper.getHolderValue(value)); + object.add(parameterInfo.getName(), JSON.toJsonTree(TarsHelper.getHolderValue(value))); } catch (Exception e) { System.err.println("server encode json holder :" + value + ", with ex:" + e); } @@ -218,7 +220,7 @@ protected byte[] encodeWupResult(TarsServantResponse response, String charsetNam unaOut.setEncodeName(charsetName); if (response.getVersion() == TarsHelper.VERSION3) { unaOut.useVersion3(); - } else if(response.getVersion() == TarsHelper.VERSION2) { + } else if (response.getVersion() == TarsHelper.VERSION2) { unaOut.setNewDataNull(); } @@ -444,7 +446,7 @@ protected Object[] decodeRequestBody(byte[] data, String charset, TarsMethodInfo } protected Object[] decodeRequestWupBody(byte[] data, int version, String charset, - TarsMethodInfo methodInfo) throws Exception { + TarsMethodInfo methodInfo) throws Exception { //wup request UniAttribute unaIn = new UniAttribute(); unaIn.setEncodeName(charsetName); @@ -479,9 +481,9 @@ protected Object[] decodeRequestWupBody(byte[] data, int version, String charset } protected Object[] decodeRequestJsonBody(byte[] data, String charset, - TarsMethodInfo methodInfo) throws Exception { + TarsMethodInfo methodInfo) throws Exception { // 解析json串 - JSONObject jsonObject = JSON.parseObject(new String(data, charset)); + JsonObject jsonObject = JSON.fromJson(new String(data, charset), JsonObject.class); // 按字段反序列化 int i = 0; @@ -492,16 +494,16 @@ protected Object[] decodeRequestJsonBody(byte[] data, String charset, for (TarsMethodParameterInfo parameterInfo : parametersList) { if (TarsHelper.isHolder(parameterInfo.getAnnotations())) { - if (jsonObject.containsKey(parameterInfo.getName())) { - value = new Holder<>(JSON.parseObject(jsonObject.get(parameterInfo.getName()).toString(), + if (jsonObject.has(parameterInfo.getName())) { + value = new Holder<>(JSON.fromJson(jsonObject.get(parameterInfo.getName()).toString(), parameterInfo.getType())); } else { // new response, can not use cache value = new Holder<>(TarsHelper.getNewParameterStamp(parameterInfo.getType())); } } else { - if (jsonObject.containsKey(parameterInfo.getName())) { - value = JSON.parseObject(jsonObject.get(parameterInfo.getName()).toString(), + if (jsonObject.has(parameterInfo.getName())) { + value = JSON.fromJson(jsonObject.get(parameterInfo.getName()).toString(), parameterInfo.getType()); } else { throw new ProtocolException("no found parameter, the context[ROOT], " From ba725eb7b7e647323232c39bdf9d8acc2ba7758d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E4=BD=B3=E6=95=8F?= Date: Thu, 4 Jun 2020 11:25:46 +0800 Subject: [PATCH 12/16] =?UTF-8?q?bool=E5=8F=98=E9=87=8F=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E6=98=AFis=E5=BC=80=E5=A4=B4=E7=9A=84=E7=89=B9=E6=AE=8A?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qq/tars/maven/gensrc/Tars2JavaMojo.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java index 533b929b..c47da113 100644 --- a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java +++ b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java @@ -875,20 +875,45 @@ private static String firstUpStr(String str) { } private static String packageName(String packagePrefixName, String namespace) { + if (!packagePrefixName.endsWith(".")) { + packagePrefixName += "."; + } return packagePrefixName + namespace.toLowerCase(); } public static String fieldGetter(String fieldName, TarsType type) { - if (type.isPrimitive() && (type.asPrimitive()).primitiveType() == TarsPrimitiveType.PrimitiveType.BOOL && fieldName.startsWith("is")) { - return fieldName; + if (type.isPrimitive() && (type.asPrimitive()).primitiveType() == PrimitiveType.BOOL) { + if (!fieldName.startsWith("is")) { + return "is" + firstUpStr(fieldName); + } + if (fieldName.length() <= 2) { + return "is" + firstUpStr(fieldName); + } + String third = fieldName.substring(2, 3); + if (third.toUpperCase().equals(third)) { + return fieldName; + } else { + return "is" + firstUpStr(fieldName); + } } else { return "get" + firstUpStr(fieldName); } } public static String fieldSetter(String fieldName, TarsType type) { - if (type.isPrimitive() && (type.asPrimitive()).primitiveType() == TarsPrimitiveType.PrimitiveType.BOOL && fieldName.startsWith("is")) { - return "set" + fieldName.substring(2); + if (type.isPrimitive() && (type.asPrimitive()).primitiveType() == PrimitiveType.BOOL) { + if (!fieldName.startsWith("is")) { + return "set" + firstUpStr(fieldName); + } + if (fieldName.length() <= 2) { + return "set" + firstUpStr(fieldName); + } + String third = fieldName.substring(2, 3); + if (third.toUpperCase().equals(third)) { + return "set" + firstUpStr(fieldName.substring(2)); + } else { + return "set" + firstUpStr(fieldName); + } } else { return "set" + firstUpStr(fieldName); } From 5dfa548a08d39d7868c34f369071cd5e0e07ffdb Mon Sep 17 00:00:00 2001 From: Kerrigan Date: Sun, 7 Jun 2020 19:51:22 +0800 Subject: [PATCH 13/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a8edc38..05fc9d15 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This project is the source code of the Tars RPC framework Java language. - + From 95e1fa09618168d557d635ca8d8ffc60b98d1e84 Mon Sep 17 00:00:00 2001 From: Kerrigan Date: Sun, 7 Jun 2020 19:51:48 +0800 Subject: [PATCH 14/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 05fc9d15..ba6c0080 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This project is the source code of the Tars RPC framework Java language. ### Environmental dependence - JDK1.8 or above -- Maven 2.2.1 or above +- Maven 3.5 or above ### From dbd1210bf5e0ca5896a22004b8d9fea1fcdd81d8 Mon Sep 17 00:00:00 2001 From: Katharine Date: Tue, 9 Jun 2020 15:55:03 +0800 Subject: [PATCH 15/16] upload LICENSE.md --- LICENSE.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..4cefdbed --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,157 @@ +# LICENSE + +Tencent is pleased to support the open source community by making Tars available. + +Copyright \(C\) 2016 THL A29 Limited, a Tencent company. All rights reserved. If you have downloaded a copy of the Tars binary from Tencent, please note that the Tars binary is licensed under the BSD 3-Clause License. + +If you have downloaded a copy of the Tars source code from Tencent, please note that Tars source code is licensed under the BSD 3-Clause License, except for the third-party components listed below which are subject to different license terms. Your integration of Tars into your own projects may require compliance with the BSD 3-Clause License, as well as the other licenses applicable to the third-party components included within Tars. + +A copy of the BSD 3-Clause License is included in this file. + +Other dependencies and licenses: + +## Open Source Software Licensed Under the Apache License, Version 2.0: + +1. Apache Tomcat 7.0.42 Copyright 1999-2013 The Apache Software Foundation +2. bootstrap-datepicker 1.7.0 Copyright 2012 Sebastien MALOT +3. grpc-java Copyright 2015 Google Inc. + +## Terms of the Apache License, Version 2.0: + +Apache License + +Version 2.0, January 2004 + +[http://www.apache.org/licenses/](http://www.apache.org/licenses/) + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means \(i\) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or \(ii\) ownership of fifty percent \(50%\) or more of the outstanding shares, or \(iii\) beneficial ownership of such entity. + +"You" \(or "Your"\) shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work \(an example is provided in the Appendix below\). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on \(or derived from\) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link \(or bind by name\) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +1. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. +2. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable \(except as stated in this section\) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution\(s\) alone or by combination of their Contribution\(s\) with the Work to which such Contribution\(s\) was submitted. If You institute patent litigation against any entity \(including a cross-claim or counterclaim in a lawsuit\) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. +3. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +a\) You must give any other recipients of the Work or Derivative Works a copy of this License; and + +b\) You must cause any modified files to carry prominent notices stating that You changed the files; and + +c\) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +d\) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +1. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. +2. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. +3. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work \(and each Contributor provides its Contributions\) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. +4. Limitation of Liability. In no event and under no legal theory, whether in tort \(including negligence\), contract, or otherwise, unless required by applicable law \(such as deliberate and grossly negligent acts\) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work \(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses\), even if such Contributor has been advised of the possibility of such damages. +5. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "\[\]" replaced with your own identifying information. \(Don't include the brackets!\) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright \[yyyy\] \[name of copyright owner\] + +Licensed 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](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. + +## Open Source Software Licensed Under the Boost Software License, Version 1.0: The below software in this distribution may have been modified by THL A29 Limited \("Tencent Modifications"\). All Tencent Modifications are Copyright \(C\) 2016 THL A29 Limited. + +1. Boost 1.53.0: + +\(1\) fcontext.hpp Copyright Oliver Kowalke 2009 + +\(2\) fcontext\_i386.hpp Copyright Oliver Kowalke 2009 + +\(3\) fcontext\_x86\_64.hpp Copyright Oliver Kowalke 2009 + +\(4\) jump\_i386\_sysv\_elf\_gas.S Copyright Oliver Kowalke 2009 + +\(5\) jump\_x86\_64\_sysv\_elf\_gas.S Copyright Oliver Kowalke 2009 + +\(6\) make\_i386\_sysv\_elf\_gas.S Copyright Oliver Kowalke 2009 + +\(7\) make\_x86\_64\_sysv\_elf\_gas.S Copyright Oliver Kowalke 2009 + +\(8\) tuple\_basic.hpp Copyright \(C\) 1999, 2000 Jaakko Jarvi \([jaakko.jarvi@cs.utu.fi](mailto:jaakko.jarvi@cs.utu.fi)\) + +## Terms of the Boost Software License, Version 1.0: + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license \(the "Software"\) to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Open Source Software Licensed Under the MIT License: + +1. jquery 1.9.1 Copyright 2012 jQuery Foundation and other contributors [http://jquery.com/](http://jquery.com/) +2. zTree 3.5.26 copyright \(c\) < hunter.z > +3. bootstrap 3.3.0 Copyright \(c\) 2011-2014 Twitter, Inc +4. bootstrap-table 1.11.0 Copyright \(c\) 2012-2016 Zhixin Wen [wenzhixin2010@gmail.com](mailto:wenzhixin2010@gmail.com) +5. Chart.js Copyright \(c\) 2013-2016 Nick Downie +6. mkdirp 0.5.0 Copyright 2010 James Halliday \([mail@substack.net](mailto:mail@substack.net)\) + +The below software \(7&8\) in this distribution may have been modified by THL A29 Limited \("Tencent Modifications"\). All Tencent Modifications are Copyright \(C\) 2016 THL A29 Limited. + +1. loki 0.1.7 Copyright \(c\) Andrei Alexandrescu, Jean-Francois Bastien, Guillaume Chatelet, Lukas Fittl, Fedor Pikus, Peter Kümmel, Rich Sposato +2. smhasher 0.150.1 Copyright \(c\) 2011 Austin Appleby \(Murmur3 routine\) Copyright \(c\) 2011 Patrick Hensley \(Python wrapper, packaging\) + +## Terms of the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files \(the "Software"\), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Open Source Software Licensed Under the BSD 3-Clause License: + +## The below software in this distribution may have been modified by THL A29 Limited \("Tencent Modifications"\). All Tencent Modifications are Copyright \(C\) 2016 THL A29 Limited. + +1. gperftools 2.0 Copyright \(c\) 2005, Google Inc. All rights reserved. +2. Chrominum 56.0.2884.2 + +\(1\) bind.h Copyright \(c\) 2011 The Chromium Authors. All rights reserved. + +\(2\) bind\_internal.h Copyright \(c\) 2011 The Chromium Authors. All rights reserved. + +\(3\) callback.h Copyright \(c\) 2012 The Chromium Authors. All rights reserved. + +\(4\) callback\_internal.h Copyright \(c\) 2012 The Chromium Authors. All rights reserved. + +\(5\) callback\_internal.cc Copyright \(c\) 2012 The Chromium Authors. All rights reserved. + +## Terms of the BSD 3-Clause License: + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of \[copyright holder\] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION\) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \(INCLUDING NEGLIGENCE OR OTHERWISE\) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + From 47f338cff3d995b6c3bd351c9939e22b01816e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E4=BD=B3=E6=95=8F?= Date: Tue, 9 Jun 2020 18:24:30 +0800 Subject: [PATCH 16/16] =?UTF-8?q?=E6=96=B0=E5=A2=9Etars=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=98=AFfloat=E5=B8=A6=E4=B8=8AF=E5=90=8E?= =?UTF-8?q?=E7=BC=80=EF=BC=9B=E4=BF=AE=E6=94=B9json=E5=8D=8F=E8=AE=AEversi?= =?UTF-8?q?on=E5=80=BC=EF=BC=9BHelloServer=20json=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- core/pom.xml | 8 ++-- .../java/com/qq/tars/common/util/JSON.java | 29 ++++++++++++ .../com/qq/tars/protocol/util/TarsHelper.java | 2 +- .../qq/tars/rpc/protocol/tars/TarsCodec.java | 36 +++++++++------ examples/quickstart-server/pom.xml | 10 ++++- .../server/testapp/HelloServant.java | 19 ++------ .../server/testapp/impl/HelloServantImpl.java | 44 +++++++++++++++++++ .../src/main/resources/hello.tars | 36 ++++++++++++++- .../qq/tars/maven/gensrc/Tars2JavaMojo.java | 19 +++++++- 10 files changed, 166 insertions(+), 39 deletions(-) create mode 100644 core/src/main/java/com/qq/tars/common/util/JSON.java diff --git a/.gitignore b/.gitignore index a9738701..75624740 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ target/ .project .classpath *.dat - +examples/**/testapp/ diff --git a/core/pom.xml b/core/pom.xml index 37e6af32..d08aa40a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -18,7 +18,7 @@ 0.31.1 2.7.4 1.2.3 - 1.2.62 + 2.8.6 @@ -64,9 +64,9 @@ - com.alibaba - fastjson - ${fastjson.version} + com.google.code.gson + gson + 2.8.2 diff --git a/core/src/main/java/com/qq/tars/common/util/JSON.java b/core/src/main/java/com/qq/tars/common/util/JSON.java new file mode 100644 index 00000000..4bba8db2 --- /dev/null +++ b/core/src/main/java/com/qq/tars/common/util/JSON.java @@ -0,0 +1,29 @@ +package com.qq.tars.common.util; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; + +import java.lang.reflect.Type; + +public class JSON { + private static final Gson gson = new Gson(); + + + public static String toJson(final Object obj) { + return gson.toJson(obj); + } + + public static T fromJson(final String str, Class cls) { + return gson.fromJson(str, cls); + } + + + public static JsonElement toJsonTree(final Object obj) { + return gson.toJsonTree(obj); + } + + + public static T fromJson(final String str, Type type) { + return gson.fromJson(str, type); + } +} diff --git a/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java b/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java index 2b4e99ad..9472ac49 100644 --- a/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java +++ b/core/src/main/java/com/qq/tars/protocol/util/TarsHelper.java @@ -62,7 +62,7 @@ public class TarsHelper { public static final short VERSION3 = 0x03; - public static final short VERSIONJSON = 0x09; + public static final short VERSIONJSON = 0x05; public static final byte NORMAL = 0x00; diff --git a/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java b/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java index 83c45e08..b82b42a3 100644 --- a/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java +++ b/core/src/main/java/com/qq/tars/rpc/protocol/tars/TarsCodec.java @@ -38,9 +38,10 @@ import com.qq.tars.rpc.protocol.tars.support.AnalystManager; import com.qq.tars.rpc.protocol.tup.UniAttribute; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.alibaba.fastjson.serializer.SerializerFeature; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import com.qq.tars.common.util.JSON; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; @@ -170,7 +171,7 @@ protected byte[] encodeJsonResult(TarsServantResponse response, String charsetNa } // 服务端接口响应 - JSONObject object = new JSONObject(); + JsonObject object = new JsonObject(); int ret = response.getRet(); Map methodInfoMap = AnalystManager.getInstance().getMethodMapByName(request.getServantName()); @@ -179,7 +180,9 @@ protected byte[] encodeJsonResult(TarsServantResponse response, String charsetNa TarsMethodParameterInfo returnInfo = methodInfo.getReturnInfo(); if (returnInfo != null && returnInfo.getType() != Void.TYPE && response.getResult() != null) { try { - object.put(TarsHelper.STAMP_STRING, response.getResult()); + JsonElement jsonElement = JSON.toJsonTree(response.getResult()); + // System.out.println("requestId: " + request.getRequestId() + ", charset: " + request.getCharsetName() + ", ret: " + jsonElement.toString()); + object.add(TarsHelper.STAMP_STRING, jsonElement); } catch (Exception e) { System.err.println("server encode json ret :" + response.getResult() + ", with ex:" + e); } @@ -192,7 +195,9 @@ protected byte[] encodeJsonResult(TarsServantResponse response, String charsetNa value = request.getMethodParameters()[parameterInfo.getOrder() - 1]; if (value != null) { try { - object.put(parameterInfo.getName(), TarsHelper.getHolderValue(value)); + JsonElement jsonElement = JSON.toJsonTree(TarsHelper.getHolderValue(value)); + // System.out.println("requestId: " + request.getRequestId() + ", charset: " + request.getCharsetName() + ", holder: " + jsonElement.toString()); + object.add(parameterInfo.getName(), jsonElement); } catch (Exception e) { System.err.println("server encode json holder :" + value + ", with ex:" + e); } @@ -395,6 +400,7 @@ public ServantRequest decodeRequestBody(ServantRequest req) { } else if (TarsHelper.VERSION2 == request.getVersion() || TarsHelper.VERSION3 == request.getVersion()) { parameters = decodeRequestWupBody(data, request.getVersion(), request.getCharsetName(), methodInfo); } else if (TarsHelper.VERSIONJSON == request.getVersion()) { + // System.out.println("requestId: " + request.getRequestId() + ", charset: " + request.getCharsetName() + ", data: " + new String(data, request.getCharsetName())); parameters = decodeRequestJsonBody(data, request.getCharsetName(), methodInfo); } else { request.setRet(TarsHelper.SERVERDECODEERR); @@ -479,7 +485,7 @@ protected Object[] decodeRequestWupBody(byte[] data, int version, String charset protected Object[] decodeRequestJsonBody(byte[] data, String charset, TarsMethodInfo methodInfo) throws Exception { // 解析json串 - JSONObject jsonObject = JSON.parseObject(new String(data, charset)); + JsonObject jsonObject = JSON.fromJson(new String(data, charset), JsonObject.class); // 按字段反序列化 int i = 0; @@ -490,18 +496,22 @@ protected Object[] decodeRequestJsonBody(byte[] data, String charset, for (TarsMethodParameterInfo parameterInfo : parametersList) { if (TarsHelper.isHolder(parameterInfo.getAnnotations())) { - if (jsonObject.containsKey(parameterInfo.getName())) { - value = new Holder<>(JSON.parseObject(jsonObject.get(parameterInfo.getName()).toString(), - parameterInfo.getType())); + if (jsonObject.has(parameterInfo.getName())) { + String reqStr = jsonObject.get(parameterInfo.getName()).toString(); + // System.out.println("holder has " + parameterInfo.getName() + ", str: " + reqStr); + value = new Holder<>(JSON.fromJson(reqStr, parameterInfo.getType())); } else { + // System.out.println("holder has no " + parameterInfo.getName()); // new response, can not use cache value = new Holder<>(TarsHelper.getNewParameterStamp(parameterInfo.getType())); } } else { - if (jsonObject.containsKey(parameterInfo.getName())) { - value = JSON.parseObject(jsonObject.get(parameterInfo.getName()).toString(), - parameterInfo.getType()); + if (jsonObject.has(parameterInfo.getName())) { + String reqStr = jsonObject.get(parameterInfo.getName()).toString(); + // System.out.println("request has " + parameterInfo.getName() + ", str: " + reqStr); + value = JSON.fromJson(reqStr, parameterInfo.getType()); } else { + System.out.println("request has no " + parameterInfo.getName() + ", exception."); throw new ProtocolException("no found parameter, the context[ROOT], " + "serviceName[" + methodInfo.getServiceName() + "], methodName[" + methodInfo.getMethodName() diff --git a/examples/quickstart-server/pom.xml b/examples/quickstart-server/pom.xml index 496348c3..79331d7f 100644 --- a/examples/quickstart-server/pom.xml +++ b/examples/quickstart-server/pom.xml @@ -13,6 +13,7 @@ UTF-8 2.2.1 3.2 + 1.0.2 @@ -21,6 +22,11 @@ ${project.parent.version} jar + + uk.org.lidalia + sysout-over-slf4j + ${sysout-over-slf4j.version} + webapp @@ -30,8 +36,8 @@ maven-compiler-plugin 2.3.1 - 1.6 - 1.6 + 1.8 + 1.8 UTF8 diff --git a/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/HelloServant.java b/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/HelloServant.java index 9a3971ae..a933cc2f 100644 --- a/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/HelloServant.java +++ b/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/HelloServant.java @@ -1,18 +1,3 @@ -/** - * Tencent is pleased to support the open source community by making Tars available. - * - * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * 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. - */ // ********************************************************************** // This file was generated by a TARS parser! // TARS version 1.0.1. @@ -27,5 +12,7 @@ @Servant public interface HelloServant { - public String hello(int no, String name); + String hello(@TarsMethodParameter(name="no")int no, @TarsMethodParameter(name="name")String name); + + int helloJson(@TarsMethodParameter(name="tie")TestInfo tie, @TarsHolder(name="otie") Holder otie); } diff --git a/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/impl/HelloServantImpl.java b/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/impl/HelloServantImpl.java index f5dc60e7..db741d8a 100644 --- a/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/impl/HelloServantImpl.java +++ b/examples/quickstart-server/src/main/java/com/qq/tars/quickstart/server/testapp/impl/HelloServantImpl.java @@ -16,12 +16,56 @@ package com.qq.tars.quickstart.server.testapp.impl; +import ch.qos.logback.classic.Logger; +import com.qq.tars.common.support.Holder; +import com.qq.tars.protocol.tars.annotation.TarsMethodParameter; import com.qq.tars.quickstart.server.testapp.HelloServant; +import com.qq.tars.quickstart.server.testapp.TestInfo; +import com.qq.tars.quickstart.server.testapp.TestInfoEx; +import com.qq.tars.support.log.LoggerFactory; +import java.util.ArrayList; +import java.util.HashMap; +import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J; public class HelloServantImpl implements HelloServant { + private static Logger logger = LoggerFactory.getLogger("hello"); + + public HelloServantImpl() { + SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); + } + @Override public String hello(int no, String name) { return String.format("hello no=%s, name=%s, time=%s", no, name, System.currentTimeMillis()); } + + @Override + public int helloJson(TestInfo tie, Holder otie) { + logger.info("ready to hello Json. s: {}, f: {}, d: {}", tie.s, tie.f, tie.d); + + if (otie.value == null) { + logger.info("hello Json. holder value is null."); + otie.value = new TestInfoEx(); + } + + otie.value.bi = tie; + otie.value.bi.s += otie.value.bi.s; + otie.value.bi.f += otie.value.bi.f; + otie.value.bi.d += otie.value.bi.d; + + otie.value.mbi = new HashMap<>(2); + otie.value.mbi.put("A", otie.value.bi); + otie.value.mbi.put("B", otie.value.bi); + + otie.value.vbi = new ArrayList<>(2); + otie.value.vbi.add(otie.value.bi); + otie.value.vbi.add(otie.value.bi); + + logger.info("succ. to hello Json. s: {}, f: {}, d: {}", tie.s, tie.f, tie.d); + + return 0; + } + + } diff --git a/examples/quickstart-server/src/main/resources/hello.tars b/examples/quickstart-server/src/main/resources/hello.tars index da273654..3f39a64f 100644 --- a/examples/quickstart-server/src/main/resources/hello.tars +++ b/examples/quickstart-server/src/main/resources/hello.tars @@ -16,8 +16,42 @@ module TestApp { + enum ENUM_TYPE { + ET_A, + ET_B, + }; + + struct TestInfo + { + 0 optional byte c = 1; + 1 optional short i1 = 2; + 2 optional int i2 = 3; + 3 optional long l = 4; + 4 optional float f = 5.0f; + 5 optional double d = 6.1d; + 6 optional string s = "test"; + 7 optional vector vs; + 8 optional map ms; + 9 optional vector vd; + 10 optional map mfd; + 11 optional ENUM_TYPE et; + 12 optional bool b = true; + 13 optional bool is = false; + 14 optional bool isBool = true; + 15 optional bool isbool = false; + 16 require string rstr; + }; + + struct TestInfoEx + { + 0 optional TestInfo bi; + 1 optional vector vbi; + 2 optional map mbi; + }; + interface Hello { string hello(int no, string name); + int helloJson(TestInfo tie, out TestInfoEx otie); }; -}; \ No newline at end of file +}; diff --git a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java index c47da113..139e2334 100644 --- a/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java +++ b/tools/tars-maven-plugin/src/main/java/com/qq/tars/maven/gensrc/Tars2JavaMojo.java @@ -264,7 +264,24 @@ private void genStruct(String dirPath, String packageName, String namespace, Tar // 定义成员变量 for (TarsStructMember m : struct.memberList()) { out.println("\t@TarsStructProperty(order = " + m.tag() + ", isRequire = " + m.isRequire() + ")"); - out.println("\tpublic " + type(m.memberType(), nsMap) + " " + m.memberName() + " = " + (m.defaultValue() == null ? typeInit(m.memberType(), nsMap, false) : m.defaultValue()) + ";"); + String defaultValue = (m.defaultValue() == null ? typeInit(m.memberType(), nsMap, false) : m.defaultValue()); + if (m.memberType().isPrimitive()) { + TarsPrimitiveType primitiveType = m.memberType().asPrimitive(); + if (primitiveType.primitiveType().equals(PrimitiveType.LONG)) { + if (!defaultValue.endsWith("l") && !defaultValue.endsWith("L")) { + defaultValue = defaultValue + "L"; + } + } else if (primitiveType.primitiveType().equals(PrimitiveType.FLOAT)) { + if (!defaultValue.endsWith("f") && !defaultValue.endsWith("F")) { + defaultValue = defaultValue + "F"; + } + } else if (primitiveType.primitiveType().equals(PrimitiveType.DOUBLE)) { + if (!defaultValue.endsWith("d") && !defaultValue.endsWith("D")) { + defaultValue = defaultValue + "D"; + } + } + } + out.println("\tpublic " + type(m.memberType(), nsMap) + " " + m.memberName() + " = " + defaultValue + ";"); } out.println();
Homepage:tarscloud.orgtarscloud.org
中文版: