Protobuf service definition and serialization support

This commit is contained in:
ken.lj 2019-09-17 15:50:18 +08:00
parent 0dad8290ea
commit 6b86651ee7
91 changed files with 2556 additions and 1225 deletions

4
.gitignore vendored
View File

@ -37,5 +37,5 @@ Thumbs.db
license-list.txt
# grpc compiler
dubbo-rpc/dubbo-rpc-grpc/compiler/gradle.properties
dubbo-rpc/dubbo-rpc-grpc/compiler/build/*
compiler/gradle.properties
compiler/build/*

View File

@ -227,4 +227,4 @@ This product contains a modified portion of 'edazdarevic.commons.net.CIDRUtils',
This product contains a modified portion of 'proto-gen-grpc-java' - a protobuf plugin used to generate grpc-java stubs,
under a "Apache License 2.0" license, see https://github.com/grpc/grpc-java/blob/v1.22.1/NOTICE.txt. All files are placed
under '/dubbo/dubbo-rpc/dubbo-rpc-grpc/compiler'
under '/dubbo/compiler'

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,97 @@
# Dubbo customized version
## 修改内容
## Get Started, how to use
1. Add maven dependency
```xml
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>org.apache.dubbo:protoc-gen-grpc-java:${proto_dubbo_plugin_version}:exe:${os.detected.classifier}</pluginArtifact>
<outputDirectory>build/generated/source/proto/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
<!-- supports 'dubbo' and 'grpc' -->
<pluginParameter>dubbo</pluginParameter>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
<goal>test-compile</goal>
<goal>test-compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>build/generated/source/proto/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
```
2. Decide which protocol to use: Dubbo or gRPC
* Dubbo, ` <pluginParameter>dubbo</pluginParameter>`
* gRPC, ` <pluginParameter>grpc</pluginParameter>`
3. Define service using IDL
```text
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.apache.dubbo.demo";
option java_outer_classname = "DemoServiceProto";
option objc_class_prefix = "DEMOSRV";
package demoservice;
// The demo service definition.
service DemoService {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
```
4. Build
mvn clean compile
## Customized
1. Dubbo Interface
```java
@ -81,7 +172,7 @@ public static abstract class GreeterImplBase implements io.grpc.BindableService,
}
```
## 如何构建
## Build locally
To compile the plugin:
```
@ -93,7 +184,7 @@ To publish to local repository
$ ../gradlew publishToMavenLocal
```
## 远程发布
## Publish to maven repository
Add gradle.properties
```properties
@ -108,64 +199,4 @@ $ ../gradlew publishMavenPublicationToDubboRepository
Notice current groupId is `com.alibaba`.
gRPC Java Codegen Plugin for Protobuf Compiler
==============================================
This generates the Java interfaces out of the service definition from a
`.proto` file. It works with the Protobuf Compiler (``protoc``).
Normally you don't need to compile the codegen by yourself, since pre-compiled
binaries for common platforms are available on Maven Central. However, if the
pre-compiled binaries are not compatible with your system, you may want to
build your own codegen.
## System requirement
* Linux, Mac OS X with Clang, or Windows with MSYS2
* Java 7 or up
* [Protobuf](https://github.com/google/protobuf) 3.0.0-beta-3 or up
## Compiling and testing the codegen
Change to the `compiler` directory:
```
$ cd $GRPC_JAVA_ROOT/compiler
```
To compile the plugin:
```
$ ../gradlew java_pluginExecutable
```
To test the plugin with the compiler:
```
$ ../gradlew test
```
You will see a `PASS` if the test succeeds.
To compile a proto file and generate Java interfaces out of the service definitions:
```
$ protoc --plugin=protoc-gen-grpc-java=build/exe/java_plugin/protoc-gen-grpc-java \
--grpc-java_out="$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" "$PROTO_FILE"
```
To generate Java interfaces with protobuf lite:
```
$ protoc --plugin=protoc-gen-grpc-java=build/exe/java_plugin/protoc-gen-grpc-java \
--grpc-java_out=lite:"$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" "$PROTO_FILE"
```
To generate Java interfaces with protobuf nano:
```
$ protoc --plugin=protoc-gen-grpc-java=build/exe/java_plugin/protoc-gen-grpc-java \
--grpc-java_out=nano:"$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" "$PROTO_FILE"
```
## Installing the codegen to Maven local repository
This will compile a codegen and put it under your ``~/.m2/repository``. This
will make it available to any build tool that pulls codegens from Maven
repostiories.
```
$ ../gradlew publishToMavenLocal
```
## Creating a release of GRPC Java
Please follow the instructions in ``RELEASING.md`` under the root directory for
details on how to create a new release.
Check [here](https://github.com/grpc/grpc-java/blob/master/compiler/README.md) for basic requirements and usage of protoc plugin.

View File

@ -69,7 +69,7 @@ def boolean usingVisualCpp // Whether VisualCpp is actually available and select
ext{
def exeSuffix = osdetector.os == 'windows' ? ".exe" : ""
protocPluginBaseName = 'protoc-gen-grpc-java'
protocPluginBaseName = 'protoc-gen-dubbo-java'
javaPluginPath = "$rootDir/build/exe/java_plugin/$protocPluginBaseName$exeSuffix"
nettyVersion = '4.1.32.Final'
@ -191,12 +191,6 @@ configurations {
testNanoCompile
}
//dependencies {
// testCompile "io.grpc:grpc-protobuf:1.22.1",
// "io.grpc:grpc-stub:1.22.1",
// "javax.annotation:javax.annotation-api:1.2"
//}
sourceSets {
testLite {
proto { setSrcDirs(['src/test/proto']) }
@ -279,13 +273,13 @@ checkstyleTestNano {
}
println "*** Building codegen requires Protobuf version ${protocVersion}"
println "*** Please refer to https://github.com/grpc/grpc-java/blob/master/COMPILING.md#how-to-build-code-generation-plugin"
println "*** Please refer to https://github.com/apache/dubbo/blob/master/compiler/README.md"
task buildArtifacts(type: Copy) {
dependsOn 'java_pluginExecutable'
from("$buildDir/exe") {
if (osdetector.os != 'windows') {
rename 'protoc-gen-grpc-java', '$0.exe'
rename 'protoc-gen-dubbo-java', '$0.exe'
}
}
into artifactStagingPath
@ -359,7 +353,7 @@ publishing {
maven(MavenPublication) {
// Removes all artifacts since grpc-compiler doesn't generates any Jar
artifacts = []
artifactId 'protoc-gen-grpc-java'
artifactId 'protoc-gen-dubbo-java'
artifact("$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" as File) {
classifier osdetector.os + "-" + arch
extension "exe"

View File

@ -127,5 +127,5 @@ checkDependencies ()
echo
}
FILE="build/artifacts/java_plugin/protoc-gen-grpc-java.exe"
FILE="build/artifacts/java_plugin/protoc-gen-dubbo-java.exe"
checkArch "$FILE" && checkDependencies "$FILE"

View File

@ -0,0 +1,572 @@
#include "java_generator.h"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <set>
#include <vector>
#include <google/protobuf/compiler/java/java_names.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
// Stringify helpers used solely to cast GRPC_VERSION
#ifndef STR
#define STR(s) #s
#endif
#ifndef XSTR
#define XSTR(s) STR(s)
#endif
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED
#endif
namespace java_dubbo_generator {
using google::protobuf::FileDescriptor;
using google::protobuf::ServiceDescriptor;
using google::protobuf::MethodDescriptor;
using google::protobuf::Descriptor;
using google::protobuf::io::Printer;
using google::protobuf::SourceLocation;
using std::to_string;
// java keywords from: https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.9
static std::set<string> java_keywords = {
"abstract",
"assert",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extends",
"final",
"finally",
"float",
"for",
"goto",
"if",
"implements",
"import",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"strictfp",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"try",
"void",
"volatile",
"while",
// additional ones added by us
"true",
"false",
};
// Adjust a method name prefix identifier to follow the JavaBean spec:
// - decapitalize the first letter
// - remove embedded underscores & capitalize the following letter
// Finally, if the result is a reserved java keyword, append an underscore.
static string MixedLower(const string& word) {
string w;
w += tolower(word[0]);
bool after_underscore = false;
for (size_t i = 1; i < word.length(); ++i) {
if (word[i] == '_') {
after_underscore = true;
} else {
w += after_underscore ? toupper(word[i]) : word[i];
after_underscore = false;
}
}
if (java_keywords.find(w) != java_keywords.end()) {
return w + "_";
}
return w;
}
// Converts to the identifier to the ALL_UPPER_CASE format.
// - An underscore is inserted where a lower case letter is followed by an
// upper case letter.
// - All letters are converted to upper case
static string ToAllUpperCase(const string& word) {
string w;
for (size_t i = 0; i < word.length(); ++i) {
w += toupper(word[i]);
if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) {
w += '_';
}
}
return w;
}
static inline string LowerMethodName(const MethodDescriptor* method) {
return MixedLower(method->name());
}
static inline string MethodPropertiesFieldName(const MethodDescriptor* method) {
return "METHOD_" + ToAllUpperCase(method->name());
}
static inline string MethodPropertiesGetterName(const MethodDescriptor* method) {
return MixedLower("get_" + method->name() + "_method");
}
static inline string MethodIdFieldName(const MethodDescriptor* method) {
return "METHODID_" + ToAllUpperCase(method->name());
}
static inline bool ShouldGenerateAsLite(const Descriptor* desc) {
return false;
}
static inline string MessageFullJavaName(bool nano, const Descriptor* desc) {
string name = google::protobuf::compiler::java::ClassName(desc);
if (nano && !ShouldGenerateAsLite(desc)) {
// XXX: Add "nano" to the original package
// (https://github.com/grpc/grpc-java/issues/900)
if (isupper(name[0])) {
// No java package specified.
return "nano." + name;
}
for (size_t i = 0; i < name.size(); ++i) {
if ((name[i] == '.') && (i < (name.size() - 1)) && isupper(name[i + 1])) {
return name.substr(0, i + 1) + "nano." + name.substr(i + 1);
}
}
}
return name;
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
template <typename ITR>
static void GrpcSplitStringToIteratorUsing(const string& full,
const char* delim,
ITR& result) {
// Optimize the common case where delim is a single character.
if (delim[0] != '\0' && delim[1] == '\0') {
char c = delim[0];
const char* p = full.data();
const char* end = p + full.size();
while (p != end) {
if (*p == c) {
++p;
} else {
const char* start = p;
while (++p != end && *p != c);
*result++ = string(start, p - start);
}
}
return;
}
string::size_type begin_index, end_index;
begin_index = full.find_first_not_of(delim);
while (begin_index != string::npos) {
end_index = full.find_first_of(delim, begin_index);
if (end_index == string::npos) {
*result++ = full.substr(begin_index);
return;
}
*result++ = full.substr(begin_index, (end_index - begin_index));
begin_index = full.find_first_not_of(delim, end_index);
}
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static void GrpcSplitStringUsing(const string& full,
const char* delim,
std::vector<string>* result) {
std::back_insert_iterator< std::vector<string> > it(*result);
GrpcSplitStringToIteratorUsing(full, delim, it);
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static std::vector<string> GrpcSplit(const string& full, const char* delim) {
std::vector<string> result;
GrpcSplitStringUsing(full, delim, &result);
return result;
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static string GrpcEscapeJavadoc(const string& input) {
string result;
result.reserve(input.size() * 2);
char prev = '*';
for (string::size_type i = 0; i < input.size(); i++) {
char c = input[i];
switch (c) {
case '*':
// Avoid "/*".
if (prev == '/') {
result.append("&#42;");
} else {
result.push_back(c);
}
break;
case '/':
// Avoid "*/".
if (prev == '*') {
result.append("&#47;");
} else {
result.push_back(c);
}
break;
case '@':
// '@' starts javadoc tags including the @deprecated tag, which will
// cause a compile-time error if inserted before a declaration that
// does not have a corresponding @Deprecated annotation.
result.append("&#64;");
break;
case '<':
// Avoid interpretation as HTML.
result.append("&lt;");
break;
case '>':
// Avoid interpretation as HTML.
result.append("&gt;");
break;
case '&':
// Avoid interpretation as HTML.
result.append("&amp;");
break;
case '\\':
// Java interprets Unicode escape sequences anywhere!
result.append("&#92;");
break;
default:
result.push_back(c);
break;
}
prev = c;
}
return result;
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
template <typename DescriptorType>
static string GrpcGetCommentsForDescriptor(const DescriptorType* descriptor) {
SourceLocation location;
if (descriptor->GetSourceLocation(&location)) {
return location.leading_comments.empty() ?
location.trailing_comments : location.leading_comments;
}
return string();
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static std::vector<string> GrpcGetDocLines(const string& comments) {
if (!comments.empty()) {
// TODO(kenton): Ideally we should parse the comment text as Markdown and
// write it back as HTML, but this requires a Markdown parser. For now
// we just use <pre> to get fixed-width text formatting.
// If the comment itself contains block comment start or end markers,
// HTML-escape them so that they don't accidentally close the doc comment.
string escapedComments = GrpcEscapeJavadoc(comments);
std::vector<string> lines = GrpcSplit(escapedComments, "\n");
while (!lines.empty() && lines.back().empty()) {
lines.pop_back();
}
return lines;
}
return std::vector<string>();
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
template <typename DescriptorType>
static std::vector<string> GrpcGetDocLinesForDescriptor(const DescriptorType* descriptor) {
return GrpcGetDocLines(GrpcGetCommentsForDescriptor(descriptor));
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static void GrpcWriteDocCommentBody(Printer* printer,
const std::vector<string>& lines,
bool surroundWithPreTag) {
if (!lines.empty()) {
if (surroundWithPreTag) {
printer->Print(" * <pre>\n");
}
for (size_t i = 0; i < lines.size(); i++) {
// Most lines should start with a space. Watch out for lines that start
// with a /, since putting that right after the leading asterisk will
// close the comment.
if (!lines[i].empty() && lines[i][0] == '/') {
printer->Print(" * $line$\n", "line", lines[i]);
} else {
printer->Print(" *$line$\n", "line", lines[i]);
}
}
if (surroundWithPreTag) {
printer->Print(" * </pre>\n");
}
}
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static void GrpcWriteDocComment(Printer* printer, const string& comments) {
printer->Print("/**\n");
std::vector<string> lines = GrpcGetDocLines(comments);
GrpcWriteDocCommentBody(printer, lines, false);
printer->Print(" */\n");
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
static void GrpcWriteServiceDocComment(Printer* printer,
const ServiceDescriptor* service) {
// Deviating from protobuf to avoid extraneous docs
// (see https://github.com/google/protobuf/issues/1406);
printer->Print("/**\n");
std::vector<string> lines = GrpcGetDocLinesForDescriptor(service);
GrpcWriteDocCommentBody(printer, lines, true);
printer->Print(" */\n");
}
// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
void GrpcWriteMethodDocComment(Printer* printer,
const MethodDescriptor* method) {
// Deviating from protobuf to avoid extraneous docs
// (see https://github.com/google/protobuf/issues/1406);
printer->Print("/**\n");
std::vector<string> lines = GrpcGetDocLinesForDescriptor(method);
GrpcWriteDocCommentBody(printer, lines, true);
printer->Print(" */\n");
}
enum StubType {
ASYNC_INTERFACE = 0,
BLOCKING_CLIENT_INTERFACE = 1,
FUTURE_CLIENT_INTERFACE = 2,
BLOCKING_SERVER_INTERFACE = 3,
ASYNC_CLIENT_IMPL = 4,
BLOCKING_CLIENT_IMPL = 5,
FUTURE_CLIENT_IMPL = 6,
ABSTRACT_CLASS = 7,
};
enum CallType {
ASYNC_CALL = 0,
BLOCKING_CALL = 1,
FUTURE_CALL = 2
};
static void PrintMarshallerStaticBlock(const ServiceDescriptor* service,
std::map<string, string>* vars,
Printer* p) {
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
(*vars)["input_type"] = google::protobuf::compiler::java::ClassName(method->input_type());
(*vars)["output_type"] = google::protobuf::compiler::java::ClassName(method->output_type());
p->Print(
*vars,
"private static final AtomicBoolean registered = new AtomicBoolean();\n\n");
p->Print(
*vars,
"static {\n"
" if (registered.compareAndSet(false, true)) {\n"
" $ProtobufUtils$.marshaller(\n"
" $input_type$.getDefaultInstance());\n"
" $ProtobufUtils$.marshaller(\n"
" $output_type$.getDefaultInstance());\n"
" }\n"
"}\n\n");
}
}
static void PrintDubboInterface(
const ServiceDescriptor* service,
std::map<string, string>* vars,
Printer* p, bool generate_nano) {
const string service_name = service->name();
(*vars)["service_name"] = service_name;
(*vars)["dubbo_interface"] = "I" + service_name;
p->Print(
"/**\n "
"* Code generated for Dubbo\n "
"*/\n"
);
p->Print(
*vars,
"public interface $dubbo_interface$ {\n\n");
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
(*vars)["input_type"] = MessageFullJavaName(generate_nano,
method->input_type());
(*vars)["output_type"] = MessageFullJavaName(generate_nano,
method->output_type());
(*vars)["lower_method_name"] = LowerMethodName(method);
// Simple RPC
p->Print(
*vars,
"$output_type$ $lower_method_name$($input_type$ request);\n\n");
// Simple Future RPC
p->Print(
*vars,
"$CompletableFuture$<$output_type$> $lower_method_name$Async(\n$input_type$ request);\n\n");
// p->Print(
// *vars,
// "default $CompletableFuture$<$output_type$> $lower_method_name$Async(\n"
// " $input_type$ request) {\n return CompletableFuture.completedFuture($lower_method_name$(request));\n}\n\n");
p->Outdent();
}
p->Outdent();
p->Print("}\n\n");
}
static void PrintService(const ServiceDescriptor* service,
std::map<string, string>* vars,
Printer* p,
bool disable_version) {
(*vars)["service_name"] = service->name();
(*vars)["file_name"] = service->file()->name();
(*vars)["service_class_name"] = ServiceClassName(service);
(*vars)["grpc_version"] = "";
#ifdef GRPC_VERSION
if (!disable_version) {
(*vars)["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")";
}
#endif
// TODO(nmittler): Replace with WriteServiceDocComment once included by protobuf distro.
GrpcWriteServiceDocComment(p, service);
p->Print(
*vars,
"@$Generated$(\n"
" value = \"by gRPC proto compiler$grpc_version$\",\n"
" comments = \"Source: $file_name$\")\n");
if (service->options().deprecated()) {
p->Print(*vars, "@$Deprecated$\n");
}
p->Print(
*vars,
"public final class $service_class_name$ {\n\n");
p->Indent();
PrintMarshallerStaticBlock(service, vars, p);
p->Print(
*vars,
"private $service_class_name$() {}\n\n");
p->Print(
*vars,
"public static final String SERVICE_NAME = "
"\"$Package$$service_name$\";\n\n");
PrintDubboInterface(service, vars, p, false);
p->Outdent();
p->Print("}\n");
}
void PrintImports(Printer* p) {
p->Print(
"import "
"java.util.concurrent.CompletableFuture;\n");
p->Print(
"import "
"java.util.concurrent.atomic.AtomicBoolean;\n");
}
void GenerateService(const ServiceDescriptor* service,
google::protobuf::io::ZeroCopyOutputStream* out,
ProtoFlavor flavor,
bool disable_version) {
// All non-generated classes must be referred by fully qualified names to
// avoid collision with generated classes.
std::map<string, string> vars;
vars["String"] = "java.lang.String";
vars["Deprecated"] = "java.lang.Deprecated";
vars["Override"] = "java.lang.Override";
vars["Iterator"] = "java.util.Iterator";
vars["Generated"] = "javax.annotation.Generated";
vars["CompletableFuture"] =
"java.util.concurrent.CompletableFuture";
vars["AtomicBoolean"] =
"java.util.concurrent.atomic.AtomicBoolean";
vars["ProtobufUtils"] =
"org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils";
Printer printer(out, '$');
string package_name = ServiceJavaPackage(service->file(),false);
if (!package_name.empty()) {
printer.Print(
"package $package_name$;\n\n",
"package_name", package_name);
}
PrintImports(&printer);
// Package string is used to fully qualify method names.
vars["Package"] = service->file()->package();
if (!vars["Package"].empty()) {
vars["Package"].append(".");
}
PrintService(service, &vars, &printer, false);
}
string ServiceJavaPackage(const FileDescriptor* file, bool nano) {
string result = google::protobuf::compiler::java::ClassName(file);
size_t last_dot_pos = result.find_last_of('.');
if (last_dot_pos != string::npos) {
result.resize(last_dot_pos);
} else {
result = "";
}
if (nano) {
if (!result.empty()) {
result += ".";
}
result += "nano";
}
return result;
}
string ServiceClassName(const google::protobuf::ServiceDescriptor* service) {
return service->name() + "Dubbo";
}
} // namespace java_dubbo_generator

View File

@ -1182,105 +1182,105 @@ static void PrintMethodHandlerClass(const ServiceDescriptor* service,
}
static void PrintGetServiceDescriptorMethod(const ServiceDescriptor* service,
std::map<string, string>* vars,
Printer* p,
ProtoFlavor flavor) {
(*vars)["service_name"] = service->name();
std::map<string, string>* vars,
Printer* p,
ProtoFlavor flavor) {
(*vars)["service_name"] = service->name();
if (flavor == ProtoFlavor::NORMAL) {
(*vars)["proto_base_descriptor_supplier"] = service->name() + "BaseDescriptorSupplier";
(*vars)["proto_file_descriptor_supplier"] = service->name() + "FileDescriptorSupplier";
(*vars)["proto_method_descriptor_supplier"] = service->name() + "MethodDescriptorSupplier";
(*vars)["proto_class_name"] = google::protobuf::compiler::java::ClassName(service->file());
p->Print(
*vars,
"private static abstract class $proto_base_descriptor_supplier$\n"
" implements $ProtoFileDescriptorSupplier$, $ProtoServiceDescriptorSupplier$ {\n"
" $proto_base_descriptor_supplier$() {}\n"
"\n"
" @$Override$\n"
" public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {\n"
" return $proto_class_name$.getDescriptor();\n"
" }\n"
"\n"
" @$Override$\n"
" public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {\n"
" return getFileDescriptor().findServiceByName(\"$service_name$\");\n"
" }\n"
"}\n"
"\n"
"private static final class $proto_file_descriptor_supplier$\n"
" extends $proto_base_descriptor_supplier$ {\n"
" $proto_file_descriptor_supplier$() {}\n"
"}\n"
"\n"
"private static final class $proto_method_descriptor_supplier$\n"
" extends $proto_base_descriptor_supplier$\n"
" implements $ProtoMethodDescriptorSupplier$ {\n"
" private final String methodName;\n"
"\n"
" $proto_method_descriptor_supplier$(String methodName) {\n"
" this.methodName = methodName;\n"
" }\n"
"\n"
" @$Override$\n"
" public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {\n"
" return getServiceDescriptor().findMethodByName(methodName);\n"
" }\n"
"}\n\n");
}
if (flavor == ProtoFlavor::NORMAL) {
(*vars)["proto_base_descriptor_supplier"] = service->name() + "BaseDescriptorSupplier";
(*vars)["proto_file_descriptor_supplier"] = service->name() + "FileDescriptorSupplier";
(*vars)["proto_method_descriptor_supplier"] = service->name() + "MethodDescriptorSupplier";
(*vars)["proto_class_name"] = google::protobuf::compiler::java::ClassName(service->file());
p->Print(
*vars,
"private static abstract class $proto_base_descriptor_supplier$\n"
" implements $ProtoFileDescriptorSupplier$, $ProtoServiceDescriptorSupplier$ {\n"
" $proto_base_descriptor_supplier$() {}\n"
"\n"
" @$Override$\n"
" public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {\n"
" return $proto_class_name$.getDescriptor();\n"
" }\n"
"\n"
" @$Override$\n"
" public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {\n"
" return getFileDescriptor().findServiceByName(\"$service_name$\");\n"
" }\n"
"}\n"
"\n"
"private static final class $proto_file_descriptor_supplier$\n"
" extends $proto_base_descriptor_supplier$ {\n"
" $proto_file_descriptor_supplier$() {}\n"
"}\n"
"\n"
"private static final class $proto_method_descriptor_supplier$\n"
" extends $proto_base_descriptor_supplier$\n"
" implements $ProtoMethodDescriptorSupplier$ {\n"
" private final String methodName;\n"
"\n"
" $proto_method_descriptor_supplier$(String methodName) {\n"
" this.methodName = methodName;\n"
" }\n"
"\n"
" @$Override$\n"
" public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {\n"
" return getServiceDescriptor().findMethodByName(methodName);\n"
" }\n"
"}\n\n");
}
p->Print(
*vars,
"private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n");
p->Print(
*vars,
"private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n");
p->Print(
*vars,
"public static $ServiceDescriptor$ getServiceDescriptor() {\n");
p->Indent();
p->Print(
*vars,
"$ServiceDescriptor$ result = serviceDescriptor;\n");
p->Print("if (result == null) {\n");
p->Indent();
p->Print(
*vars,
"synchronized ($service_class_name$.class) {\n");
p->Indent();
p->Print("result = serviceDescriptor;\n");
p->Print("if (result == null) {\n");
p->Indent();
p->Print(
*vars,
"public static $ServiceDescriptor$ getServiceDescriptor() {\n");
p->Indent();
p->Print(
*vars,
"$ServiceDescriptor$ result = serviceDescriptor;\n");
p->Print("if (result == null) {\n");
p->Indent();
p->Print(
*vars,
"synchronized ($service_class_name$.class) {\n");
p->Indent();
p->Print("result = serviceDescriptor;\n");
p->Print("if (result == null) {\n");
p->Indent();
p->Print(
*vars,
"serviceDescriptor = result = $ServiceDescriptor$.newBuilder(SERVICE_NAME)");
p->Indent();
p->Indent();
if (flavor == ProtoFlavor::NORMAL) {
p->Print(
*vars,
"\n.setSchemaDescriptor(new $proto_file_descriptor_supplier$())");
}
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
(*vars)["method_method_name"] = MethodPropertiesGetterName(method);
p->Print(*vars, "\n.addMethod($method_method_name$())");
}
p->Print("\n.build();\n");
p->Outdent();
p->Outdent();
p->Print(
*vars,
"serviceDescriptor = result = $ServiceDescriptor$.newBuilder(SERVICE_NAME)");
p->Indent();
p->Indent();
if (flavor == ProtoFlavor::NORMAL) {
p->Print(
*vars,
"\n.setSchemaDescriptor(new $proto_file_descriptor_supplier$())");
}
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
(*vars)["method_method_name"] = MethodPropertiesGetterName(method);
p->Print(*vars, "\n.addMethod($method_method_name$())");
}
p->Print("\n.build();\n");
p->Outdent();
p->Outdent();
p->Outdent();
p->Print("}\n");
p->Outdent();
p->Print("}\n");
p->Outdent();
p->Print("}\n");
p->Print("return result;\n");
p->Outdent();
p->Print("}\n");
}
p->Outdent();
p->Print("}\n");
p->Outdent();
p->Print("}\n");
p->Outdent();
p->Print("}\n");
p->Print("return result;\n");
p->Outdent();
p->Print("}\n");
}
static void PrintBindServiceMethodBody(const ServiceDescriptor* service,
std::map<string, string>* vars,

View File

@ -54,4 +54,25 @@ void GenerateService(const google::protobuf::ServiceDescriptor* service,
} // namespace java_grpc_generator
namespace java_dubbo_generator {
enum ProtoFlavor {
NORMAL
};
// Returns the package name of the Dubbo services defined in the given file.
string ServiceJavaPackage(const google::protobuf::FileDescriptor* file, bool nano);
// Returns the name of the outer class that wraps in all the generated code for
// the given service.
string ServiceClassName(const google::protobuf::ServiceDescriptor* service);
// Writes the generated service interface into the given ZeroCopyOutputStream
void GenerateService(const google::protobuf::ServiceDescriptor* service,
google::protobuf::io::ZeroCopyOutputStream* out,
ProtoFlavor flavor,
bool disable_version);
} // namespace java_dubbo_generator
#endif // NET_GRPC_COMPILER_JAVA_GENERATOR_H_

View File

@ -0,0 +1,87 @@
// Generates Java gRPC service interface out of Protobuf IDL.
//
// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto
// and net/proto2/compiler/public/plugin.h for more information on plugins.
#include <memory>
#include "java_generator.h"
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream.h>
static string JavaPackageToDir(const string& package_name) {
string package_dir = package_name;
for (size_t i = 0; i < package_dir.size(); ++i) {
if (package_dir[i] == '.') {
package_dir[i] = '/';
}
}
if (!package_dir.empty()) package_dir += "/";
return package_dir;
}
class JavaGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
public:
JavaGrpcGenerator() {}
virtual ~JavaGrpcGenerator() {}
virtual bool Generate(const google::protobuf::FileDescriptor* file,
const string& parameter,
google::protobuf::compiler::GeneratorContext* context,
string* error) const {
std::vector<std::pair<string, string> > options;
google::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
string DUBBO("dubbo");
if (DUBBO == parameter) {
string package_name = java_dubbo_generator::ServiceJavaPackage(
file, false);
string package_filename = JavaPackageToDir(package_name);
for (int i = 0; i < file->service_count(); ++i) {
const google::protobuf::ServiceDescriptor* service = file->service(i);
string filename = package_filename
+ java_dubbo_generator::ServiceClassName(service) + ".java";
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
context->Open(filename));
java_dubbo_generator::GenerateService(
service, output.get(), java_dubbo_generator::ProtoFlavor::NORMAL, false);
}
} else {
java_grpc_generator::ProtoFlavor flavor =
java_grpc_generator::ProtoFlavor::NORMAL;
bool disable_version = false;
for (size_t i = 0; i < options.size(); i++) {
if (options[i].first == "nano") {
flavor = java_grpc_generator::ProtoFlavor::NANO;
} else if (options[i].first == "lite") {
flavor = java_grpc_generator::ProtoFlavor::LITE;
} else if (options[i].first == "noversion") {
disable_version = true;
}
}
string package_name = java_grpc_generator::ServiceJavaPackage(
file, flavor == java_grpc_generator::ProtoFlavor::NANO);
string package_filename = JavaPackageToDir(package_name);
for (int i = 0; i < file->service_count(); ++i) {
const google::protobuf::ServiceDescriptor* service = file->service(i);
string filename = package_filename
+ java_grpc_generator::ServiceClassName(service) + ".java";
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
context->Open(filename));
java_grpc_generator::GenerateService(
service, output.get(), flavor, disable_version);
}
}
return true;
}
};
int main(int argc, char* argv[]) {
JavaGrpcGenerator generator;
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

View File

@ -420,7 +420,7 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-protobuf-json</artifactId>
<artifactId>dubbo-serialization-protobuf</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
@ -662,7 +662,7 @@
<include>org.apache.dubbo:dubbo-serialization-jdk</include>
<include>org.apache.dubbo:dubbo-serialization-protostuff</include>
<include>org.apache.dubbo:dubbo-serialization-gson</include>
<include>org.apache.dubbo:dubbo-serialization-protobuf-json</include>
<include>org.apache.dubbo:dubbo-serialization-protobuf</include>
<include>org.apache.dubbo:dubbo-configcenter-api</include>
<include>org.apache.dubbo:dubbo-configcenter-definition</include>
<include>org.apache.dubbo:dubbo-configcenter-apollo</include>

View File

@ -360,7 +360,7 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-protobuf-json</artifactId>
<artifactId>dubbo-serialization-protobuf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View File

@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.protobuf;
/**
* proto-gen-dubbo-java
*/
public interface ProtobufService {
}

View File

@ -116,7 +116,7 @@
<hibernate_validator_version>5.4.1.Final</hibernate_validator_version>
<jel_version>3.0.1-b08</jel_version>
<jcache_version>1.0.0</jcache_version>
<kryo_version>4.0.1</kryo_version>
<kryo_version>4.0.2</kryo_version>
<kryo_serializers_version>0.42</kryo_serializers_version>
<fst_version>2.48-jdk-6</fst_version>
<avro_version>1.8.2</avro_version>

View File

@ -51,7 +51,7 @@
<exclude>**/*.jar</exclude>
<exclude>**/mvnw*</exclude>
<exclude>**/.flattened-pom.xml</exclude>
<exclude>**/dubbo-rpc-grpc/compiler/**</exclude>
<exclude>**/compiler/**</exclude>
</excludes>
</fileSet>
</fileSets>

View File

@ -278,7 +278,7 @@ public class ExchangeCodec extends TelnetCodec {
// encode response data or error message.
if (status == Response.OK) {
if (res.isHeartbeat()) {
encodeHeartbeatData(channel, out, res.getResult());
encodeEventData(channel, out, res.getResult());
} else {
encodeResponseData(channel, out, res.getResult(), res.getVersion());
}
@ -401,9 +401,9 @@ public class ExchangeCodec extends TelnetCodec {
protected Object decodeEventData(Channel channel, ObjectInput in) throws IOException {
try {
return in.readObject();
} catch (ClassNotFoundException e) {
throw new IOException(StringUtils.toString("Read object failed.", e));
return in.readUTF();
} catch (IOException e) {
throw new IOException(StringUtils.toString("Decode dubbo protocol event failed.", e));
}
}

View File

@ -99,6 +99,7 @@ public class CuratorZookeeperClient extends AbstractZookeeperClient<CuratorZooke
try {
client.create().forPath(path);
} catch (NodeExistsException e) {
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}

View File

@ -127,6 +127,7 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
Object value = null;
if (ArrayUtils.isEmpty(returnTypes)) {
// This almost never happens?
value = in.readObject();
} else if (returnTypes.length == 1) {
value = in.readObject((Class<?>) returnTypes[0]);
@ -141,7 +142,7 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
private void handleException(ObjectInput in) throws IOException {
try {
Object obj = in.readObject();
Object obj = in.readThrowable();
if (!(obj instanceof Throwable)) {
throw new IOException("Response data error, expect Throwable, but get " + obj);
}

View File

@ -78,10 +78,7 @@ public class DubboCodec extends ExchangeCodec {
try {
if (status == Response.OK) {
Object data;
if (res.isHeartbeat()) {
ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
data = decodeHeartbeatData(channel, in);
} else if (res.isEvent()) {
if (res.isEvent()) {
ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
data = decodeEventData(channel, in);
} else {
@ -120,10 +117,7 @@ public class DubboCodec extends ExchangeCodec {
}
try {
Object data;
if (req.isHeartbeat()) {
ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
data = decodeHeartbeatData(channel, in);
} else if (req.isEvent()) {
if (req.isEvent()) {
ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
data = decodeEventData(channel, in);
} else {
@ -205,7 +199,7 @@ public class DubboCodec extends ExchangeCodec {
}
} else {
out.writeByte(attach ? RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS : RESPONSE_WITH_EXCEPTION);
out.writeObject(th);
out.writeThrowable(th);
}
if (attach) {

View File

@ -1,70 +0,0 @@
// Generates Java gRPC service interface out of Protobuf IDL.
//
// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto
// and net/proto2/compiler/public/plugin.h for more information on plugins.
#include <memory>
#include "java_generator.h"
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream.h>
static string JavaPackageToDir(const string& package_name) {
string package_dir = package_name;
for (size_t i = 0; i < package_dir.size(); ++i) {
if (package_dir[i] == '.') {
package_dir[i] = '/';
}
}
if (!package_dir.empty()) package_dir += "/";
return package_dir;
}
class JavaGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
public:
JavaGrpcGenerator() {}
virtual ~JavaGrpcGenerator() {}
virtual bool Generate(const google::protobuf::FileDescriptor* file,
const string& parameter,
google::protobuf::compiler::GeneratorContext* context,
string* error) const {
std::vector<std::pair<string, string> > options;
google::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
java_grpc_generator::ProtoFlavor flavor =
java_grpc_generator::ProtoFlavor::NORMAL;
bool disable_version = false;
for (size_t i = 0; i < options.size(); i++) {
if (options[i].first == "nano") {
flavor = java_grpc_generator::ProtoFlavor::NANO;
} else if (options[i].first == "lite") {
flavor = java_grpc_generator::ProtoFlavor::LITE;
} else if (options[i].first == "noversion") {
disable_version = true;
}
}
string package_name = java_grpc_generator::ServiceJavaPackage(
file, flavor == java_grpc_generator::ProtoFlavor::NANO);
string package_filename = JavaPackageToDir(package_name);
for (int i = 0; i < file->service_count(); ++i) {
const google::protobuf::ServiceDescriptor* service = file->service(i);
string filename = package_filename
+ java_grpc_generator::ServiceClassName(service) + ".java";
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
context->Open(filename));
java_grpc_generator::GenerateService(
service, output.get(), flavor, disable_version);
}
return true;
}
};
int main(int argc, char* argv[]) {
JavaGrpcGenerator generator;
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

View File

@ -60,6 +60,7 @@ public class GrpcProtocol extends AbstractProxyProtocol {
String key = url.getAddress();
GrpcServer grpcServer = serverMap.computeIfAbsent(key, k -> {
DubboHandlerRegistry registry = new DubboHandlerRegistry();
Server originalServer = ServerBuilder
.forPort(url.getPort())
.fallbackHandlerRegistry(registry)

View File

@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.protocol.grpc;
import org.apache.dubbo.common.URL;
import io.grpc.ManagedChannelBuilder;
import io.grpc.ServerBuilder;
/**
* Support gRPC configs in the Dubbo specific way.
*/
public class GrpcServerUtils {
public static void configureServer(URL url, ServerBuilder builder) {
}
public static void configureChannel(URL url, ManagedChannelBuilder builder) {
}
}

View File

@ -25,14 +25,19 @@ import java.lang.reflect.Type;
public interface ObjectInput extends DataInput {
/**
* read object
* Consider use {@link #readObject(Class)} or {@link #readObject(Class, Type)} where possible
*
* @return object
* @throws IOException if an I/O error occurs
* @throws ClassNotFoundException if an ClassNotFoundException occurs
*/
@Deprecated
Object readObject() throws IOException, ClassNotFoundException;
default Object readThrowable() throws IOException, ClassNotFoundException {
return readObject();
}
/**
* read object
*

View File

@ -30,4 +30,28 @@ public interface ObjectOutput extends DataOutput {
*/
void writeObject(Object obj) throws IOException;
/**
* The following methods are customized for the requirement of Dubbo's RPC protocol implementation. Legacy protocol
* implementation will try to write Map, Throwable and Null value directly to the stream, which does not meet the
* restrictions of all serialization protocols.
* <p>
* See ProtobufSerialization, KryoSerialization for more details.
* <p>
* The binding of RPC protocol and biz serialization protocol is not a good practice. The encoding of RPC protocol
* should be highly independent and portable, easy to cross platforms and languages, for example, like the http headers,
* restricting the headers / attachments to Ascii strings and uses ISO_8859_1 to encode.
* https://tools.ietf.org/html/rfc7540#section-8.1.2
*/
default void writeThrowable(Object obj) throws IOException {
writeObject(obj);
}
default void writeEvent(String data) throws IOException {
writeObject(data);
}
default void writeAttachments(Object obj) throws IOException {
}
}

View File

@ -0,0 +1,170 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.kryo.optimized;
import org.apache.dubbo.common.serialize.Cleanable;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.kryo.utils.KryoUtils;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.Input;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
* Kryo object input implementation, kryo object can be clean
*/
public class KryoObjectInput2 implements ObjectInput, Cleanable {
private Kryo kryo;
private Input input;
public KryoObjectInput2(InputStream inputStream) {
input = new Input(inputStream);
this.kryo = KryoUtils.get();
}
@Override
public boolean readBool() throws IOException {
try {
return input.readBoolean();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public byte readByte() throws IOException {
try {
return input.readByte();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public short readShort() throws IOException {
try {
return input.readShort();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public int readInt() throws IOException {
try {
return input.readInt();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public long readLong() throws IOException {
try {
return input.readLong();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public float readFloat() throws IOException {
try {
return input.readFloat();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public double readDouble() throws IOException {
try {
return input.readDouble();
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public byte[] readBytes() throws IOException {
try {
int len = input.readInt();
if (len < 0) {
return null;
} else if (len == 0) {
return new byte[]{};
} else {
return input.readBytes(len);
}
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public String readUTF() throws IOException {
try {
return input.readString();
} catch (KryoException e) {
throw new IOException(e);
}
}
/**
* works as the only endpoint
*
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
@Override
public Object readObject() throws IOException, ClassNotFoundException {
try {
return kryo.readObjectOrNull(input, String.class);
} catch (KryoException e) {
throw new IOException(e);
}
}
@Override
public Object readThrowable() throws IOException, ClassNotFoundException {
return kryo.readClassAndObject(input);
}
@Override
@SuppressWarnings("unchecked")
public <T> T readObject(Class<T> clazz) throws IOException, ClassNotFoundException {
return kryo.readObjectOrNull(input, clazz);
}
@Override
@SuppressWarnings("unchecked")
public <T> T readObject(Class<T> clazz, Type type) throws IOException, ClassNotFoundException {
return readObject(clazz);
}
@Override
public void cleanup() {
KryoUtils.release(kryo);
kryo = null;
}
}

View File

@ -0,0 +1,122 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.kryo.optimized;
import org.apache.dubbo.common.serialize.Cleanable;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.kryo.utils.KryoUtils;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Output;
import java.io.IOException;
import java.io.OutputStream;
/**
* Kryo object output implementation, kryo object can be clean
*/
public class KryoObjectOutput2 implements ObjectOutput, Cleanable {
private Output output;
private Kryo kryo;
public KryoObjectOutput2(OutputStream outputStream) {
output = new Output(outputStream);
this.kryo = KryoUtils.get();
}
@Override
public void writeBool(boolean v) throws IOException {
output.writeBoolean(v);
}
@Override
public void writeByte(byte v) throws IOException {
output.writeByte(v);
}
@Override
public void writeShort(short v) throws IOException {
output.writeShort(v);
}
@Override
public void writeInt(int v) throws IOException {
output.writeInt(v);
}
@Override
public void writeLong(long v) throws IOException {
output.writeLong(v);
}
@Override
public void writeFloat(float v) throws IOException {
output.writeFloat(v);
}
@Override
public void writeDouble(double v) throws IOException {
output.writeDouble(v);
}
@Override
public void writeBytes(byte[] v) throws IOException {
if (v == null) {
output.writeInt(-1);
} else {
writeBytes(v, 0, v.length);
}
}
@Override
public void writeBytes(byte[] v, int off, int len) throws IOException {
if (v == null) {
output.writeInt(-1);
} else {
output.writeInt(len);
output.write(v, off, len);
}
}
@Override
public void writeUTF(String v) throws IOException {
output.writeString(v);
}
@Override
public void writeObject(Object v) throws IOException {
kryo.writeObjectOrNull(output, v, v.getClass());
}
@Override
public void writeThrowable(Object v) throws IOException {
kryo.writeClassAndObject(output, v);
}
@Override
public void flushBuffer() throws IOException {
output.flush();
}
@Override
public void cleanup() {
KryoUtils.release(kryo);
kryo = null;
}
}

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.kryo.optimized;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import static org.apache.dubbo.common.serialize.Constants.KRYO_SERIALIZATION_ID;
/**
* TODO for now kryo serialization doesn't deny classes that don't implement the serializable interface
*
* <pre>
* e.g. &lt;dubbo:protocol serialization="kryo" /&gt;
* </pre>
*/
public class KryoSerialization2 implements Serialization {
@Override
public byte getContentTypeId() {
return KRYO_SERIALIZATION_ID;
}
@Override
public String getContentType() {
return "x-application/kryo";
}
@Override
public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
return new KryoObjectOutput2(out);
}
@Override
public ObjectInput deserialize(URL url, InputStream is) throws IOException {
return new KryoObjectInput2(is);
}
}

View File

@ -1 +1,2 @@
kryo=org.apache.dubbo.common.serialize.kryo.KryoSerialization
kryo=org.apache.dubbo.common.serialize.kryo.KryoSerialization
kryo2=org.apache.dubbo.common.serialize.kryo.optimized.KryoSerialization2

View File

@ -1,47 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>dubbo-serialization-protobuf-json</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>The protobuf serialization module of dubbo project</description>
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,830 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
/**
* Generated by the protocol buffer compiler. DO NOT EDIT!
*/
public final class MapValue {
private MapValue() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
public interface MapOrBuilder extends
// @@protoc_insertion_point(interface_extends:Map)
com.google.protobuf.MessageOrBuilder {
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
int getAttachmentsCount();
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
boolean containsAttachments(
String key);
/**
* Use {@link #getAttachmentsMap()} instead.
*/
@Deprecated
java.util.Map<String, String>
getAttachments();
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
java.util.Map<String, String>
getAttachmentsMap();
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
String getAttachmentsOrDefault(
String key,
String defaultValue);
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
String getAttachmentsOrThrow(
String key);
}
/**
* Protobuf type {@code Map}
*/
public static final class Map extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:Map)
MapOrBuilder {
private static final long serialVersionUID = 0L;
// Use Map.newBuilder() to construct.
private Map(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private Map() {
}
@Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private Map(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new NullPointerException();
}
int mutable_bitField0_ = 0;
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 10: {
if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
attachments_ = com.google.protobuf.MapField.newMapField(
AttachmentsDefaultEntryHolder.defaultEntry);
mutable_bitField0_ |= 0x00000001;
}
com.google.protobuf.MapEntry<String, String>
attachments__ = input.readMessage(
AttachmentsDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);
attachments_.getMutableMap().put(
attachments__.getKey(), attachments__.getValue());
break;
}
default: {
if (!parseUnknownFieldProto3(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return MapValue.internal_static_Map_descriptor;
}
@SuppressWarnings({"rawtypes"})
@Override
protected com.google.protobuf.MapField internalGetMapField(
int number) {
switch (number) {
case 1:
return internalGetAttachments();
default:
throw new RuntimeException(
"Invalid map field number: " + number);
}
}
@Override
protected FieldAccessorTable
internalGetFieldAccessorTable() {
return MapValue.internal_static_Map_fieldAccessorTable
.ensureFieldAccessorsInitialized(
Map.class, Builder.class);
}
public static final int ATTACHMENTS_FIELD_NUMBER = 1;
private static final class AttachmentsDefaultEntryHolder {
static final com.google.protobuf.MapEntry<
String, String> defaultEntry =
com.google.protobuf.MapEntry
.<String, String>newDefaultInstance(
MapValue.internal_static_Map_AttachmentsEntry_descriptor,
com.google.protobuf.WireFormat.FieldType.STRING,
"",
com.google.protobuf.WireFormat.FieldType.STRING,
"");
}
private com.google.protobuf.MapField<
String, String> attachments_;
private com.google.protobuf.MapField<String, String>
internalGetAttachments() {
if (attachments_ == null) {
return com.google.protobuf.MapField.emptyMapField(
AttachmentsDefaultEntryHolder.defaultEntry);
}
return attachments_;
}
@Override
public int getAttachmentsCount() {
return internalGetAttachments().getMap().size();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public boolean containsAttachments(
String key) {
if (key == null) { throw new NullPointerException(); }
return internalGetAttachments().getMap().containsKey(key);
}
/**
* Use {@link #getAttachmentsMap()} instead.
*/
@Override
@Deprecated
public java.util.Map<String, String> getAttachments() {
return getAttachmentsMap();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public java.util.Map<String, String> getAttachmentsMap() {
return internalGetAttachments().getMap();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public String getAttachmentsOrDefault(
String key,
String defaultValue) {
if (key == null) { throw new NullPointerException(); }
java.util.Map<String, String> map =
internalGetAttachments().getMap();
return map.containsKey(key) ? map.get(key) : defaultValue;
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public String getAttachmentsOrThrow(
String key) {
if (key == null) { throw new NullPointerException(); }
java.util.Map<String, String> map =
internalGetAttachments().getMap();
if (!map.containsKey(key)) {
throw new IllegalArgumentException();
}
return map.get(key);
}
private byte memoizedIsInitialized = -1;
@Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) {
return true;
}
if (isInitialized == 0) {
return false;
}
memoizedIsInitialized = 1;
return true;
}
@Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
com.google.protobuf.GeneratedMessageV3
.serializeStringMapTo(
output,
internalGetAttachments(),
AttachmentsDefaultEntryHolder.defaultEntry,
1);
unknownFields.writeTo(output);
}
@Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) {
return size;
}
size = 0;
for (java.util.Map.Entry<String, String> entry
: internalGetAttachments().getMap().entrySet()) {
com.google.protobuf.MapEntry<String, String>
attachments__ = AttachmentsDefaultEntryHolder.defaultEntry.newBuilderForType()
.setKey(entry.getKey())
.setValue(entry.getValue())
.build();
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(1, attachments__);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Map)) {
return super.equals(obj);
}
Map other = (Map) obj;
boolean result = true;
result = result && internalGetAttachments().equals(
other.internalGetAttachments());
result = result && unknownFields.equals(other.unknownFields);
return result;
}
@Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
if (!internalGetAttachments().getMap().isEmpty()) {
hash = (37 * hash) + ATTACHMENTS_FIELD_NUMBER;
hash = (53 * hash) + internalGetAttachments().hashCode();
}
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static Map parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static Map parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static Map parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static Map parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static Map parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static Map parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static Map parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static Map parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static Map parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static Map parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static Map parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static Map parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(Map prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@Override
protected Builder newBuilderForType(
BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* Protobuf type {@code Map}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:Map)
MapOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return MapValue.internal_static_Map_descriptor;
}
@Override
@SuppressWarnings({"rawtypes"})
protected com.google.protobuf.MapField internalGetMapField(
int number) {
switch (number) {
case 1:
return internalGetAttachments();
default:
throw new RuntimeException(
"Invalid map field number: " + number);
}
}
@Override
@SuppressWarnings({"rawtypes"})
protected com.google.protobuf.MapField internalGetMutableMapField(
int number) {
switch (number) {
case 1:
return internalGetMutableAttachments();
default:
throw new RuntimeException(
"Invalid map field number: " + number);
}
}
@Override
protected FieldAccessorTable
internalGetFieldAccessorTable() {
return MapValue.internal_static_Map_fieldAccessorTable
.ensureFieldAccessorsInitialized(
Map.class, Builder.class);
}
// Construct using org.apache.dubbo.common.serialize.protobuf.support.MapValue.Map.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@Override
public Builder clear() {
super.clear();
internalGetMutableAttachments().clear();
return this;
}
@Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return MapValue.internal_static_Map_descriptor;
}
@Override
public Map getDefaultInstanceForType() {
return Map.getDefaultInstance();
}
@Override
public Map build() {
Map result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@Override
public Map buildPartial() {
Map result = new Map(this);
int from_bitField0_ = bitField0_;
result.attachments_ = internalGetAttachments();
result.attachments_.makeImmutable();
onBuilt();
return result;
}
@Override
public Builder clone() {
return (Builder) super.clone();
}
@Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
Object value) {
return (Builder) super.setField(field, value);
}
@Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return (Builder) super.clearField(field);
}
@Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return (Builder) super.clearOneof(oneof);
}
@Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, Object value) {
return (Builder) super.setRepeatedField(field, index, value);
}
@Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
Object value) {
return (Builder) super.addRepeatedField(field, value);
}
@Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof Map) {
return mergeFrom((Map)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(Map other) {
if (other == Map.getDefaultInstance()) {
return this;
}
internalGetMutableAttachments().mergeFrom(
other.internalGetAttachments());
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@Override
public final boolean isInitialized() {
return true;
}
@Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
Map parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (Map) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private int bitField0_;
private com.google.protobuf.MapField<
String, String> attachments_;
private com.google.protobuf.MapField<String, String>
internalGetAttachments() {
if (attachments_ == null) {
return com.google.protobuf.MapField.emptyMapField(
AttachmentsDefaultEntryHolder.defaultEntry);
}
return attachments_;
}
private com.google.protobuf.MapField<String, String>
internalGetMutableAttachments() {
onChanged();;
if (attachments_ == null) {
attachments_ = com.google.protobuf.MapField.newMapField(
AttachmentsDefaultEntryHolder.defaultEntry);
}
if (!attachments_.isMutable()) {
attachments_ = attachments_.copy();
}
return attachments_;
}
@Override
public int getAttachmentsCount() {
return internalGetAttachments().getMap().size();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public boolean containsAttachments(
String key) {
if (key == null) { throw new NullPointerException(); }
return internalGetAttachments().getMap().containsKey(key);
}
/**
* Use {@link #getAttachmentsMap()} instead.
*/
@Override
@Deprecated
public java.util.Map<String, String> getAttachments() {
return getAttachmentsMap();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public java.util.Map<String, String> getAttachmentsMap() {
return internalGetAttachments().getMap();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public String getAttachmentsOrDefault(
String key,
String defaultValue) {
if (key == null) { throw new NullPointerException(); }
java.util.Map<String, String> map =
internalGetAttachments().getMap();
return map.containsKey(key) ? map.get(key) : defaultValue;
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
@Override
public String getAttachmentsOrThrow(
String key) {
if (key == null) { throw new NullPointerException(); }
java.util.Map<String, String> map =
internalGetAttachments().getMap();
if (!map.containsKey(key)) {
throw new IllegalArgumentException();
}
return map.get(key);
}
public Builder clearAttachments() {
internalGetMutableAttachments().getMutableMap()
.clear();
return this;
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
public Builder removeAttachments(
String key) {
if (key == null) { throw new NullPointerException(); }
internalGetMutableAttachments().getMutableMap()
.remove(key);
return this;
}
/**
* Use alternate mutation accessors instead.
*/
@Deprecated
public java.util.Map<String, String>
getMutableAttachments() {
return internalGetMutableAttachments().getMutableMap();
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
public Builder putAttachments(
String key,
String value) {
if (key == null) { throw new NullPointerException(); }
if (value == null) { throw new NullPointerException(); }
internalGetMutableAttachments().getMutableMap()
.put(key, value);
return this;
}
/**
* <code>map&lt;string, string&gt; attachments = 1;</code>
*/
public Builder putAllAttachments(
java.util.Map<String, String> values) {
internalGetMutableAttachments().getMutableMap()
.putAll(values);
return this;
}
@Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFieldsProto3(unknownFields);
}
@Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:Map)
}
// @@protoc_insertion_point(class_scope:Map)
private static final Map DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new Map();
}
public static Map getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<Map>
PARSER = new com.google.protobuf.AbstractParser<Map>() {
@Override
public Map parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new Map(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<Map> parser() {
return PARSER;
}
@Override
public com.google.protobuf.Parser<Map> getParserForType() {
return PARSER;
}
@Override
public Map getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_Map_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_Map_fieldAccessorTable;
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_Map_AttachmentsEntry_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_Map_AttachmentsEntry_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
String[] descriptorData = {
"\n\tmap.proto\"e\n\003Map\022*\n\013attachments\030\001 \003(\0132" +
"\025.Map.AttachmentsEntry\0322\n\020AttachmentsEnt" +
"ry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001B>\n2or" +
"g.apache.dubbo.common.serialize.protobuf" +
".supportB\010MapValueb\006proto3"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@Override
public com.google.protobuf.ExtensionRegistry assignDescriptors(
com.google.protobuf.Descriptors.FileDescriptor root) {
descriptor = root;
return null;
}
};
com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
}, assigner);
internal_static_Map_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_Map_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_Map_descriptor,
new String[] { "Attachments", });
internal_static_Map_AttachmentsEntry_descriptor =
internal_static_Map_descriptor.getNestedTypes().get(0);
internal_static_Map_AttachmentsEntry_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_Map_AttachmentsEntry_descriptor,
new String[] { "Key", "Value", });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@ -1,61 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.GeneratedMessageV3.Builder;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
import java.lang.reflect.Method;
public class ProtobufUtils {
static boolean isSupported(Class<?> clazz) {
if (clazz == null) {
return false;
}
if (GeneratedMessageV3.class.isAssignableFrom(clazz)) {
return true;
}
return false;
}
static <T> T deserialize(String json, Class<T> requestClass) throws InvalidProtocolBufferException {
Builder builder;
try {
builder = getMessageBuilder(requestClass);
} catch (Exception e) {
throw new IllegalArgumentException("Get google protobuf message builder from " + requestClass.getName() + "failed", e);
}
JsonFormat.parser().merge(json, builder);
return (T) builder.build();
}
static String serialize(Object value) throws InvalidProtocolBufferException {
Printer printer = JsonFormat.printer().omittingInsignificantWhitespace();
return printer.print((MessageOrBuilder) value);
}
private static Builder getMessageBuilder(Class<?> requestType) throws Exception {
Method method = requestType.getMethod("newBuilder");
return (Builder) method.invoke(null, null);
}
}

View File

@ -1 +0,0 @@
protobuf-json=org.apache.dubbo.common.serialize.protobuf.support.GenericProtobufSerialization

View File

@ -0,0 +1,105 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>dubbo-serialization-protobuf</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>The protobuf serialization module of dubbo project</description>
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
<!-- /compiler/build.gradle -->
<proto_dubbo_plugin_version>1.19.0-SNAPSHOT</proto_dubbo_plugin_version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>
org.apache.dubbo:protoc-gen-grpc-java:${proto_dubbo_plugin_version}:exe:${os.detected.classifier}
</pluginArtifact>
<outputDirectory>build/generated/source/proto/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
<!-- supports 'dubbo' and 'grpc' -->
<pluginParameter>dubbo</pluginParameter>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
<goal>test-compile</goal>
<goal>test-compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>build/generated/source/proto/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -17,10 +17,13 @@
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.MapValue;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.ThrowablePB;
import com.google.protobuf.BoolValue;
import com.google.protobuf.BytesValue;
import com.google.protobuf.DoubleValue;
import com.google.protobuf.Empty;
import com.google.protobuf.FloatValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.Int64Value;
@ -37,10 +40,10 @@ import java.util.Map;
/**
* GenericGoogleProtobuf object input implementation
*/
public class GenericProtobufObjectInput implements ObjectInput {
public class GenericProtobufJsonObjectInput implements ObjectInput {
private final BufferedReader reader;
public GenericProtobufObjectInput(InputStream in) {
public GenericProtobufJsonObjectInput(InputStream in) {
this.reader = new BufferedReader(new InputStreamReader(in));
}
@ -91,7 +94,17 @@ public class GenericProtobufObjectInput implements ObjectInput {
@Override
public Object readObject() {
throw new UnsupportedOperationException();
try {
read(Empty.class);
return null;
} catch (Exception e) {
throw new UnsupportedOperationException("Provide the protobuf message type you want to read.");
}
}
@Override
public Object readThrowable() throws IOException, ClassNotFoundException {
return read(Throwable.class);
}
@Override
@ -117,12 +130,16 @@ public class GenericProtobufObjectInput implements ObjectInput {
if (cls.equals(Map.class)) {
// only for attachments
String json = readLine();
return (T) ProtobufUtils.deserialize(json, MapValue.Map.class).getAttachmentsMap();
return (T) ProtobufUtils.deserializeJson(json, MapValue.Map.class).getAttachmentsMap();
} else if (getClass().isAssignableFrom(Throwable.class)) {
String json = readLine();
ThrowablePB.ThrowableProto throwableProto = ProtobufUtils.deserializeJson(json, ThrowablePB.ThrowableProto.class);
return (T) ProtobufUtils.convertToException(throwableProto);
} else if (!ProtobufUtils.isSupported(cls)) {
throw new IllegalArgumentException("This serialization only support google protobuf entity, the class is :" + cls.getName());
}
String json = readLine();
return ProtobufUtils.deserialize(json, cls);
return ProtobufUtils.deserializeJson(json, cls);
}
}

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.MapValue;
import com.google.protobuf.BoolValue;
import com.google.protobuf.ByteString;
@ -36,11 +37,11 @@ import java.util.Map;
/**
* GenericGoogleProtobuf object output implementation
*/
public class GenericProtobufObjectOutput implements ObjectOutput {
public class GenericProtobufJsonObjectOutput implements ObjectOutput {
private final PrintWriter writer;
public GenericProtobufObjectOutput(OutputStream out) {
public GenericProtobufJsonObjectOutput(OutputStream out) {
this.writer = new PrintWriter(new OutputStreamWriter(out));
}
@ -104,11 +105,13 @@ public class GenericProtobufObjectOutput implements ObjectOutput {
if (obj instanceof Map) {
// only for attachment
obj = MapValue.Map.newBuilder().putAllAttachments((Map) obj).build();
} else if (obj instanceof Throwable && !ProtobufUtils.isSupported(obj.getClass())) {
obj = ProtobufUtils.serializeJson(ProtobufUtils.convertToThrowableProto((Throwable) obj));
} else if (!ProtobufUtils.isSupported(obj.getClass())) {
throw new IllegalArgumentException("This serialization only support google protobuf object, the object class is: " + obj.getClass().getName());
}
writer.write(ProtobufUtils.serialize(obj));
writer.write(ProtobufUtils.serializeJson(obj));
writer.println();
writer.flush();
}

View File

@ -29,9 +29,8 @@ import static org.apache.dubbo.common.serialize.Constants.PROTOBUF_JSON_SERIALIZ
/**
* This serizalization is use for google protobuf generic reference.
* The entity be transported between client and server by json string.
*
*/
public class GenericProtobufSerialization implements Serialization {
public class GenericProtobufJsonSerialization implements Serialization {
@Override
public byte getContentTypeId() {
@ -45,11 +44,11 @@ public class GenericProtobufSerialization implements Serialization {
@Override
public ObjectOutput serialize(URL url, OutputStream output) {
return new GenericProtobufObjectOutput(output);
return new GenericProtobufJsonObjectOutput(output);
}
@Override
public ObjectInput deserialize(URL url, InputStream input) {
return new GenericProtobufObjectInput(input);
return new GenericProtobufJsonObjectInput(input);
}
}

View File

@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.MapValue;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.ThrowablePB;
import com.google.protobuf.BoolValue;
import com.google.protobuf.BytesValue;
import com.google.protobuf.DoubleValue;
import com.google.protobuf.Empty;
import com.google.protobuf.FloatValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.Int64Value;
import com.google.protobuf.StringValue;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Map;
public class GenericProtobufObjectInput implements ObjectInput {
private final InputStream is;
public GenericProtobufObjectInput(InputStream is) {
this.is = is;
}
@Override
public boolean readBool() throws IOException {
return read(BoolValue.class).getValue();
}
@Override
public byte readByte() throws IOException {
return (byte) read(Int32Value.class).getValue();
}
@Override
public short readShort() throws IOException {
return (short) read(Int32Value.class).getValue();
}
@Override
public int readInt() throws IOException {
return read(Int32Value.class).getValue();
}
@Override
public long readLong() throws IOException {
return read(Int64Value.class).getValue();
}
@Override
public float readFloat() throws IOException {
return read(FloatValue.class).getValue();
}
@Override
public double readDouble() throws IOException {
return read(DoubleValue.class).getValue();
}
@Override
public String readUTF() throws IOException {
return read(StringValue.class).getValue();
}
@Override
public byte[] readBytes() throws IOException {
return read(BytesValue.class).getValue().toByteArray();
}
/**
* FIXME assume this method only has the following single entry point:
* DecodeableRpcResult#readValue, decode empty value for heart beat event.
* <p>
* Avoid using readObject, always try to pass the target class type for the data you want to read.
*
* @return
*/
@Deprecated
@Override
public Object readObject() {
try {
read(Empty.class);
return null;
} catch (Exception e) {
throw new UnsupportedOperationException("Provide the protobuf message type you want to read.");
}
}
@Override
public Object readThrowable() throws IOException, ClassNotFoundException {
return read(Throwable.class);
}
@Override
public <T> T readObject(Class<T> cls) throws IOException {
return read(cls);
}
@Override
public <T> T readObject(Class<T> cls, Type type) throws IOException {
return readObject(cls);
}
@SuppressWarnings("unchecked")
private <T> T read(Class<T> cls) throws IOException {
if (cls.isAssignableFrom(Map.class)) {
// only for attachments
return (T) ProtobufUtils.deserialize(is, MapValue.Map.class).getAttachmentsMap();
} else if (getClass().isAssignableFrom(Throwable.class)) {
ThrowablePB.ThrowableProto throwableProto = ProtobufUtils.deserialize(is, ThrowablePB.ThrowableProto.class);
return (T) ProtobufUtils.convertToException(throwableProto);
} else if (!ProtobufUtils.isSupported(cls)) {
throw new IllegalArgumentException("This serialization only support google protobuf entity, the class is :" + cls.getName());
}
return ProtobufUtils.deserialize(is, cls);
}
}

View File

@ -0,0 +1,141 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.MapValue;
import com.google.protobuf.BoolValue;
import com.google.protobuf.ByteString;
import com.google.protobuf.BytesValue;
import com.google.protobuf.DoubleValue;
import com.google.protobuf.FloatValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.Int64Value;
import com.google.protobuf.MessageLite;
import com.google.protobuf.StringValue;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
/**
* GenericGoogleProtobuf object output implementation
*/
public class GenericProtobufObjectOutput implements ObjectOutput {
private final OutputStream os;
public GenericProtobufObjectOutput(OutputStream os) {
this.os = os;
}
@Override
public void writeBool(boolean v) throws IOException {
writeObject(BoolValue.newBuilder().setValue(v).build());
}
@Override
public void writeByte(byte v) throws IOException {
writeObject(Int32Value.newBuilder().setValue((v)).build());
}
@Override
public void writeShort(short v) throws IOException {
writeObject(Int32Value.newBuilder().setValue(v).build());
}
@Override
public void writeInt(int v) throws IOException {
writeObject(Int32Value.newBuilder().setValue(v).build());
}
@Override
public void writeLong(long v) throws IOException {
writeObject(Int64Value.newBuilder().setValue(v).build());
}
@Override
public void writeFloat(float v) throws IOException {
writeObject(FloatValue.newBuilder().setValue(v).build());
}
@Override
public void writeDouble(double v) throws IOException {
writeObject(DoubleValue.newBuilder().setValue(v).build());
}
@Override
public void writeUTF(String v) throws IOException {
writeObject(StringValue.newBuilder().setValue(v).build());
}
@Override
public void writeBytes(byte[] b) throws IOException {
writeObject(BytesValue.newBuilder().setValue(ByteString.copyFrom(b)).build());
}
@Override
public void writeBytes(byte[] b, int off, int len) throws IOException {
writeObject(BytesValue.newBuilder().setValue(ByteString.copyFrom(b, off, len)).build());
}
@SuppressWarnings("unchecked")
@Override
public void writeObject(Object obj) throws IOException {
/**
* Protobuf does not allow writing of non-protobuf generated message, including null value.
* Writing of null value from developers should be denied immediately by throwing exception.
*/
if (obj == null) {
throw new IllegalStateException("This serialization only supports google protobuf objects, " +
"please use com.google.protobuf.Empty instead if you want to transmit null values.");
// obj = ProtobufUtils.convertNullToEmpty();
}
if (obj instanceof Map) {
// only for attachment
obj = MapValue.Map.newBuilder().putAllAttachments((Map) obj).build();
} else if (!ProtobufUtils.isSupported(obj.getClass())) {
throw new IllegalArgumentException("This serialization only supports google protobuf objects, current object class is: " + obj.getClass().getName());
}
ProtobufUtils.serialize(obj, os);
os.flush();
}
@Override
public void writeEvent(String data) throws IOException {
if (data == null) {
data = "H";
}
writeUTF(data);
}
@Override
public void writeThrowable(Object obj) throws IOException {
if (obj instanceof Throwable && !(obj instanceof MessageLite)) {
obj = ProtobufUtils.convertToThrowableProto((Throwable) obj);
}
}
@Override
public void flushBuffer() throws IOException {
os.flush();
}
}

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
import java.io.InputStream;
import java.io.OutputStream;
import static org.apache.dubbo.common.serialize.Constants.PROTOBUF_JSON_SERIALIZATION_ID;
/**
* <p>
* Currently, the Dubbo protocol / framework data, such as attachments, event data, etc.,
* depends on business layer serialization protocol to do serialization before transmitted.
* That's a problem when using Protobuf as business serialization protocol, because Protobuf does not support raw java Object types,
* to solve it, we can use one of the following methods:
*
* <ul>
* <li>1. Package these data with Protobuf so that they can be serialized.</li>
* <li>2. Separate the serialization of Dubbo protocol/framework and the service args (easy to cross-platform, cross-language serialization) to avoid the binding of this part and serialization protocol.</li>
* </ul>
*
* </p>
*/
public class GenericProtobufSerialization implements Serialization {
@Override
public byte getContentTypeId() {
return PROTOBUF_JSON_SERIALIZATION_ID;
}
@Override
public String getContentType() {
return "text/json";
}
@Override
public ObjectOutput serialize(URL url, OutputStream output) {
return new GenericProtobufJsonObjectOutput(output);
}
@Override
public ObjectInput deserialize(URL url, InputStream input) {
return new GenericProtobufJsonObjectInput(input);
}
}

View File

@ -0,0 +1,193 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.MapValue;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.ThrowablePB.StackTraceElementProto;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.ThrowablePB.ThrowableProto;
import com.google.common.base.Strings;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.Empty;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.GeneratedMessageV3.Builder;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageLite;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.Parser;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ProtobufUtils {
static boolean isSupported(Class<?> clazz) {
if (clazz == null) {
return false;
}
if (GeneratedMessageV3.class.isAssignableFrom(clazz)) {
return true;
}
return false;
}
/* Protobuf json */
static <T> T deserializeJson(String json, Class<T> requestClass) throws InvalidProtocolBufferException {
Builder builder;
try {
builder = getMessageBuilder(requestClass);
} catch (Exception e) {
throw new IllegalArgumentException("Get google protobuf message builder from " + requestClass.getName() + "failed", e);
}
JsonFormat.parser().merge(json, builder);
return (T) builder.build();
}
static String serializeJson(Object value) throws InvalidProtocolBufferException {
Printer printer = JsonFormat.printer().omittingInsignificantWhitespace();
return printer.print((MessageOrBuilder) value);
}
private static Builder getMessageBuilder(Class<?> requestType) throws Exception {
Method method = requestType.getMethod("newBuilder");
return (Builder) method.invoke(null, null);
}
/* Protobuf */
private static ConcurrentMap<Class<? extends MessageLite>, MessageMarshaller> marshallers =
new ConcurrentHashMap<>();
private static volatile ExtensionRegistryLite globalRegistry =
ExtensionRegistryLite.getEmptyRegistry();
static {
// Builtin types needed to be registered in advance
marshaller(MapValue.Map.getDefaultInstance());
marshaller(Empty.getDefaultInstance());
marshaller(ThrowableProto.getDefaultInstance());
}
public static <T extends MessageLite> void marshaller(T defaultInstance) {
marshallers.put(defaultInstance.getClass(), new MessageMarshaller<>(defaultInstance));
}
static void serialize(Object value, OutputStream os) throws IOException {
MessageLite messageLite = (MessageLite) value;
messageLite.writeTo(os);
}
@SuppressWarnings("unchecked")
static <T> T deserialize(InputStream is, Class<T> requestClass) throws InvalidProtocolBufferException {
MessageMarshaller<?> marshaller = marshallers.get(requestClass);
if (marshaller == null) {
throw new IllegalStateException(String.format("Protobuf classes should be registered in advance before " +
"do serialization, class name: %s", requestClass.getName()));
}
return (T) marshaller.parse(is);
}
public static Empty convertNullToEmpty() {
return Empty.newBuilder().build();
}
public static Object convertEmptyToNull(Empty empty) {
return null;
}
public static ThrowableProto convertToThrowableProto(Throwable throwable) {
final ThrowableProto.Builder builder = ThrowableProto.newBuilder();
builder.setOriginalClassName(throwable.getClass().getCanonicalName());
builder.setOriginalMessage(Strings.nullToEmpty(throwable.getMessage()));
for (StackTraceElement e : throwable.getStackTrace()) {
builder.addStackTrace(toStackTraceElement(e));
}
if (throwable.getCause() != null) {
builder.setCause(convertToThrowableProto(throwable.getCause()));
}
return builder.build();
}
public static Throwable convertToException(ThrowableProto throwableProto) {
return new ProtobufWrappedException(throwableProto);
}
private static StackTraceElementProto toStackTraceElement(StackTraceElement element) {
final StackTraceElementProto.Builder builder =
StackTraceElementProto.newBuilder()
.setClassName(element.getClassName())
.setMethodName(element.getMethodName())
.setLineNumber(element.getLineNumber());
if (element.getFileName() != null) {
builder.setFileName(element.getFileName());
}
return builder.build();
}
private static final class MessageMarshaller<T extends MessageLite> {
private final Parser<T> parser;
private final T defaultInstance;
@SuppressWarnings("unchecked")
MessageMarshaller(T defaultInstance) {
this.defaultInstance = defaultInstance;
parser = (Parser<T>) defaultInstance.getParserForType();
}
@SuppressWarnings("unchecked")
public Class<T> getMessageClass() {
// Precisely T since protobuf doesn't let messages extend other messages.
return (Class<T>) defaultInstance.getClass();
}
public T getMessagePrototype() {
return defaultInstance;
}
public T parse(InputStream stream) throws InvalidProtocolBufferException {
CodedInputStream cis = CodedInputStream.newInstance(stream);
// Pre-create the CodedInputStream so that we can remove the size limit restriction
// when parsing.
cis.setSizeLimit(Integer.MAX_VALUE);
return parseFrom(cis);
}
private T parseFrom(CodedInputStream stream) throws InvalidProtocolBufferException {
T message = parser.parseFrom(stream, globalRegistry);
try {
stream.checkLastTagWas(0);
return message;
} catch (InvalidProtocolBufferException e) {
e.setUnfinishedMessage(message);
throw e;
}
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.ThrowablePB;
import org.apache.dubbo.common.serialize.protobuf.support.wrapper.ThrowablePB.ThrowableProto;
import com.google.common.base.Strings;
/**
* For protobuf, all server side exceptions should be wrapped using this specific one.
*/
public class ProtobufWrappedException extends RuntimeException {
private static final long serialVersionUID = -1792808536714102039L;
private String originalClassName;
private String originalMessage;
public ProtobufWrappedException(ThrowableProto throwableProto) {
super(throwableProto.getOriginalClassName() + ": " + throwableProto.getOriginalMessage());
originalClassName = throwableProto.getOriginalClassName();
originalMessage = throwableProto.getOriginalMessage();
if (throwableProto.getStackTraceCount() > 0) {
setStackTrace(throwableProto.getStackTraceList().stream()
.map(ProtobufWrappedException::toStackTraceElement)
.toArray(StackTraceElement[]::new));
}
if (throwableProto.hasCause()) {
initCause(new ProtobufWrappedException(throwableProto.getCause()));
}
}
public String getOriginalClassName() {
return originalClassName;
}
public String getOriginalMessage() {
return originalMessage;
}
private static StackTraceElement toStackTraceElement(ThrowablePB.StackTraceElementProto proto) {
return new StackTraceElement(
proto.getClassName(),
proto.getMethodName(),
Strings.emptyToNull(proto.getFileName()),
proto.getLineNumber());
}
}

View File

@ -0,0 +1,26 @@
// Copyright 2018 LINE Corporation
//
// LINE Corporation licenses this file to you under the Apache License,
// version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at:
//
// https://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.
// Messages used for transporting debug information between server and client.
syntax = "proto3";
package org.apache.dubbo.common.serialize.protobuf.support.wrapper;
option java_package = "org.apache.dubbo.common.serialize.protobuf.support.wrapper";
option java_multiple_files = false;
message Map{
map<string,string> attachments = 1;
}

View File

@ -0,0 +1,63 @@
// Copyright 2018 LINE Corporation
//
// LINE Corporation licenses this file to you under the Apache License,
// version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at:
//
// https://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.
// Messages used for transporting debug information between server and client.
syntax = "proto3";
package org.apache.dubbo.common.serialize.protobuf.support.wrapper;
option java_package = "org.apache.dubbo.common.serialize.protobuf.support.wrapper";
option java_multiple_files = false;
// An element in a stack trace, based on the Java type of the same name.
//
// See: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StackTraceElement.html
message StackTraceElementProto {
// The fully qualified name of the class containing the execution point
// represented by the stack trace element.
string class_name = 1;
// The name of the method containing the execution point represented by the
// stack trace element
string method_name = 2;
// The name of the file containing the execution point represented by the
// stack trace element, or null if this information is unavailable.
string file_name = 3;
// The line number of the source line containing the execution point represented
// by this stack trace element, or a negative number if this information is
// unavailable.
int32 line_number = 4;
}
// An exception that was thrown by some code, based on the Java type of the same name.
//
// See: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Throwable.html
message ThrowableProto {
// The name of the class of the exception that was actually thrown. Downstream readers
// of this message may or may not have the actual class available to initialize, so
// this is just used to prefix the message of a generic exception type.
string original_class_name = 1;
// The message of this throwable. Not filled if there is no message.
string original_message = 2;
// The stack trace of this Throwable.
repeated StackTraceElementProto stack_trace = 3;
// The cause of this Throwable. Not filled if there is no cause.
ThrowableProto cause = 4;
}

View File

@ -0,0 +1,2 @@
protobuf-json=org.apache.dubbo.common.serialize.protobuf.support.GenericProtobufJsonSerialization
protobuf=org.apache.dubbo.common.serialize.protobuf.support.GenericProtobufSerialization

View File

@ -80,7 +80,7 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-protobuf-json</artifactId>
<artifactId>dubbo-serialization-protobuf</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

View File

@ -0,0 +1,360 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
import org.apache.dubbo.common.serialize.protobuf.support.model.GooglePB;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.fail;
public class AbstractProtobufSerializationTest {
protected static Random random = new Random();
protected URL url = new URL("protocol", "1.1.1.1", 1234);
protected ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
protected Serialization serialization = new GenericProtobufSerialization();
@Test
public void test_Bool() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeBool(false);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertFalse(deserialize.readBool());
try {
deserialize.readBool();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Bool_Multi() throws Exception {
boolean[] array = new boolean[100];
for (int i = 0; i < array.length; i++) {
array[i] = random.nextBoolean();
}
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
for (boolean b : array) {
objectOutput.writeBool(b);
}
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
for (boolean b : array) {
assertEquals(b, deserialize.readBool());
}
try {
deserialize.readBool();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Byte() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeByte((byte) 123);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertEquals((byte) 123, deserialize.readByte());
try {
deserialize.readByte();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Byte_Multi() throws Exception {
byte[] array = new byte[100];
random.nextBytes(array);
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
for (byte b : array) {
objectOutput.writeByte(b);
}
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
for (byte b : array) {
assertEquals(b, deserialize.readByte());
}
try {
deserialize.readByte();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Short() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeShort((short) 123);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertEquals((short) 123, deserialize.readShort());
try {
deserialize.readShort();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Integer() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeInt(1);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
int i = deserialize.readInt();
assertEquals(1, i);
try {
deserialize.readInt();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Long() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeLong(123L);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertEquals(123L, deserialize.readLong());
try {
deserialize.readLong();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Float() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeFloat(1.28F);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertEquals(1.28F, deserialize.readFloat());
try {
deserialize.readFloat();
fail();
} catch (IOException expected) {
}
}
// ================== Util methods ==================
@Test
public void test_Double() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeDouble(1.28);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertEquals(1.28, deserialize.readDouble());
try {
deserialize.readDouble();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_UtfString() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeUTF("123中华人民共和国");
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertEquals("123中华人民共和国", deserialize.readUTF());
try {
deserialize.readUTF();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_Bytes() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeBytes("123中华人民共和国".getBytes());
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
assertArrayEquals("123中华人民共和国".getBytes(), deserialize.readBytes());
try {
deserialize.readBytes();
fail();
} catch (IOException expected) {
}
}
@Test
public void test_BytesRange() throws Exception {
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeBytes("123中华人民共和国-新疆维吾尔自治区".getBytes(), 1, 9);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream);
byte[] expectedArray = new byte[9];
System.arraycopy("123中华人民共和国-新疆维吾尔自治区".getBytes(), 1, expectedArray, 0, expectedArray.length);
assertArrayEquals(expectedArray, deserialize.readBytes());
try {
deserialize.readBytes();
fail();
} catch (IOException expected) {
}
}
private GooglePB.PBRequestType buildPbMessage() {
Random random = new Random();
final int bound = 100000;
List<GooglePB.PhoneNumber> phoneNumberList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
phoneNumberList.add(GooglePB.PhoneNumber.newBuilder().setNumber(random.nextInt(bound) + "").setType(GooglePB.PhoneType.forNumber(random.nextInt(GooglePB.PhoneType.values().length - 1))).build());
}
Map<String, GooglePB.PhoneNumber> phoneNumberMap = new HashMap<>();
for (int i = 0; i < 5; i++) {
phoneNumberMap.put("phoneNumber" + i, GooglePB.PhoneNumber.newBuilder().setNumber(random.nextInt(bound) + "").setType(GooglePB.PhoneType.forNumber(random.nextInt(GooglePB.PhoneType.values().length - 1))).build());
}
GooglePB.PBRequestType request = GooglePB.PBRequestType.newBuilder()
.setAge(15).setCash(10).setMoney(16.0).setNum(100L)
.addAllPhone(phoneNumberList).putAllDoubleMap(phoneNumberMap).build();
return request;
}
@Test
public void testPbNormal() throws Exception {
GooglePB.PBRequestType request = buildPbMessage();
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeObject(request);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput objectInput = serialization.deserialize(url, byteArrayInputStream);
GooglePB.PBRequestType derializedRequest = objectInput.readObject(GooglePB.PBRequestType.class);
assertEquals(request, derializedRequest);
}
/**
* Special test case
* Dubbo protocol will directly writes native map (Invocation.attachments) using protobuf.
* this should definitely be fixed but not done yet.
*/
@Test
public void testPbMap() throws Exception {
Map<String, Object> attachments = new HashMap<>();
attachments.put("key", "value");
ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream);
objectOutput.writeObject(attachments);
objectOutput.flushBuffer();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInput objectInput = serialization.deserialize(url, byteArrayInputStream);
Map<String, Object> derializedAttachments = objectInput.readObject(Map.class);
assertEquals(attachments, derializedAttachments);
}
@Test
public void testPbThrowable() {
}
@Test
public void testNotPb() {
}
}

View File

@ -35,16 +35,16 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class GenericProtobufObjectOutputTest {
public class GenericProtobufJsonObjectOutputTest {
private ByteArrayOutputStream byteArrayOutputStream;
private GenericProtobufObjectOutput genericProtobufObjectOutput;
private GenericProtobufObjectInput genericProtobufObjectInput;
private GenericProtobufJsonObjectOutput genericProtobufObjectOutput;
private GenericProtobufJsonObjectInput genericProtobufObjectInput;
private ByteArrayInputStream byteArrayInputStream;
@BeforeEach
public void setUp() {
this.byteArrayOutputStream = new ByteArrayOutputStream();
this.genericProtobufObjectOutput = new GenericProtobufObjectOutput(byteArrayOutputStream);
this.genericProtobufObjectOutput = new GenericProtobufJsonObjectOutput(byteArrayOutputStream);
}
@Test
@ -200,7 +200,7 @@ public class GenericProtobufObjectOutputTest {
private void flushToInput() {
this.genericProtobufObjectOutput.flushBuffer();
this.byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
this.genericProtobufObjectInput = new GenericProtobufObjectInput(byteArrayInputStream);
this.genericProtobufObjectInput = new GenericProtobufJsonObjectInput(byteArrayInputStream);
}
}

View File

@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.serialize.protobuf.support;
public class GenericProtobufJsonSerializationTest extends AbstractProtobufSerializationTest {
{
serialization = new GenericProtobufJsonSerialization();
}
}

View File

@ -16,11 +16,8 @@
*/
package org.apache.dubbo.common.serialize.protobuf.support;
import org.apache.dubbo.common.serialize.base.AbstractSerializationTest;
import org.apache.dubbo.common.serialize.protostuff.ProtostuffSerialization;
public class GenericProtobufSerializationTest extends AbstractSerializationTest {
public class GenericProtobufSerializationTest extends AbstractProtobufSerializationTest {
{
serialization = new ProtostuffSerialization();
serialization = new GenericProtobufSerialization();
}
}

View File

@ -40,7 +40,7 @@
<module>dubbo-serialization-avro</module>
<module>dubbo-serialization-test</module>
<module>dubbo-serialization-gson</module>
<module>dubbo-serialization-protobuf-json</module>
<module>dubbo-serialization-protobuf</module>
<module>dubbo-serialization-native-hession</module>
</modules>
</project>