Merge "Fix outer classname for javamicro/javanano."
This commit is contained in:
commit
062d561e31
326
java/README.txt
326
java/README.txt
@ -91,9 +91,11 @@ Micro version
|
||||
============================
|
||||
|
||||
The runtime and generated code for MICRO_RUNTIME is smaller
|
||||
because it does not include support for the descriptor,
|
||||
reflection or extensions. Also, not currently supported
|
||||
are packed repeated elements nor testing of java_multiple_files.
|
||||
because it does not include support for the descriptor and
|
||||
reflection, and enums are generated as integer constants in
|
||||
the parent message or the file's outer class. Also, not
|
||||
currently supported are packed repeated elements or
|
||||
extensions.
|
||||
|
||||
To create a jar file for the runtime and run tests invoke
|
||||
"mvn package -P micro" from the <protobuf-root>/java
|
||||
@ -128,26 +130,24 @@ opt -> speed or space
|
||||
java_use_vector -> true or false
|
||||
java_package -> <file-name>|<package-name>
|
||||
java_outer_classname -> <file-name>|<package-name>
|
||||
java_multiple_files -> true or false
|
||||
|
||||
opt:
|
||||
This changes the code generation to optimize for speed,
|
||||
opt=speed, or space, opt=space. When opt=speed this
|
||||
changes the code generation for strings so that multiple
|
||||
conversions to Utf8 are eliminated. The default value
|
||||
is opt=space.
|
||||
opt={speed,space} (default: space)
|
||||
This changes the code generation to optimize for speed or
|
||||
space. When opt=speed this changes the code generation
|
||||
for strings so that multiple conversions to Utf8 are
|
||||
eliminated.
|
||||
|
||||
java_use_vector:
|
||||
Is a boolean flag either java_use_vector=true or
|
||||
java_use_vector=false. When java_use_vector=true the
|
||||
code generated for repeated elements uses
|
||||
java.util.Vector and when java_use_vector=false the
|
||||
java.util.ArrayList<> is used. When java.util.Vector
|
||||
is used the code must be compiled with Java 1.3 and
|
||||
when ArrayList is used Java 1.5 or above must be used.
|
||||
The using javac the source parameter may be used to
|
||||
control the version of the source: "javac -source 1.3".
|
||||
You can also change the <source> xml element for the
|
||||
maven-compiler-plugin. Below is for 1.5 sources:
|
||||
java_use_vector={true,false} (default: false)
|
||||
This specifies the collection class for repeated elements.
|
||||
If false, repeated elements use java.util.ArrayList<> and
|
||||
the code must be compiled with Java 1.5 or above. If true,
|
||||
repeated elements use java.util.Vector and the code can
|
||||
be compiled with Java 1.3 or above. The 'source'
|
||||
parameter of 'javac' may be used to control the version
|
||||
of the source: "javac -source 1.3". You can also change
|
||||
the <source> xml element for the maven-compiler-plugin.
|
||||
Below is for 1.5 sources:
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
@ -157,11 +157,8 @@ java_use_vector:
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
When compiling for 1.5 java_use_vector=false or not
|
||||
present where the default value is false.
|
||||
|
||||
And below would be for 1.3 sources note when changing
|
||||
to 1.3 you must also set java_use_vector=true:
|
||||
And below would be for 1.3 sources (note when changing
|
||||
to 1.3 you must also set java_use_vector=true):
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
@ -171,93 +168,241 @@ java_use_vector:
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
java_package:
|
||||
The allows setting/overriding the java_package option
|
||||
and associates allows a package name for a file to
|
||||
be specified on the command line. Overriding any
|
||||
"option java_package xxxx" in the file. The default
|
||||
if not present is to use the value from the package
|
||||
statment or "option java_package xxxx" in the file.
|
||||
java_package=<file-name>|<package-name> (no default)
|
||||
This allows overriding the 'java_package' option value
|
||||
for the given file from the command line. Use multiple
|
||||
java_package options to override the option for multiple
|
||||
files. The final Java package for each file is the value
|
||||
of this command line option if present, or the value of
|
||||
the same option defined in the file if present, or the
|
||||
proto package if present, or the default Java package.
|
||||
|
||||
java_outer_classname=<file-name>|<outer-classname> (no default)
|
||||
This allows overriding the 'java_outer_classname' option
|
||||
for the given file from the command line. Use multiple
|
||||
java_outer_classname options to override the option for
|
||||
multiple files. The final Java outer class name for each
|
||||
file is the value of this command line option if present,
|
||||
or the value of the same option defined in the file if
|
||||
present, or the file name converted to CamelCase. This
|
||||
outer class will nest all classes and integer constants
|
||||
generated from file-scope messages and enums.
|
||||
|
||||
java_multiple_files={true,false} (no default)
|
||||
This allows overriding the 'java_multiple_files' option
|
||||
in all source files and their imported files from the
|
||||
command line. The final value of this option for each
|
||||
file is the value defined in this command line option, or
|
||||
the value of the same option defined in the file if
|
||||
present, or false. This specifies whether to generate
|
||||
package-level classes for the file-scope messages in the
|
||||
same Java package as the outer class (instead of nested
|
||||
classes in the outer class). File-scope enum constants
|
||||
are still generated as integer constants in the outer
|
||||
class. This affects the fully qualified references in the
|
||||
Java code. NOTE: because the command line option
|
||||
overrides the value for all files and their imported
|
||||
files, using this option inconsistently may result in
|
||||
incorrect references to the imported messages and enum
|
||||
constants.
|
||||
|
||||
|
||||
IMPORTANT: change of javamicro_out behavior:
|
||||
|
||||
In previous versions, if the outer class name has not been
|
||||
given explicitly, javamicro_out would not infer the outer
|
||||
class name from the file name, and would skip the outer
|
||||
class generation. This makes the compilation succeed only
|
||||
if the source file contains a single message and no enums,
|
||||
and the generated class for that message is placed at the
|
||||
package level. To re-align with java_out, javamicro_out
|
||||
will now always generate the outer class, inferring its
|
||||
name from the file name if not given, as a container of the
|
||||
message classes and enum constants. To keep any existing
|
||||
single-message source file from causing the generation of
|
||||
an unwanted outer class, you can set the option
|
||||
java_multiple_files to true, either in the file or as a
|
||||
command line option.
|
||||
|
||||
java_outer_classname:
|
||||
This allows the setting/overriding of the outer
|
||||
class name option and associates a class name
|
||||
to a file. An outer class name is required and
|
||||
must be specified if there are multiple messages
|
||||
in a single proto file either in the proto source
|
||||
file or on the command line. If not present the
|
||||
no outer class name will be used.
|
||||
|
||||
Below are a series of examples for clarification of the
|
||||
various javamicro_out parameters using
|
||||
src/test/proto/simple-data.proto:
|
||||
various parameters and options. Assuming this file:
|
||||
|
||||
package testprotobuf;
|
||||
src/proto/simple-data-protos.proto:
|
||||
|
||||
message SimpleData {
|
||||
optional fixed64 id = 1;
|
||||
optional string description = 2;
|
||||
optional bool ok = 3 [default = false];
|
||||
};
|
||||
package testprotobuf;
|
||||
|
||||
message SimpleData {
|
||||
optional fixed64 id = 1;
|
||||
optional string description = 2;
|
||||
optional bool ok = 3 [default = false];
|
||||
};
|
||||
|
||||
Assuming you've only compiled and not installed protoc and
|
||||
your current working directory java/, then a simple
|
||||
command line to compile simple-data would be:
|
||||
and the compiled protoc in the current working directory,
|
||||
then a simple command line to compile this file would be:
|
||||
|
||||
../src/protoc --javamicro_out=. src/test/proto/simple-data.proto
|
||||
./protoc --javamicro_out=. src/proto/simple-data-protos.proto
|
||||
|
||||
This will create testprotobuf/SimpleData.java
|
||||
This will create testprotobuf/SimpleDataProtos.java, which
|
||||
has the following content (extremely simplified):
|
||||
|
||||
The directory testprotobuf is created because on line 1
|
||||
of simple-data.proto is "package testprotobuf;". If you
|
||||
wanted a different package name you could use the
|
||||
java_package option command line sub-parameter:
|
||||
package testprotobuf;
|
||||
|
||||
../src/protoc '--javamicro_out=java_package=src/test/proto/simple-data.proto|my_package:.' src/test/proto/simple-data.proto
|
||||
public final class SimpleDataProtos {
|
||||
public static final class SimpleData
|
||||
extends MessageMicro {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
The message SimpleData is compiled into the SimpleData
|
||||
class, nested in the file's outer class SimpleDataProtos,
|
||||
whose name is implicitly defined by the proto file name
|
||||
"simple-data-protos".
|
||||
|
||||
The directory, aka Java package, testprotobuf is created
|
||||
because on line 1 of simple-data-protos.proto is
|
||||
"package testprotobuf;". If you wanted a different
|
||||
package name you could use the java_package option in the
|
||||
file:
|
||||
|
||||
option java_package = "my_package";
|
||||
|
||||
or in command line sub-parameter:
|
||||
|
||||
./protoc '--javamicro_out=\
|
||||
java_package=src/proto/simple-data-protos.proto|my_package:\
|
||||
.' src/proto/simple-data-protos.proto
|
||||
|
||||
Here you see the new java_package sub-parameter which
|
||||
itself needs two parameters the file name and the
|
||||
package name, these are separated by "|". Now you'll
|
||||
find my_package/SimpleData.java.
|
||||
package name, these are separated by "|". The value set
|
||||
in the command line overrides the value set in the file.
|
||||
Now you'll find SimpleDataProtos.java in the my_package/
|
||||
directory.
|
||||
|
||||
If you wanted to also change the optimization for
|
||||
speed you'd add opt=speed with the comma seperator
|
||||
as follows:
|
||||
|
||||
../src/protoc '--javamicro_out=opt=speed,java_package=src/test/proto/simple-data.proto|my_package:.' src/test/proto/simple-data.proto
|
||||
./protoc '--javamicro_out=\
|
||||
opt=speed,\
|
||||
java_package=src/proto/simple-data-protos.proto|my_package:
|
||||
.' src/proto/simple-data-protos.proto
|
||||
|
||||
Finally if you also wanted an outer class name you'd
|
||||
If you also wanted a different outer class name you'd
|
||||
do the following:
|
||||
|
||||
../src/protoc '--javamicro_out=opt=speed,java_package=src/test/proto/simple-data.proto|my_package,java_outer_classname=src/test/proto/simple-data.proto|OuterName:.' src/test/proto/simple-data.proto
|
||||
./protoc '--javamicro_out=\
|
||||
opt=speed,\
|
||||
java_package=src/proto/simple-data-protos.proto|my_package,\
|
||||
java_outer_classname=src/proto/simple-data-protos.proto|OuterName:\
|
||||
.' src/proto/simple-data-protos.proto
|
||||
|
||||
Now you'll find my_packate/OuterName.java.
|
||||
Now you'll find my_package/OuterName.java and the
|
||||
message class SimpleData nested in it.
|
||||
|
||||
As mentioned java_package and java_outer_classname
|
||||
may also be specified in the file. In the example
|
||||
below we must define java_outer_classname because
|
||||
there are multiple messages in
|
||||
src/test/proto/two-messages.proto
|
||||
As mentioned java_package, java_outer_classname and
|
||||
java_multiple_files may also be specified in the file.
|
||||
In the example below we must define
|
||||
java_outer_classname because otherwise the outer class
|
||||
and one of the message classes will have the same name,
|
||||
which is forbidden to prevent name ambiguity:
|
||||
|
||||
package testmicroruntime;
|
||||
src/proto/sample-message.proto:
|
||||
|
||||
option java_package = "com.example";
|
||||
option java_outer_classname = "TestMessages";
|
||||
package testmicroruntime;
|
||||
|
||||
message TestMessage1 {
|
||||
required int32 id = 1;
|
||||
}
|
||||
option java_package = "com.example";
|
||||
option java_outer_classname = "SampleMessageProtos";
|
||||
|
||||
message TestMessage2 {
|
||||
required int32 id = 1;
|
||||
}
|
||||
enum MessageType {
|
||||
SAMPLE = 1;
|
||||
EXAMPLE = 2;
|
||||
}
|
||||
|
||||
message SampleMessage {
|
||||
required int32 id = 1;
|
||||
required MessageType type = 2;
|
||||
}
|
||||
|
||||
message SampleMessageContainer {
|
||||
required SampleMessage message = 1;
|
||||
}
|
||||
|
||||
This could be compiled using:
|
||||
|
||||
../src/protoc --javamicro_out=. src/test/proto/two-message.proto
|
||||
./protoc --javamicro_out=. src/proto/sample-message.proto
|
||||
|
||||
With the result will be com/example/TestMessages.java
|
||||
and the output will be:
|
||||
|
||||
com/example/SampleMessageProtos.java:
|
||||
|
||||
package com.example;
|
||||
|
||||
public final class SampleMessageProtos {
|
||||
public static final int SAMPLE = 1;
|
||||
public static final int EXAMPLE = 2;
|
||||
public static final class SampleMessage
|
||||
extends MessageMicro {
|
||||
...
|
||||
}
|
||||
public static final class SampleMessageContainer
|
||||
extends MessageMicro {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
As you can see the file-scope enum MessageType is
|
||||
disassembled into two integer constants in the outer class.
|
||||
In javamicro_out, all enums are disassembled and compiled
|
||||
into integer constants in the parent scope (the containing
|
||||
message's class or the file's (i.e. outer) class).
|
||||
|
||||
You may prefer the file-scope messages to be saved in
|
||||
separate files. You can do this by setting the option
|
||||
java_multiple_files to true, in either the file like this:
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
or the command line like this:
|
||||
|
||||
./protoc --javamicro_out=\
|
||||
java_multiple_files=true:\
|
||||
. src/proto/sample-message.proto
|
||||
|
||||
The java_multiple_files option causes javamicro to use a
|
||||
separate file for each file-scope message, which resides
|
||||
directly in the Java package alongside the outer class:
|
||||
|
||||
com/example/SampleMessageProtos.java:
|
||||
|
||||
package com.example;
|
||||
public final class SampleMessageProtos {
|
||||
public static final int SAMPLE = 1;
|
||||
public static final int EXAMPLE = 2;
|
||||
}
|
||||
|
||||
com/example/SampleMessage.java:
|
||||
|
||||
package com.example;
|
||||
public final class SampleMessage
|
||||
extends MessageMicro {
|
||||
...
|
||||
}
|
||||
|
||||
com/example/SampleMessageContainer.java:
|
||||
|
||||
package com.example;
|
||||
public final class SampleMessageContainer
|
||||
extends MessageMicro {
|
||||
...
|
||||
}
|
||||
|
||||
As you can see, the outer class now contains only the
|
||||
integer constants, generated from the file-scope enum
|
||||
"MessageType". Please note that message-scope enums are
|
||||
still generated as integer constants in the message class.
|
||||
|
||||
|
||||
Nano version
|
||||
@ -303,9 +448,19 @@ empty default.
|
||||
|
||||
Nano Generator options
|
||||
|
||||
java_nano_generate_has:
|
||||
java_package -> <file-name>|<package-name>
|
||||
java_outer_classname -> <file-name>|<package-name>
|
||||
java_multiple_files -> true or false
|
||||
java_nano_generate_has -> true or false
|
||||
|
||||
java_package:
|
||||
java_outer_classname:
|
||||
java_multiple_files:
|
||||
Same as Micro version.
|
||||
|
||||
java_nano_generate_has={true,false} (default: false)
|
||||
If true, generates a public boolean variable has<fieldname>
|
||||
accompanying the optional or required field (not present for
|
||||
accompanying each optional or required field (not present for
|
||||
repeated fields, groups or messages). It is set to false initially
|
||||
and upon clear(). If parseFrom(...) reads the field from the wire,
|
||||
it is set to true. This is a way for clients to inspect the "has"
|
||||
@ -324,7 +479,10 @@ To use nano protobufs:
|
||||
<protobuf-root>java/target/protobuf-java-2.3.0-nano.jar.
|
||||
- Invoke with --javanano_out, e.g.:
|
||||
|
||||
../src/protoc '--javanano_out=java_package=src/test/proto/simple-data.proto|my_package,java_outer_classname=src/test/proto/simple-data.proto|OuterName:.' src/test/proto/simple-data.proto
|
||||
./protoc '--javanano_out=\
|
||||
java_package=src/proto/simple-data.proto|my_package,\
|
||||
java_outer_classname=src/proto/simple-data.proto|OuterName:\
|
||||
.' src/proto/simple-data.proto
|
||||
|
||||
Contributing to nano:
|
||||
|
||||
|
@ -33,16 +33,22 @@ package com.google.protobuf;
|
||||
import com.google.protobuf.nano.CodedInputByteBufferNano;
|
||||
import com.google.protobuf.nano.Extensions;
|
||||
import com.google.protobuf.nano.Extensions.AnotherMessage;
|
||||
import com.google.protobuf.nano.FileScopeEnumRefNano;
|
||||
import com.google.protobuf.nano.InternalNano;
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
import com.google.protobuf.nano.MessageScopeEnumRefNano;
|
||||
import com.google.protobuf.nano.MultipleImportingNonMultipleNano1;
|
||||
import com.google.protobuf.nano.MultipleImportingNonMultipleNano2;
|
||||
import com.google.protobuf.nano.MultipleNameClashNano;
|
||||
import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
|
||||
import com.google.protobuf.nano.NanoOuterClass;
|
||||
import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
|
||||
import com.google.protobuf.nano.RecursiveMessageNano;
|
||||
import com.google.protobuf.nano.SimpleMessageNano;
|
||||
import com.google.protobuf.nano.UnittestImportNano;
|
||||
import com.google.protobuf.nano.UnittestMultipleNano;
|
||||
import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
|
||||
import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
|
||||
import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
|
||||
import com.google.protobuf.nano.UnittestStringutf8Nano.StringUtf8;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -2061,6 +2067,41 @@ public class NanoTest extends TestCase {
|
||||
assertEquals(nestedMsg2.bb, newMsg.repeatedNestedMessage[2].bb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that code generation correctly wraps a single message into its outer
|
||||
* class. The class {@code SingleMessageNano} is imported from the outer
|
||||
* class {@code UnittestSingleNano}, whose name is implicit. Any error would
|
||||
* cause this method to fail compilation.
|
||||
*/
|
||||
public void testNanoSingle() throws Exception {
|
||||
SingleMessageNano msg = new SingleMessageNano();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that code generation correctly skips generating the outer class if
|
||||
* unnecessary, letting a file-scope entity have the same name. The class
|
||||
* {@code MultipleNameClashNano} shares the same name with the file's outer
|
||||
* class defined explicitly, but the file contains no other entities and has
|
||||
* java_multiple_files set. Any error would cause this method to fail
|
||||
* compilation.
|
||||
*/
|
||||
public void testNanoMultipleNameClash() throws Exception {
|
||||
MultipleNameClashNano msg = new MultipleNameClashNano();
|
||||
msg.field = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that code generation correctly handles enums in different scopes in
|
||||
* a source file with the option java_multiple_files set to true. Any error
|
||||
* would cause this method to fail compilation.
|
||||
*/
|
||||
public void testNanoMultipleEnumScoping() throws Exception {
|
||||
FileScopeEnumRefNano msg1 = new FileScopeEnumRefNano();
|
||||
msg1.enumField = UnittestMultipleNano.ONE;
|
||||
MessageScopeEnumRefNano msg2 = new MessageScopeEnumRefNano();
|
||||
msg2.enumField = MessageScopeEnumRefNano.TWO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that code generation with mixed values of the java_multiple_files
|
||||
* options between the main source file and the imported source files would
|
||||
|
@ -69,18 +69,6 @@ EnumGenerator::~EnumGenerator() {}
|
||||
|
||||
void EnumGenerator::Generate(io::Printer* printer) {
|
||||
printer->Print("// enum $classname$\n", "classname", descriptor_->name());
|
||||
const string& file_name = descriptor_->file()->name();
|
||||
bool is_own_file = params_.java_multiple_files(file_name) ||
|
||||
((descriptor_->containing_type() == NULL) &&
|
||||
!params_.has_java_outer_classname(file_name));
|
||||
|
||||
if (is_own_file) {
|
||||
printer->Print("public final class $classname$ {\n", "classname",
|
||||
descriptor_->name());
|
||||
printer->Indent();
|
||||
printer->Print("private $classname$() {}\n", "classname",
|
||||
descriptor_->name());
|
||||
}
|
||||
for (int i = 0; i < canonical_values_.size(); i++) {
|
||||
map<string, string> vars;
|
||||
vars["name"] = RenameJavaKeywords(canonical_values_[i]->name());
|
||||
@ -99,10 +87,6 @@ void EnumGenerator::Generate(io::Printer* printer) {
|
||||
"public static final int $name$ = $canonical_name$;\n");
|
||||
}
|
||||
|
||||
if (is_own_file) {
|
||||
printer->Outdent();
|
||||
printer->Print("}");
|
||||
}
|
||||
printer->Print("\n");
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <google/protobuf/compiler/javanano/javanano_file.h>
|
||||
#include <google/protobuf/compiler/javanano/javanano_enum.h>
|
||||
#include <google/protobuf/compiler/javanano/javanano_extension.h>
|
||||
@ -103,39 +105,6 @@ bool FileGenerator::Validate(string* error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no outer class name then there must be only
|
||||
// message and no enums defined in the file scope.
|
||||
if (!params_.has_java_outer_classname(file_->name())) {
|
||||
if (file_->message_type_count() != 1) {
|
||||
error->assign(file_->name());
|
||||
error->append(
|
||||
": Java NANO_RUNTIME may only have 1 message if there is no 'option java_outer_classname'\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_->enum_type_count() != 0) {
|
||||
error->assign(file_->name());
|
||||
error->append(
|
||||
": Java NANO_RUNTIME must have an 'option java_outer_classname' if file scope enums are present\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that no class name matches the file's class name. This is a common
|
||||
// problem that leads to Java compile errors that can be hard to understand.
|
||||
// It's especially bad when using the java_multiple_files, since we would
|
||||
// end up overwriting the outer class with one of the inner ones.
|
||||
int found_fileName = 0;
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
if (file_->enum_type(i)->name() == classname_) {
|
||||
found_fileName += 1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
if (file_->message_type(i)->name() == classname_) {
|
||||
found_fileName += 1;
|
||||
}
|
||||
}
|
||||
if (file_->service_count() != 0) {
|
||||
error->assign(file_->name());
|
||||
error->append(
|
||||
@ -143,16 +112,41 @@ bool FileGenerator::Validate(string* error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (found_fileName > 1) {
|
||||
if (!IsOuterClassNeeded(params_, file_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check whether legacy javanano generator would omit the outer class.
|
||||
if (!params_.has_java_outer_classname(file_->name())
|
||||
&& file_->message_type_count() == 1
|
||||
&& file_->enum_type_count() == 0 && file_->extension_count() == 0) {
|
||||
cout << "INFO: " << file_->name() << ":" << endl;
|
||||
cout << "Javanano generator has changed to align with java generator. "
|
||||
"An outer class will be created for this file and the single message "
|
||||
"in the file will become a nested class. Use java_multiple_files to "
|
||||
"skip generating the outer class, or set an explicit "
|
||||
"java_outer_classname to suppress this message." << endl;
|
||||
}
|
||||
|
||||
// Check that no class name matches the file's class name. This is a common
|
||||
// problem that leads to Java compile errors that can be hard to understand.
|
||||
// It's especially bad when using the java_multiple_files, since we would
|
||||
// end up overwriting the outer class with one of the inner ones.
|
||||
bool found_conflict = false;
|
||||
for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) {
|
||||
if (file_->message_type(i)->name() == classname_) {
|
||||
found_conflict = true;
|
||||
}
|
||||
}
|
||||
if (found_conflict) {
|
||||
error->assign(file_->name());
|
||||
error->append(
|
||||
": Cannot generate Java output because there is more than one class name, \"");
|
||||
": Cannot generate Java output because the file's outer class name, \"");
|
||||
error->append(classname_);
|
||||
error->append(
|
||||
"\", matches the name of one of the types declared inside it. "
|
||||
"Please either rename the type or use the java_outer_classname "
|
||||
"option to specify a different outer class name for the .proto file."
|
||||
" -- FIX THIS MESSAGE");
|
||||
"option to specify a different outer class name for the .proto file.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -171,13 +165,11 @@ void FileGenerator::Generate(io::Printer* printer) {
|
||||
"package", java_package_);
|
||||
}
|
||||
|
||||
if (params_.has_java_outer_classname(file_->name())) {
|
||||
printer->Print(
|
||||
"public final class $classname$ {\n"
|
||||
" private $classname$() {}\n",
|
||||
"classname", classname_);
|
||||
printer->Indent();
|
||||
}
|
||||
printer->Print(
|
||||
"public final class $classname$ {\n"
|
||||
" private $classname$() {}\n",
|
||||
"classname", classname_);
|
||||
printer->Indent();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
@ -186,10 +178,13 @@ void FileGenerator::Generate(io::Printer* printer) {
|
||||
ExtensionGenerator(file_->extension(i), params_).Generate(printer);
|
||||
}
|
||||
|
||||
// Enums.
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
EnumGenerator(file_->enum_type(i), params_).Generate(printer);
|
||||
}
|
||||
|
||||
// Messages.
|
||||
if (!params_.java_multiple_files(file_->name())) {
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
EnumGenerator(file_->enum_type(i), params_).Generate(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
MessageGenerator(file_->message_type(i), params_).Generate(printer);
|
||||
}
|
||||
@ -201,11 +196,9 @@ void FileGenerator::Generate(io::Printer* printer) {
|
||||
MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer);
|
||||
}
|
||||
|
||||
if (params_.has_java_outer_classname(file_->name())) {
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n");
|
||||
}
|
||||
|
||||
template<typename GeneratorClass, typename DescriptorClass>
|
||||
@ -239,11 +232,6 @@ void FileGenerator::GenerateSiblings(const string& package_dir,
|
||||
OutputDirectory* output_directory,
|
||||
vector<string>* file_list) {
|
||||
if (params_.java_multiple_files(file_->name())) {
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
GenerateSibling<EnumGenerator>(package_dir, java_package_,
|
||||
file_->enum_type(i),
|
||||
output_directory, file_list, params_);
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
GenerateSibling<MessageGenerator>(package_dir, java_package_,
|
||||
file_->message_type(i),
|
||||
|
@ -138,16 +138,18 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file,
|
||||
|
||||
vector<string> all_files;
|
||||
|
||||
string java_filename = package_dir;
|
||||
java_filename += file_generator.classname();
|
||||
java_filename += ".java";
|
||||
all_files.push_back(java_filename);
|
||||
if (IsOuterClassNeeded(params, file)) {
|
||||
string java_filename = package_dir;
|
||||
java_filename += file_generator.classname();
|
||||
java_filename += ".java";
|
||||
all_files.push_back(java_filename);
|
||||
|
||||
// Generate main java file.
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(java_filename));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.Generate(&printer);
|
||||
// Generate main java file.
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
output_directory->Open(java_filename));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.Generate(&printer);
|
||||
}
|
||||
|
||||
// Generate sibling files.
|
||||
file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
|
||||
|
@ -167,31 +167,20 @@ string StripProto(const string& filename) {
|
||||
}
|
||||
|
||||
string FileClassName(const Params& params, const FileDescriptor* file) {
|
||||
string name;
|
||||
|
||||
if (params.has_java_outer_classname(file->name())) {
|
||||
name = params.java_outer_classname(file->name());
|
||||
return params.java_outer_classname(file->name());
|
||||
} else {
|
||||
if ((file->message_type_count() == 1)
|
||||
|| (file->enum_type_count() == 0)) {
|
||||
// If no outer calls and only one message then
|
||||
// use the message name as the file name
|
||||
name = file->message_type(0)->name();
|
||||
// Use the filename itself with underscores removed
|
||||
// and a CamelCase style name.
|
||||
string basename;
|
||||
string::size_type last_slash = file->name().find_last_of('/');
|
||||
if (last_slash == string::npos) {
|
||||
basename = file->name();
|
||||
} else {
|
||||
// Use the filename it self with underscores removed
|
||||
// and a CamelCase style name.
|
||||
string basename;
|
||||
string::size_type last_slash = file->name().find_last_of('/');
|
||||
if (last_slash == string::npos) {
|
||||
basename = file->name();
|
||||
} else {
|
||||
basename = file->name().substr(last_slash + 1);
|
||||
}
|
||||
name = UnderscoresToCamelCaseImpl(StripProto(basename), true);
|
||||
basename = file->name().substr(last_slash + 1);
|
||||
}
|
||||
return UnderscoresToCamelCaseImpl(StripProto(basename), true);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
string FileJavaPackage(const Params& params, const FileDescriptor* file) {
|
||||
@ -207,38 +196,27 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) {
|
||||
}
|
||||
}
|
||||
|
||||
string ToJavaName(const Params& params, const string& full_name,
|
||||
const FileDescriptor* file) {
|
||||
bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) {
|
||||
// Enums and extensions need the outer class as the scope.
|
||||
if (file->enum_type_count() != 0 || file->extension_count() != 0) {
|
||||
return true;
|
||||
}
|
||||
// Messages need the outer class only if java_multiple_files is false.
|
||||
return !params.java_multiple_files(file->name());
|
||||
}
|
||||
|
||||
string ToJavaName(const Params& params, const string& name, bool is_class,
|
||||
const Descriptor* parent, const FileDescriptor* file) {
|
||||
string result;
|
||||
if (params.java_multiple_files(file->name())) {
|
||||
result = FileJavaPackage(params, file);
|
||||
if (parent != NULL) {
|
||||
result.append(ClassName(params, parent));
|
||||
} else if (is_class && params.java_multiple_files(file->name())) {
|
||||
result.append(FileJavaPackage(params, file));
|
||||
} else {
|
||||
result = ClassName(params, file);
|
||||
}
|
||||
if (file->package().empty()) {
|
||||
result += '.';
|
||||
result += full_name;
|
||||
} else {
|
||||
// Strip the proto package from full_name since we've replaced it with
|
||||
// the Java package. If there isn't an outer classname then strip it too.
|
||||
int sizeToSkipPackageName = file->package().size();
|
||||
int sizeToSkipOutClassName;
|
||||
if (params.has_java_outer_classname(file->name())) {
|
||||
sizeToSkipOutClassName = 0;
|
||||
} else {
|
||||
sizeToSkipOutClassName =
|
||||
full_name.find_first_of('.', sizeToSkipPackageName + 1);
|
||||
}
|
||||
int sizeToSkip = sizeToSkipOutClassName > 0 ?
|
||||
sizeToSkipOutClassName : sizeToSkipPackageName;
|
||||
string class_name = full_name.substr(sizeToSkip + 1);
|
||||
if (class_name == FileClassName(params, file)) {
|
||||
// Done class_name is already present.
|
||||
} else {
|
||||
result += '.';
|
||||
result += class_name;
|
||||
}
|
||||
result.append(ClassName(params, file));
|
||||
}
|
||||
if (!result.empty()) result.append(1, '.');
|
||||
result.append(RenameJavaKeywords(name));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -250,61 +228,14 @@ string ClassName(const Params& params, const FileDescriptor* descriptor) {
|
||||
}
|
||||
|
||||
string ClassName(const Params& params, const EnumDescriptor* descriptor) {
|
||||
string result;
|
||||
const FileDescriptor* file = descriptor->file();
|
||||
const string file_name = file->name();
|
||||
const string full_name = descriptor->full_name();
|
||||
|
||||
// Remove enum class name as we use int's for enums
|
||||
int last_dot_in_name = full_name.find_last_of('.');
|
||||
string base_name = full_name.substr(0, last_dot_in_name);
|
||||
|
||||
if (!file->package().empty()) {
|
||||
if (file->package() == base_name.substr(0, file->package().size())) {
|
||||
// Remove package name leaving just the parent class of the enum
|
||||
int offset = file->package().size();
|
||||
if (base_name.size() > offset) {
|
||||
// Remove period between package and class name if there is a classname
|
||||
offset += 1;
|
||||
}
|
||||
base_name = base_name.substr(offset);
|
||||
} else {
|
||||
GOOGLE_LOG(FATAL) << "Expected package name to start an enum";
|
||||
}
|
||||
// An enum's class name is the enclosing message's class name or the outer
|
||||
// class name.
|
||||
const Descriptor* parent = descriptor->containing_type();
|
||||
if (parent != NULL) {
|
||||
return ClassName(params, parent);
|
||||
} else {
|
||||
return ClassName(params, descriptor->file());
|
||||
}
|
||||
|
||||
// Construct the path name from the package and outer class
|
||||
|
||||
// Add the java package name if it exists
|
||||
if (params.has_java_package(file_name)) {
|
||||
result += params.java_package(file_name);
|
||||
}
|
||||
|
||||
// If the java_multiple_files option is present, we will generate enums into separate
|
||||
// classes, each named after the original enum type. This takes precedence over
|
||||
// any outer_classname.
|
||||
if (params.java_multiple_files(file_name) && last_dot_in_name != string::npos) {
|
||||
string enum_simple_name = full_name.substr(last_dot_in_name + 1);
|
||||
if (!result.empty()) {
|
||||
result += ".";
|
||||
}
|
||||
result += enum_simple_name;
|
||||
} else if (params.has_java_outer_classname(file_name)) {
|
||||
// Add the outer classname if it exists
|
||||
if (!result.empty()) {
|
||||
result += ".";
|
||||
}
|
||||
result += params.java_outer_classname(file_name);
|
||||
}
|
||||
|
||||
// Create the full class name from the base and path
|
||||
if (!base_name.empty()) {
|
||||
if (!result.empty()) {
|
||||
result += ".";
|
||||
}
|
||||
result += base_name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string FieldConstantName(const FieldDescriptor *field) {
|
||||
|
@ -73,25 +73,35 @@ string FileClassName(const Params& params, const FileDescriptor* file);
|
||||
// Returns the file's Java package name.
|
||||
string FileJavaPackage(const Params& params, const FileDescriptor* file);
|
||||
|
||||
// Converts the given fully-qualified name in the proto namespace to its
|
||||
// fully-qualified name in the Java namespace, given that it is in the given
|
||||
// file.
|
||||
string ToJavaName(const Params& params, const string& full_name,
|
||||
const FileDescriptor* file);
|
||||
// Returns whether the Java outer class is needed, i.e. whether the option
|
||||
// java_multiple_files is false, or the proto file contains any file-scope
|
||||
// enums/extensions.
|
||||
bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file);
|
||||
|
||||
// Converts the given simple name of a proto entity to its fully-qualified name
|
||||
// in the Java namespace, given that it is in the given file enclosed in the
|
||||
// given parent message (or NULL for file-scope entities). Whether the file's
|
||||
// outer class name should be included in the return value depends on factors
|
||||
// inferrable from the given arguments, including is_class which indicates
|
||||
// whether the entity translates to a Java class.
|
||||
string ToJavaName(const Params& params, const string& name, bool is_class,
|
||||
const Descriptor* parent, const FileDescriptor* file);
|
||||
|
||||
// These return the fully-qualified class name corresponding to the given
|
||||
// descriptor.
|
||||
inline string ClassName(const Params& params, const Descriptor* descriptor) {
|
||||
return ToJavaName(params, descriptor->full_name(), descriptor->file());
|
||||
return ToJavaName(params, descriptor->name(), true,
|
||||
descriptor->containing_type(), descriptor->file());
|
||||
}
|
||||
string ClassName(const Params& params, const EnumDescriptor* descriptor);
|
||||
inline string ClassName(const Params& params,
|
||||
const ServiceDescriptor* descriptor) {
|
||||
return ToJavaName(params, descriptor->full_name(), descriptor->file());
|
||||
return ToJavaName(params, descriptor->name(), true, NULL, descriptor->file());
|
||||
}
|
||||
inline string ExtensionIdentifierName(const Params& params,
|
||||
const FieldDescriptor* descriptor) {
|
||||
return ToJavaName(params, descriptor->full_name(), descriptor->file());
|
||||
return ToJavaName(params, descriptor->name(), false,
|
||||
descriptor->extension_scope(), descriptor->file());
|
||||
}
|
||||
string ClassName(const Params& params, const FileDescriptor* descriptor);
|
||||
|
||||
|
@ -114,7 +114,7 @@ void MessageGenerator::GenerateStaticVariableInitializers(
|
||||
io::Printer* printer) {
|
||||
// Generate static member initializers for all nested types.
|
||||
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
|
||||
// TODO(kenton): Reuse MessageGenerator objects?
|
||||
// TODO(kenton): Reuse MessageGenerator objects?
|
||||
MessageGenerator(descriptor_->nested_type(i), params_)
|
||||
.GenerateStaticVariableInitializers(printer);
|
||||
}
|
||||
@ -124,15 +124,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
|
||||
const string& file_name = descriptor_->file()->name();
|
||||
bool is_own_file =
|
||||
params_.java_multiple_files(file_name)
|
||||
|| ((descriptor_->containing_type() == NULL)
|
||||
&& !params_.has_java_outer_classname(file_name));
|
||||
|
||||
#if 0
|
||||
GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
|
||||
GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
|
||||
GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
|
||||
GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
|
||||
#endif
|
||||
&& descriptor_->containing_type() == NULL;
|
||||
|
||||
if (!params_.store_unknown_fields() &&
|
||||
(descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
|
||||
@ -355,25 +347,21 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
|
||||
|
||||
void MessageGenerator::
|
||||
GenerateParseFromMethods(io::Printer* printer) {
|
||||
bool is_own_file =
|
||||
descriptor_->containing_type() == NULL;
|
||||
|
||||
// Note: These are separate from GenerateMessageSerializationMethods()
|
||||
// because they need to be generated even for messages that are optimized
|
||||
// for code size.
|
||||
printer->Print(
|
||||
"public $static$ $classname$ parseFrom(byte[] data)\n"
|
||||
"public static $classname$ parseFrom(byte[] data)\n"
|
||||
" throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n"
|
||||
" return com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"public $static$ $classname$ parseFrom(\n"
|
||||
"public static $classname$ parseFrom(\n"
|
||||
" com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
|
||||
" throws java.io.IOException {\n"
|
||||
" return new $classname$().mergeFrom(input);\n"
|
||||
"}\n"
|
||||
"\n",
|
||||
"static", (is_own_file ? "static" : ""),
|
||||
"classname", descriptor_->name());
|
||||
}
|
||||
|
||||
|
@ -28,26 +28,14 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: bduff@google.com (Brian Duff)
|
||||
//
|
||||
// Author: maxtroy@google.com (Max Cai)
|
||||
|
||||
package protobuf_unittest_import;
|
||||
|
||||
option java_package = "com.google.protobuf.nano";
|
||||
option java_outer_classname = "NanoEnumsWithMultipleFiles";
|
||||
option java_outer_classname = "MultipleNameClashNano";
|
||||
option java_multiple_files = true;
|
||||
|
||||
enum FirstTopLevelEnum {
|
||||
FIRST_TOP_LEVEL_FIRST = 1;
|
||||
FIRST_TOP_LEVEL_SECOND = 2;
|
||||
}
|
||||
|
||||
enum SecondTopLevelEnum {
|
||||
SECOND_TOP_LEVEL_FIRST = 1;
|
||||
SECOND_TOP_LEVEL_SECOND = 2;
|
||||
}
|
||||
|
||||
message SomeMessage {
|
||||
optional FirstTopLevelEnum first = 1;
|
||||
optional SecondTopLevelEnum second = 2;
|
||||
message MultipleNameClashNano {
|
||||
optional int32 field = 1;
|
||||
}
|
@ -35,9 +35,25 @@ package protobuf_unittest_import;
|
||||
import "google/protobuf/unittest_import_nano.proto";
|
||||
|
||||
option java_package = "com.google.protobuf.nano";
|
||||
option java_outer_classname = "NanoMultipleImportingNonMultiple";
|
||||
option java_multiple_files = true;
|
||||
|
||||
enum FileScopeEnum {
|
||||
ONE = 1;
|
||||
TWO = 2;
|
||||
}
|
||||
|
||||
message FileScopeEnumRefNano {
|
||||
optional FileScopeEnum enum_field = 1;
|
||||
}
|
||||
|
||||
message MessageScopeEnumRefNano {
|
||||
enum MessageScopeEnum {
|
||||
ONE = 1;
|
||||
TWO = 2;
|
||||
}
|
||||
optional MessageScopeEnum enum_field = 1;
|
||||
}
|
||||
|
||||
message MultipleImportingNonMultipleNano1 {
|
||||
optional ImportMessageNano field = 1;
|
||||
}
|
||||
|
@ -34,6 +34,8 @@
|
||||
package protobuf_unittest_import;
|
||||
|
||||
option java_package = "com.google.protobuf.nano";
|
||||
// Explicit outer classname to suppress legacy info.
|
||||
option java_outer_classname = "UnittestRecursiveNano";
|
||||
|
||||
message RecursiveMessageNano {
|
||||
message NestedMessage {
|
||||
|
@ -34,6 +34,8 @@
|
||||
package protobuf_unittest_import;
|
||||
|
||||
option java_package = "com.google.protobuf.nano";
|
||||
// Explicit outer classname to suppress legacy info.
|
||||
option java_outer_classname = "UnittestSimpleNano";
|
||||
|
||||
message SimpleMessageNano {
|
||||
message NestedMessage {
|
||||
|
38
src/google/protobuf/unittest_single_nano.proto
Normal file
38
src/google/protobuf/unittest_single_nano.proto
Normal file
@ -0,0 +1,38 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: maxtroy@google.com (Max Cai)
|
||||
|
||||
package protobuf_unittest_import;
|
||||
|
||||
option java_package = "com.google.protobuf.nano";
|
||||
|
||||
message SingleMessageNano {
|
||||
}
|
@ -34,6 +34,8 @@
|
||||
package protobuf_unittest_import;
|
||||
|
||||
option java_package = "com.google.protobuf.nano";
|
||||
// Explicit outer classname to suppress legacy info.
|
||||
option java_outer_classname = "UnittestStringutf8Nano";
|
||||
|
||||
message StringUtf8 {
|
||||
optional string id = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user