• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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