blob: c81723304f35792538cefa87ecdf094f0ba5e21c [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <google/protobuf/compiler/java/java_file.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000036
37#include <memory>
Feng Xiao6ef984a2014-11-10 17:34:54 -080038#ifndef _SHARED_PTR_H
39#include <google/protobuf/stubs/shared_ptr.h>
40#endif
Bo Yang5db21732015-05-21 14:28:59 -070041#include <set>
jieluo@google.com4de8f552014-07-18 00:47:59 +000042
43#include <google/protobuf/compiler/java/java_context.h>
temporal40ee5512008-07-10 02:12:20 +000044#include <google/protobuf/compiler/java/java_enum.h>
Feng Xiaoe841bac2015-12-11 17:09:20 -080045#include <google/protobuf/compiler/java/java_enum_lite.h>
temporal40ee5512008-07-10 02:12:20 +000046#include <google/protobuf/compiler/java/java_extension.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000047#include <google/protobuf/compiler/java/java_generator_factory.h>
temporal40ee5512008-07-10 02:12:20 +000048#include <google/protobuf/compiler/java/java_helpers.h>
49#include <google/protobuf/compiler/java/java_message.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000050#include <google/protobuf/compiler/java/java_name_resolver.h>
51#include <google/protobuf/compiler/java/java_service.h>
jieluo@google.com7db9c092014-08-07 19:03:12 +000052#include <google/protobuf/compiler/java/java_shared_code_generator.h>
temporal40ee5512008-07-10 02:12:20 +000053#include <google/protobuf/compiler/code_generator.h>
54#include <google/protobuf/io/printer.h>
55#include <google/protobuf/io/zero_copy_stream.h>
56#include <google/protobuf/descriptor.pb.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000057#include <google/protobuf/dynamic_message.h>
temporal40ee5512008-07-10 02:12:20 +000058#include <google/protobuf/stubs/strutil.h>
59
60namespace google {
61namespace protobuf {
62namespace compiler {
63namespace java {
64
kenton@google.com24bf56f2008-09-24 20:31:01 +000065namespace {
66
Daniel Martine2416ca2014-11-25 10:37:57 -050067struct FieldDescriptorCompare {
68 bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) {
Daniel Martin153a2262015-04-08 09:53:26 -040069 if(f1 == NULL) {
Daniel Martine2416ca2014-11-25 10:37:57 -050070 return false;
71 }
72 if(f2 == NULL) {
73 return true;
74 }
75 return f1->full_name() < f2->full_name();
76 }
77};
78
79typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> FieldDescriptorSet;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000080
81// Recursively searches the given message to collect extensions.
82// Returns true if all the extensions can be recognized. The extensions will be
83// appended in to the extensions parameter.
84// Returns false when there are unknown fields, in which case the data in the
85// extensions output parameter is not reliable and should be discarded.
86bool CollectExtensions(const Message& message,
Daniel Martine2416ca2014-11-25 10:37:57 -050087 FieldDescriptorSet* extensions) {
kenton@google.com24bf56f2008-09-24 20:31:01 +000088 const Reflection* reflection = message.GetReflection();
89
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000090 // There are unknown fields that could be extensions, thus this call fails.
91 if (reflection->GetUnknownFields(message).field_count() > 0) return false;
kenton@google.com24bf56f2008-09-24 20:31:01 +000092
93 vector<const FieldDescriptor*> fields;
94 reflection->ListFields(message, &fields);
95
96 for (int i = 0; i < fields.size(); i++) {
Daniel Martine2416ca2014-11-25 10:37:57 -050097 if (fields[i]->is_extension()) extensions->insert(fields[i]);
kenton@google.com24bf56f2008-09-24 20:31:01 +000098
kenton@google.comfccb1462009-12-18 02:11:36 +000099 if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
kenton@google.com24bf56f2008-09-24 20:31:01 +0000100 if (fields[i]->is_repeated()) {
101 int size = reflection->FieldSize(message, fields[i]);
102 for (int j = 0; j < size; j++) {
103 const Message& sub_message =
104 reflection->GetRepeatedMessage(message, fields[i], j);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000105 if (!CollectExtensions(sub_message, extensions)) return false;
kenton@google.com24bf56f2008-09-24 20:31:01 +0000106 }
107 } else {
108 const Message& sub_message = reflection->GetMessage(message, fields[i]);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000109 if (!CollectExtensions(sub_message, extensions)) return false;
kenton@google.com24bf56f2008-09-24 20:31:01 +0000110 }
111 }
112 }
113
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000114 return true;
115}
116
117// Finds all extensions in the given message and its sub-messages. If the
118// message contains unknown fields (which could be extensions), then those
119// extensions are defined in alternate_pool.
120// The message will be converted to a DynamicMessage backed by alternate_pool
121// in order to handle this case.
122void CollectExtensions(const FileDescriptorProto& file_proto,
123 const DescriptorPool& alternate_pool,
Daniel Martine2416ca2014-11-25 10:37:57 -0500124 FieldDescriptorSet* extensions,
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000125 const string& file_data) {
126 if (!CollectExtensions(file_proto, extensions)) {
127 // There are unknown fields in the file_proto, which are probably
128 // extensions. We need to parse the data into a dynamic message based on the
129 // builder-pool to find out all extensions.
130 const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName(
131 file_proto.GetDescriptor()->full_name());
132 GOOGLE_CHECK(file_proto_desc)
133 << "Find unknown fields in FileDescriptorProto when building "
134 << file_proto.name()
135 << ". It's likely that those fields are custom options, however, "
136 "descriptor.proto is not in the transitive dependencies. "
137 "This normally should not happen. Please report a bug.";
138 DynamicMessageFactory factory;
Feng Xiaof157a562014-11-14 11:50:31 -0800139 google::protobuf::scoped_ptr<Message> dynamic_file_proto(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000140 factory.GetPrototype(file_proto_desc)->New());
141 GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
142 GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
143
144 // Collect the extensions again from the dynamic message. There should be no
145 // more unknown fields this time, i.e. all the custom options should be
146 // parsed as extensions now.
147 extensions->clear();
148 GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
149 << "Find unknown fields in FileDescriptorProto when building "
150 << file_proto.name()
151 << ". It's likely that those fields are custom options, however, "
152 "those options cannot be recognized in the builder pool. "
153 "This normally should not happen. Please report a bug.";
154 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000155}
156
Bo Yang5db21732015-05-21 14:28:59 -0700157// Compare two field descriptors, returning true if the first should come
158// before the second.
159bool CompareFieldsByName(const FieldDescriptor *a, const FieldDescriptor *b) {
160 return a->full_name() < b->full_name();
161}
162
Daniel Martine2416ca2014-11-25 10:37:57 -0500163// Our static initialization methods can become very, very large.
164// So large that if we aren't careful we end up blowing the JVM's
165// 64K bytes of bytecode/method. Fortunately, since these static
166// methods are executed only once near the beginning of a program,
167// there's usually plenty of stack space available and we can
168// extend our methods by simply chaining them to another method
169// with a tail call. This inserts the sequence call-next-method,
170// end this one, begin-next-method as needed.
171void MaybeRestartJavaMethod(io::Printer* printer,
172 int *bytecode_estimate,
173 int *method_num,
174 const char *chain_statement,
175 const char *method_decl) {
Daniel Martine2416ca2014-11-25 10:37:57 -0500176 // The goal here is to stay under 64K bytes of jvm bytecode/method,
177 // since otherwise we hit a hardcoded limit in the jvm and javac will
178 // then fail with the error "code too large". This limit lets our
179 // estimates be off by a factor of two and still we're okay.
180 static const int bytesPerMethod = 1<<15; // aka 32K
181
182 if ((*bytecode_estimate) > bytesPerMethod) {
183 ++(*method_num);
184 printer->Print(chain_statement, "method_num", SimpleItoa(*method_num));
185 printer->Outdent();
186 printer->Print("}\n");
187 printer->Print(method_decl, "method_num", SimpleItoa(*method_num));
188 printer->Indent();
189 *bytecode_estimate = 0;
190 }
191}
kenton@google.comfccb1462009-12-18 02:11:36 +0000192
Bo Yang5db21732015-05-21 14:28:59 -0700193
kenton@google.com24bf56f2008-09-24 20:31:01 +0000194} // namespace
195
jieluo@google.com4de8f552014-07-18 00:47:59 +0000196FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
197 : file_(file),
198 java_package_(FileJavaPackage(file, immutable_api)),
199 message_generators_(
Feng Xiaof157a562014-11-14 11:50:31 -0800200 new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000201 extension_generators_(
Feng Xiaof157a562014-11-14 11:50:31 -0800202 new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000203 context_(new Context(file)),
204 name_resolver_(context_->GetNameResolver()),
205 immutable_api_(immutable_api) {
206 classname_ = name_resolver_->GetFileClassName(file, immutable_api);
207 generator_factory_.reset(
208 new ImmutableGeneratorFactory(context_.get()));
209 for (int i = 0; i < file_->message_type_count(); ++i) {
210 message_generators_[i].reset(
211 generator_factory_->NewMessageGenerator(file_->message_type(i)));
212 }
213 for (int i = 0; i < file_->extension_count(); ++i) {
214 extension_generators_[i].reset(
215 generator_factory_->NewExtensionGenerator(file_->extension(i)));
216 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000217}
temporal40ee5512008-07-10 02:12:20 +0000218
219FileGenerator::~FileGenerator() {}
220
221bool FileGenerator::Validate(string* error) {
222 // Check that no class name matches the file's class name. This is a common
223 // problem that leads to Java compile errors that can be hard to understand.
224 // It's especially bad when using the java_multiple_files, since we would
225 // end up overwriting the outer class with one of the inner ones.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000226 if (name_resolver_->HasConflictingClassName(file_, classname_)) {
temporal40ee5512008-07-10 02:12:20 +0000227 error->assign(file_->name());
228 error->append(
229 ": Cannot generate Java output because the file's outer class name, \"");
230 error->append(classname_);
231 error->append(
232 "\", matches the name of one of the types declared inside it. "
233 "Please either rename the type or use the java_outer_classname "
234 "option to specify a different outer class name for the .proto file.");
235 return false;
236 }
temporal40ee5512008-07-10 02:12:20 +0000237 return true;
238}
239
240void FileGenerator::Generate(io::Printer* printer) {
241 // We don't import anything because we refer to all classes by their
242 // fully-qualified names in the generated source.
243 printer->Print(
244 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
kenton@google.comfccb1462009-12-18 02:11:36 +0000245 "// source: $filename$\n"
246 "\n",
247 "filename", file_->name());
temporal40ee5512008-07-10 02:12:20 +0000248 if (!java_package_.empty()) {
249 printer->Print(
250 "package $package$;\n"
251 "\n",
252 "package", java_package_);
253 }
254 printer->Print(
255 "public final class $classname$ {\n"
256 " private $classname$() {}\n",
257 "classname", classname_);
258 printer->Indent();
259
260 // -----------------------------------------------------------------
261
temporal40ee5512008-07-10 02:12:20 +0000262 printer->Print(
kenton@google.com24bf56f2008-09-24 20:31:01 +0000263 "public static void registerAllExtensions(\n"
kenton@google.com80b1d622009-07-29 01:13:20 +0000264 " com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
265 "lite", HasDescriptorMethods(file_) ? "" : "Lite");
266
temporal40ee5512008-07-10 02:12:20 +0000267 printer->Indent();
268
kenton@google.com24bf56f2008-09-24 20:31:01 +0000269 for (int i = 0; i < file_->extension_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000270 extension_generators_[i]->GenerateRegistrationCode(printer);
temporal40ee5512008-07-10 02:12:20 +0000271 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000272
273 for (int i = 0; i < file_->message_type_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000274 message_generators_[i]->GenerateExtensionRegistrationCode(printer);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000275 }
temporal40ee5512008-07-10 02:12:20 +0000276
277 printer->Outdent();
278 printer->Print(
kenton@google.com24bf56f2008-09-24 20:31:01 +0000279 "}\n");
temporal40ee5512008-07-10 02:12:20 +0000280
281 // -----------------------------------------------------------------
282
jieluo@google.com4de8f552014-07-18 00:47:59 +0000283 if (!MultipleJavaFiles(file_, immutable_api_)) {
temporal40ee5512008-07-10 02:12:20 +0000284 for (int i = 0; i < file_->enum_type_count(); i++) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800285 if (HasDescriptorMethods(file_)) {
286 EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
287 .Generate(printer);
288 } else {
289 EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get())
290 .Generate(printer);
291 }
temporal40ee5512008-07-10 02:12:20 +0000292 }
293 for (int i = 0; i < file_->message_type_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000294 message_generators_[i]->GenerateInterface(printer);
295 message_generators_[i]->Generate(printer);
temporal40ee5512008-07-10 02:12:20 +0000296 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000297 if (HasGenericServices(file_)) {
298 for (int i = 0; i < file_->service_count(); i++) {
Feng Xiaof157a562014-11-14 11:50:31 -0800299 google::protobuf::scoped_ptr<ServiceGenerator> generator(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000300 generator_factory_->NewServiceGenerator(file_->service(i)));
301 generator->Generate(printer);
kenton@google.comfccb1462009-12-18 02:11:36 +0000302 }
temporal40ee5512008-07-10 02:12:20 +0000303 }
304 }
305
306 // Extensions must be generated in the outer class since they are values,
307 // not classes.
308 for (int i = 0; i < file_->extension_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000309 extension_generators_[i]->Generate(printer);
temporal40ee5512008-07-10 02:12:20 +0000310 }
311
312 // Static variables.
313 for (int i = 0; i < file_->message_type_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000314 message_generators_[i]->GenerateStaticVariables(printer);
temporal40ee5512008-07-10 02:12:20 +0000315 }
316
kenton@google.com24bf56f2008-09-24 20:31:01 +0000317 printer->Print("\n");
318
kenton@google.com80b1d622009-07-29 01:13:20 +0000319 if (HasDescriptorMethods(file_)) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000320 if (immutable_api_) {
321 GenerateDescriptorInitializationCodeForImmutable(printer);
322 } else {
323 GenerateDescriptorInitializationCodeForMutable(printer);
324 }
kenton@google.com80b1d622009-07-29 01:13:20 +0000325 } else {
326 printer->Print(
327 "static {\n");
328 printer->Indent();
Daniel Martine2416ca2014-11-25 10:37:57 -0500329 int bytecode_estimate = 0;
330 int method_num = 0;
kenton@google.com24bf56f2008-09-24 20:31:01 +0000331
kenton@google.com80b1d622009-07-29 01:13:20 +0000332 for (int i = 0; i < file_->message_type_count(); i++) {
Daniel Martine2416ca2014-11-25 10:37:57 -0500333 bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
334 MaybeRestartJavaMethod(
335 printer,
336 &bytecode_estimate, &method_num,
337 "_clinit_autosplit_$method_num$();\n",
338 "private static void _clinit_autosplit_$method_num$() {\n");
kenton@google.com80b1d622009-07-29 01:13:20 +0000339 }
340
kenton@google.com80b1d622009-07-29 01:13:20 +0000341 printer->Outdent();
342 printer->Print(
343 "}\n");
344 }
345
kenton@google.comfccb1462009-12-18 02:11:36 +0000346 printer->Print(
347 "\n"
348 "// @@protoc_insertion_point(outer_class_scope)\n");
349
kenton@google.com80b1d622009-07-29 01:13:20 +0000350 printer->Outdent();
351 printer->Print("}\n");
352}
353
jieluo@google.com4de8f552014-07-18 00:47:59 +0000354void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
355 io::Printer* printer) {
kenton@google.com24bf56f2008-09-24 20:31:01 +0000356 printer->Print(
357 "public static com.google.protobuf.Descriptors.FileDescriptor\n"
358 " getDescriptor() {\n"
359 " return descriptor;\n"
360 "}\n"
jieluo@google.comd7339312014-08-07 22:22:00 +0000361 "private static com.google.protobuf.Descriptors.FileDescriptor\n"
kenton@google.com24bf56f2008-09-24 20:31:01 +0000362 " descriptor;\n"
jieluo@google.com4de8f552014-07-18 00:47:59 +0000363 "static {\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +0000364 printer->Indent();
kenton@google.com24bf56f2008-09-24 20:31:01 +0000365
jieluo@google.com7db9c092014-08-07 19:03:12 +0000366 SharedCodeGenerator shared_code_generator(file_);
367 shared_code_generator.GenerateDescriptors(printer);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000368
Daniel Martine2416ca2014-11-25 10:37:57 -0500369 int bytecode_estimate = 0;
370 int method_num = 0;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800371
kenton@google.com24bf56f2008-09-24 20:31:01 +0000372 for (int i = 0; i < file_->message_type_count(); i++) {
Daniel Martine2416ca2014-11-25 10:37:57 -0500373 bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
374 MaybeRestartJavaMethod(
375 printer,
376 &bytecode_estimate, &method_num,
377 "_clinit_autosplit_dinit_$method_num$();\n",
378 "private static void _clinit_autosplit_dinit_$method_num$() {\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +0000379 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000380 for (int i = 0; i < file_->extension_count(); i++) {
Daniel Martine2416ca2014-11-25 10:37:57 -0500381 bytecode_estimate += extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
382 MaybeRestartJavaMethod(
383 printer,
384 &bytecode_estimate, &method_num,
385 "_clinit_autosplit_dinit_$method_num$();\n",
386 "private static void _clinit_autosplit_dinit_$method_num$() {\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +0000387 }
388
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000389 // Proto compiler builds a DescriptorPool, which holds all the descriptors to
390 // generate, when processing the ".proto" files. We call this DescriptorPool
391 // the parsed pool (a.k.a. file_->pool()).
392 //
393 // Note that when users try to extend the (.*)DescriptorProto in their
394 // ".proto" files, it does not affect the pre-built FileDescriptorProto class
395 // in proto compiler. When we put the descriptor data in the file_proto, those
396 // extensions become unknown fields.
397 //
398 // Now we need to find out all the extension value to the (.*)DescriptorProto
399 // in the file_proto message, and prepare an ExtensionRegistry to return.
400 //
401 // To find those extensions, we need to parse the data into a dynamic message
402 // of the FileDescriptor based on the builder-pool, then we can use
403 // reflections to find all extension fields
jieluo@google.com4de8f552014-07-18 00:47:59 +0000404 FileDescriptorProto file_proto;
405 file_->CopyTo(&file_proto);
406 string file_data;
407 file_proto.SerializeToString(&file_data);
Daniel Martine2416ca2014-11-25 10:37:57 -0500408 FieldDescriptorSet extensions;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000409 CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
410
411 if (extensions.size() > 0) {
412 // Must construct an ExtensionRegistry containing all existing extensions
jieluo@google.com4de8f552014-07-18 00:47:59 +0000413 // and use it to parse the descriptor data again to recognize extensions.
kenton@google.com24bf56f2008-09-24 20:31:01 +0000414 printer->Print(
415 "com.google.protobuf.ExtensionRegistry registry =\n"
jieluo@google.com4de8f552014-07-18 00:47:59 +0000416 " com.google.protobuf.ExtensionRegistry.newInstance();\n");
Daniel Martine2416ca2014-11-25 10:37:57 -0500417 FieldDescriptorSet::iterator it;
418 for (it = extensions.begin(); it != extensions.end(); it++) {
Feng Xiaof157a562014-11-14 11:50:31 -0800419 google::protobuf::scoped_ptr<ExtensionGenerator> generator(
Daniel Martine2416ca2014-11-25 10:37:57 -0500420 generator_factory_->NewExtensionGenerator(*it));
421 bytecode_estimate += generator->GenerateRegistrationCode(printer);
422 MaybeRestartJavaMethod(
423 printer,
424 &bytecode_estimate, &method_num,
425 "_clinit_autosplit_dinit_$method_num$(registry);\n",
426 "private static void _clinit_autosplit_dinit_$method_num$(\n"
427 " com.google.protobuf.ExtensionRegistry registry) {\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +0000428 }
429 printer->Print(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000430 "com.google.protobuf.Descriptors.FileDescriptor\n"
431 " .internalUpdateFileDescriptor(descriptor, registry);\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +0000432 }
433
jieluo@google.com4de8f552014-07-18 00:47:59 +0000434 // Force descriptor initialization of all dependencies.
kenton@google.com24bf56f2008-09-24 20:31:01 +0000435 for (int i = 0; i < file_->dependency_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000436 if (ShouldIncludeDependency(file_->dependency(i), true)) {
437 string dependency =
438 name_resolver_->GetImmutableClassName(file_->dependency(i));
kenton@google.comfccb1462009-12-18 02:11:36 +0000439 printer->Print(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000440 "$dependency$.getDescriptor();\n",
441 "dependency", dependency);
kenton@google.comfccb1462009-12-18 02:11:36 +0000442 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000443 }
444
jieluo@google.com4de8f552014-07-18 00:47:59 +0000445 printer->Outdent();
kenton@google.com24bf56f2008-09-24 20:31:01 +0000446 printer->Print(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000447 "}\n");
448}
449
450void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* printer) {
451 printer->Print(
452 "public static com.google.protobuf.Descriptors.FileDescriptor\n"
453 " getDescriptor() {\n"
454 " return descriptor;\n"
455 "}\n"
456 "private static com.google.protobuf.Descriptors.FileDescriptor\n"
457 " descriptor;\n"
458 "static {\n");
459 printer->Indent();
460
461 printer->Print(
462 "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n",
463 "immutable_package", FileJavaPackage(file_, true),
464 "descriptor_classname", name_resolver_->GetDescriptorClassName(file_));
465
466 for (int i = 0; i < file_->message_type_count(); i++) {
467 message_generators_[i]->GenerateStaticVariableInitializers(printer);
468 }
469 for (int i = 0; i < file_->extension_count(); i++) {
470 extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
471 }
472
473 // Check if custom options exist. If any, try to load immutable classes since
474 // custom options are only represented with immutable messages.
475 FileDescriptorProto file_proto;
476 file_->CopyTo(&file_proto);
477 string file_data;
478 file_proto.SerializeToString(&file_data);
Daniel Martine2416ca2014-11-25 10:37:57 -0500479 FieldDescriptorSet extensions;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000480 CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
481
482 if (extensions.size() > 0) {
483 // Try to load immutable messages' outer class. Its initialization code
484 // will take care of interpreting custom options.
485 printer->Print(
486 "try {\n"
487 // Note that we have to load the immutable class dynamically here as
488 // we want the mutable code to be independent from the immutable code
489 // at compile time. It is required to implement dual-compile for
490 // mutable and immutable API in blaze.
491 " java.lang.Class immutableClass = java.lang.Class.forName(\n"
492 " \"$immutable_classname$\");\n"
493 "} catch (java.lang.ClassNotFoundException e) {\n"
494 // The immutable class can not be found. Custom options are left
495 // as unknown fields.
496 // TODO(xiaofeng): inform the user with a warning?
497 "}\n",
498 "immutable_classname", name_resolver_->GetImmutableClassName(file_));
499 }
500
501 // Force descriptor initialization of all dependencies.
502 for (int i = 0; i < file_->dependency_count(); i++) {
503 if (ShouldIncludeDependency(file_->dependency(i), false)) {
504 string dependency = name_resolver_->GetMutableClassName(
505 file_->dependency(i));
506 printer->Print(
507 "$dependency$.getDescriptor();\n",
508 "dependency", dependency);
509 }
510 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000511
512 printer->Outdent();
513 printer->Print(
514 "}\n");
temporal40ee5512008-07-10 02:12:20 +0000515}
516
517template<typename GeneratorClass, typename DescriptorClass>
518static void GenerateSibling(const string& package_dir,
519 const string& java_package,
520 const DescriptorClass* descriptor,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000521 GeneratorContext* context,
522 vector<string>* file_list,
523 const string& name_suffix,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000524 GeneratorClass* generator,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000525 void (GeneratorClass::*pfn)(io::Printer* printer)) {
526 string filename = package_dir + descriptor->name() + name_suffix + ".java";
temporal40ee5512008-07-10 02:12:20 +0000527 file_list->push_back(filename);
528
Feng Xiaof157a562014-11-14 11:50:31 -0800529 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
temporal40ee5512008-07-10 02:12:20 +0000530 io::Printer printer(output.get(), '$');
531
532 printer.Print(
533 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000534 "// source: $filename$\n"
535 "\n",
536 "filename", descriptor->file()->name());
temporal40ee5512008-07-10 02:12:20 +0000537 if (!java_package.empty()) {
538 printer.Print(
539 "package $package$;\n"
540 "\n",
541 "package", java_package);
542 }
543
jieluo@google.com4de8f552014-07-18 00:47:59 +0000544 (generator->*pfn)(&printer);
temporal40ee5512008-07-10 02:12:20 +0000545}
546
547void FileGenerator::GenerateSiblings(const string& package_dir,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000548 GeneratorContext* context,
temporal40ee5512008-07-10 02:12:20 +0000549 vector<string>* file_list) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000550 if (MultipleJavaFiles(file_, immutable_api_)) {
temporal40ee5512008-07-10 02:12:20 +0000551 for (int i = 0; i < file_->enum_type_count(); i++) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800552 if (HasDescriptorMethods(file_)) {
553 EnumGenerator generator(file_->enum_type(i), immutable_api_,
554 context_.get());
555 GenerateSibling<EnumGenerator>(package_dir, java_package_,
556 file_->enum_type(i),
557 context, file_list, "",
558 &generator,
559 &EnumGenerator::Generate);
560 } else {
561 EnumLiteGenerator generator(file_->enum_type(i), immutable_api_,
562 context_.get());
563 GenerateSibling<EnumLiteGenerator>(package_dir, java_package_,
564 file_->enum_type(i),
565 context, file_list, "",
566 &generator,
567 &EnumLiteGenerator::Generate);
568 }
temporal40ee5512008-07-10 02:12:20 +0000569 }
570 for (int i = 0; i < file_->message_type_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000571 if (immutable_api_) {
572 GenerateSibling<MessageGenerator>(package_dir, java_package_,
573 file_->message_type(i),
574 context, file_list,
575 "OrBuilder",
576 message_generators_[i].get(),
577 &MessageGenerator::GenerateInterface);
578 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000579 GenerateSibling<MessageGenerator>(package_dir, java_package_,
580 file_->message_type(i),
581 context, file_list, "",
jieluo@google.com4de8f552014-07-18 00:47:59 +0000582 message_generators_[i].get(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000583 &MessageGenerator::Generate);
temporal40ee5512008-07-10 02:12:20 +0000584 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000585 if (HasGenericServices(file_)) {
586 for (int i = 0; i < file_->service_count(); i++) {
Feng Xiaof157a562014-11-14 11:50:31 -0800587 google::protobuf::scoped_ptr<ServiceGenerator> generator(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000588 generator_factory_->NewServiceGenerator(file_->service(i)));
kenton@google.comfccb1462009-12-18 02:11:36 +0000589 GenerateSibling<ServiceGenerator>(package_dir, java_package_,
590 file_->service(i),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000591 context, file_list, "",
jieluo@google.com4de8f552014-07-18 00:47:59 +0000592 generator.get(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000593 &ServiceGenerator::Generate);
kenton@google.comfccb1462009-12-18 02:11:36 +0000594 }
temporal40ee5512008-07-10 02:12:20 +0000595 }
596 }
597}
598
jieluo@google.com4de8f552014-07-18 00:47:59 +0000599bool FileGenerator::ShouldIncludeDependency(
600 const FileDescriptor* descriptor, bool immutable_api) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000601 return true;
602}
603
temporal40ee5512008-07-10 02:12:20 +0000604} // namespace java
605} // namespace compiler
606} // namespace protobuf
607} // namespace google