1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Author: kenton@google.com (Kenton Varda)
9 // Based on original Protocol Buffers design by
10 // Sanjay Ghemawat, Jeff Dean, and others.
11
12 #include "google/protobuf/compiler/java/generator.h"
13
14 #include <utility>
15 #include <vector>
16
17 #include "google/protobuf/compiler/code_generator.h"
18
19
20 #include <memory>
21
22 #include "absl/strings/str_format.h"
23 #include "google/protobuf/compiler/java/file.h"
24 #include "google/protobuf/compiler/java/helpers.h"
25 #include "google/protobuf/compiler/java/name_resolver.h"
26 #include "google/protobuf/compiler/java/options.h"
27 #include "google/protobuf/compiler/java/shared_code_generator.h"
28 #include "google/protobuf/descriptor.pb.h"
29
30
31 namespace google {
32 namespace protobuf {
33 namespace compiler {
34 namespace java {
35
36
JavaGenerator()37 JavaGenerator::JavaGenerator() {}
~JavaGenerator()38 JavaGenerator::~JavaGenerator() {}
39
GetSupportedFeatures() const40 uint64_t JavaGenerator::GetSupportedFeatures() const {
41 return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL |
42 CodeGenerator::Feature::FEATURE_SUPPORTS_EDITIONS;
43 }
44
Generate(const FileDescriptor * file,const std::string & parameter,GeneratorContext * context,std::string * error) const45 bool JavaGenerator::Generate(const FileDescriptor* file,
46 const std::string& parameter,
47 GeneratorContext* context,
48 std::string* error) const {
49 // -----------------------------------------------------------------
50 // parse generator options
51
52 std::vector<std::pair<std::string, std::string> > options;
53 ParseGeneratorParameter(parameter, &options);
54 Options file_options;
55
56 file_options.opensource_runtime = opensource_runtime_;
57
58 for (auto& option : options) {
59 if (option.first == "output_list_file") {
60 file_options.output_list_file = option.second;
61 } else if (option.first == "immutable") {
62 file_options.generate_immutable_code = true;
63 } else if (option.first == "mutable") {
64 file_options.generate_mutable_code = true;
65 } else if (option.first == "shared") {
66 file_options.generate_shared_code = true;
67 } else if (option.first == "lite") {
68 // Note: Java Lite does not guarantee API/ABI stability. We may choose to
69 // break existing API in order to boost performance / reduce code size.
70 file_options.enforce_lite = true;
71 } else if (option.first == "annotate_code") {
72 file_options.annotate_code = true;
73 } else if (option.first == "annotation_list_file") {
74 file_options.annotation_list_file = option.second;
75 } else if (option.first == "experimental_strip_nonfunctional_codegen") {
76 file_options.strip_nonfunctional_codegen = true;
77 } else {
78 *error = absl::StrCat("Unknown generator option: ", option.first);
79 return false;
80 }
81 }
82
83 if (file_options.enforce_lite && file_options.generate_mutable_code) {
84 *error = "lite runtime generator option cannot be used with mutable API.";
85 return false;
86 }
87
88 // By default we generate immutable code and shared code for immutable API.
89 if (!file_options.generate_immutable_code &&
90 !file_options.generate_mutable_code &&
91 !file_options.generate_shared_code) {
92 file_options.generate_immutable_code = true;
93 file_options.generate_shared_code = true;
94 }
95
96 // -----------------------------------------------------------------
97
98
99 std::vector<std::string> all_files;
100 std::vector<std::string> all_annotations;
101
102
103 std::vector<std::unique_ptr<FileGenerator>> file_generators;
104 if (file_options.generate_immutable_code) {
105 file_generators.emplace_back(
106 std::make_unique<FileGenerator>(file, file_options,
107 /* immutable = */ true));
108 }
109 if (file_options.generate_mutable_code) {
110 file_generators.emplace_back(
111 std::make_unique<FileGenerator>(file, file_options,
112 /* mutable = */ false));
113 }
114
115 for (auto& file_generator : file_generators) {
116 if (!file_generator->Validate(error)) {
117 return false;
118 }
119 }
120
121 for (auto& file_generator : file_generators) {
122 std::string package_dir = JavaPackageToDir(file_generator->java_package());
123
124 std::string java_filename =
125 absl::StrCat(package_dir, file_generator->classname(), ".java");
126 all_files.push_back(java_filename);
127 std::string info_full_path = absl::StrCat(java_filename, ".pb.meta");
128 if (file_options.annotate_code) {
129 all_annotations.push_back(info_full_path);
130 }
131
132 // Generate main java file.
133 std::unique_ptr<io::ZeroCopyOutputStream> output(
134 context->Open(java_filename));
135 GeneratedCodeInfo annotations;
136 io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
137 &annotations);
138 io::Printer printer(
139 output.get(), '$',
140 file_options.annotate_code ? &annotation_collector : nullptr);
141
142 file_generator->Generate(&printer);
143
144 // Generate sibling files.
145 file_generator->GenerateSiblings(package_dir, context, &all_files,
146 &all_annotations);
147
148 if (file_options.annotate_code) {
149 std::unique_ptr<io::ZeroCopyOutputStream> info_output(
150 context->Open(info_full_path));
151 annotations.SerializeToZeroCopyStream(info_output.get());
152 }
153 }
154
155
156 file_generators.clear();
157
158 // Generate output list if requested.
159 if (!file_options.output_list_file.empty()) {
160 // Generate output list. This is just a simple text file placed in a
161 // deterministic location which lists the .java files being generated.
162 std::unique_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
163 context->Open(file_options.output_list_file));
164 io::Printer srclist_printer(srclist_raw_output.get(), '$');
165 for (int i = 0; i < all_files.size(); i++) {
166 srclist_printer.Print("$filename$\n", "filename", all_files[i]);
167 }
168 }
169
170 if (!file_options.annotation_list_file.empty()) {
171 // Generate output list. This is just a simple text file placed in a
172 // deterministic location which lists the .java files being generated.
173 std::unique_ptr<io::ZeroCopyOutputStream> annotation_list_raw_output(
174 context->Open(file_options.annotation_list_file));
175 io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
176 for (int i = 0; i < all_annotations.size(); i++) {
177 annotation_list_printer.Print("$filename$\n", "filename",
178 all_annotations[i]);
179 }
180 }
181
182 return true;
183 }
184
185 } // namespace java
186 } // namespace compiler
187 } // namespace protobuf
188 } // namespace google
189