I'm using protobuf and I'm generating JAVA classes from the following proto file.
syntax = "proto3";
enum Greeting {
NONE = 0;
MR = 1;
MRS = 2;
MISS = 3;
}
message Hello {
Greeting greeting = 1;
string name = 2;
}
message Bye {
string name = 1;
}
option java_multiple_files = true;
Now I need to add some code to the generated files and I found that is possible using a custom plugin (https://developers.google.com/protocol-buffers/docs/reference/java-generated#plugins). I'm trying to generate that plugin in Java, something like this.
public class Test {
PluginProtos.CodeGeneratorResponse.getDefaultInstance();
/* Code to get generated files from java_out and use the insertion points */
codeGeneratorResponse.writeTo(System.out);
}
And then I run
protoc --java_out=./classes --plugin=protoc-gen-demo=my-plugin --demo_out=. example.proto
The problem is that on my Test.java main method I don't know how to get access to the files created by the option --java_out so that I can use their insertion points. Currently the CodeGeneratorResponse for the default instance is empty (no files).
Does anybody know how can I get the CodeGeneratorResponse from the --java_out so that I can add more code to the generated classes?
Thanks in advance.
解决方案
I recently struggled with this as well and wasn't able to find a good answer. I finally figured it out after staring at the comments within the CodeGeneratorResponse message for a while.
What threw me off at first was that I was thinking of plugins as a pipeline, where the output from one feeds into the next. However, each plugin gets the exact same input (the parsed .proto files expressed via CodeGeneratorRequest messages), and all the generated code from the plugins (including the built-in ones) gets combined into the output file. However, plugins may modify the output from the previous plugins, which is what insertion points are designed for.
Specifically to your question, you would add a file to the response with the name field getting set to the name of the generated Java file, the insertion_point field getting set to the name of the insertion point at which you want to add code, and the content field getting set to the code you want inserted at that point.
I found this article helpful in creating a simple plugin (in this case in python). As a simple test, I modified the generate_code function from that article to look like this:
def generate_code(request, response):
for proto_file in request.proto_file:
f = response.file.add()
f.name = "Test.java"
f.insertion_point = "outer_class_scope"
f.content = "// Inserting a comment as a test"
Then I ran protoc with the plugin:
$ cat test.proto
syntax = "proto3";
message MyMsg {
int32 num = 1;
}
$ protoc --plugin=protoc-gen-sample=sample_proto_gen.py --java_out=. --sample_out=. test.proto
$ tail -n3 Test.java
// Inserting a comment as a test
// @@protoc_insertion_point(outer_class_scope)
}
Your plugin just needs to be some executable which reads a CodeGeneratorRequest message from stdin and writes a CodeGeneratorResponse message to stdout, so could certainly be written in Java instead. I just chose python as I'm generally more comfortable with it and found this simple example.