1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * 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.
18 //
19 // 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.
30
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>
36 #include <google/protobuf/compiler/java/java_enum.h>
37 #include <google/protobuf/compiler/java/java_service.h>
38 #include <google/protobuf/compiler/java/java_extension.h>
39 #include <google/protobuf/compiler/java/java_helpers.h>
40 #include <google/protobuf/compiler/java/java_message.h>
41 #include <google/protobuf/compiler/code_generator.h>
42 #include <google/protobuf/io/printer.h>
43 #include <google/protobuf/io/zero_copy_stream.h>
44 #include <google/protobuf/descriptor.pb.h>
45 #include <google/protobuf/stubs/strutil.h>
46
47 namespace google {
48 namespace protobuf {
49 namespace compiler {
50 namespace java {
51
52 namespace {
53
54 // Recursively searches the given message to see if it contains any extensions.
UsesExtensions(const Message & message)55 bool UsesExtensions(const Message& message) {
56 const Reflection* reflection = message.GetReflection();
57
58 // We conservatively assume that unknown fields are extensions.
59 if (reflection->GetUnknownFields(message).field_count() > 0) return true;
60
61 vector<const FieldDescriptor*> fields;
62 reflection->ListFields(message, &fields);
63
64 for (int i = 0; i < fields.size(); i++) {
65 if (fields[i]->is_extension()) return true;
66
67 if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
68 if (fields[i]->is_repeated()) {
69 int size = reflection->FieldSize(message, fields[i]);
70 for (int j = 0; j < size; j++) {
71 const Message& sub_message =
72 reflection->GetRepeatedMessage(message, fields[i], j);
73 if (UsesExtensions(sub_message)) return true;
74 }
75 } else {
76 const Message& sub_message = reflection->GetMessage(message, fields[i]);
77 if (UsesExtensions(sub_message)) return true;
78 }
79 }
80 }
81
82 return false;
83 }
84
85
86 } // namespace
87
FileGenerator(const FileDescriptor * file)88 FileGenerator::FileGenerator(const FileDescriptor* file)
89 : file_(file),
90 java_package_(FileJavaPackage(file)),
91 classname_(FileClassName(file)) {}
92
~FileGenerator()93 FileGenerator::~FileGenerator() {}
94
Validate(string * error)95 bool FileGenerator::Validate(string* error) {
96 // Check that no class name matches the file's class name. This is a common
97 // problem that leads to Java compile errors that can be hard to understand.
98 // It's especially bad when using the java_multiple_files, since we would
99 // end up overwriting the outer class with one of the inner ones.
100
101 bool found_conflict = false;
102 for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) {
103 if (file_->enum_type(i)->name() == classname_) {
104 found_conflict = true;
105 }
106 }
107 for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) {
108 if (file_->message_type(i)->name() == classname_) {
109 found_conflict = true;
110 }
111 }
112 for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
113 if (file_->service(i)->name() == classname_) {
114 found_conflict = true;
115 }
116 }
117
118 if (found_conflict) {
119 error->assign(file_->name());
120 error->append(
121 ": Cannot generate Java output because the file's outer class name, \"");
122 error->append(classname_);
123 error->append(
124 "\", matches the name of one of the types declared inside it. "
125 "Please either rename the type or use the java_outer_classname "
126 "option to specify a different outer class name for the .proto file.");
127 return false;
128 }
129
130 return true;
131 }
132
Generate(io::Printer * printer)133 void FileGenerator::Generate(io::Printer* printer) {
134 // We don't import anything because we refer to all classes by their
135 // fully-qualified names in the generated source.
136 printer->Print(
137 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
138 "// source: $filename$\n"
139 "\n",
140 "filename", file_->name());
141 if (!java_package_.empty()) {
142 printer->Print(
143 "package $package$;\n"
144 "\n",
145 "package", java_package_);
146 }
147 printer->Print(
148 "public final class $classname$ {\n"
149 " private $classname$() {}\n",
150 "classname", classname_);
151 printer->Indent();
152
153 // -----------------------------------------------------------------
154
155 printer->Print(
156 "public static void registerAllExtensions(\n"
157 " com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
158 "lite", HasDescriptorMethods(file_) ? "" : "Lite");
159
160 printer->Indent();
161
162 for (int i = 0; i < file_->extension_count(); i++) {
163 ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer);
164 }
165
166 for (int i = 0; i < file_->message_type_count(); i++) {
167 MessageGenerator(file_->message_type(i))
168 .GenerateExtensionRegistrationCode(printer);
169 }
170
171 printer->Outdent();
172 printer->Print(
173 "}\n");
174
175 // -----------------------------------------------------------------
176
177 if (!file_->options().java_multiple_files()) {
178 for (int i = 0; i < file_->enum_type_count(); i++) {
179 EnumGenerator(file_->enum_type(i)).Generate(printer);
180 }
181 for (int i = 0; i < file_->message_type_count(); i++) {
182 MessageGenerator(file_->message_type(i)).Generate(printer);
183 }
184 if (HasGenericServices(file_)) {
185 for (int i = 0; i < file_->service_count(); i++) {
186 ServiceGenerator(file_->service(i)).Generate(printer);
187 }
188 }
189 }
190
191 // Extensions must be generated in the outer class since they are values,
192 // not classes.
193 for (int i = 0; i < file_->extension_count(); i++) {
194 ExtensionGenerator(file_->extension(i)).Generate(printer);
195 }
196
197 // Static variables.
198 for (int i = 0; i < file_->message_type_count(); i++) {
199 // TODO(kenton): Reuse MessageGenerator objects?
200 MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer);
201 }
202
203 printer->Print("\n");
204
205 if (HasDescriptorMethods(file_)) {
206 GenerateEmbeddedDescriptor(printer);
207 } else {
208 printer->Print(
209 "static {\n");
210 printer->Indent();
211
212 for (int i = 0; i < file_->message_type_count(); i++) {
213 // TODO(kenton): Reuse MessageGenerator objects?
214 MessageGenerator(file_->message_type(i))
215 .GenerateStaticVariableInitializers(printer);
216 }
217
218 for (int i = 0; i < file_->extension_count(); i++) {
219 // TODO(kenton): Reuse ExtensionGenerator objects?
220 ExtensionGenerator(file_->extension(i))
221 .GenerateInitializationCode(printer);
222 }
223
224 printer->Outdent();
225 printer->Print(
226 "}\n");
227 }
228
229 // Dummy function we can use to force the static initialization block to
230 // run. Needed by inner classes. Cannot be private due to
231 // java_multiple_files option.
232 printer->Print(
233 "\n"
234 "public static void internalForceInit() {}\n");
235
236 printer->Print(
237 "\n"
238 "// @@protoc_insertion_point(outer_class_scope)\n");
239
240 printer->Outdent();
241 printer->Print("}\n");
242 }
243
GenerateEmbeddedDescriptor(io::Printer * printer)244 void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
245 // Embed the descriptor. We simply serialize the entire FileDescriptorProto
246 // and embed it as a string literal, which is parsed and built into real
247 // descriptors at initialization time. We unfortunately have to put it in
248 // a string literal, not a byte array, because apparently using a literal
249 // byte array causes the Java compiler to generate *instructions* to
250 // initialize each and every byte of the array, e.g. as if you typed:
251 // b[0] = 123; b[1] = 456; b[2] = 789;
252 // This makes huge bytecode files and can easily hit the compiler's internal
253 // code size limits (error "code to large"). String literals are apparently
254 // embedded raw, which is what we want.
255 FileDescriptorProto file_proto;
256 file_->CopyTo(&file_proto);
257
258 string file_data;
259 file_proto.SerializeToString(&file_data);
260
261 printer->Print(
262 "public static com.google.protobuf.Descriptors.FileDescriptor\n"
263 " getDescriptor() {\n"
264 " return descriptor;\n"
265 "}\n"
266 "private static com.google.protobuf.Descriptors.FileDescriptor\n"
267 " descriptor;\n"
268 "static {\n"
269 " java.lang.String[] descriptorData = {\n");
270 printer->Indent();
271 printer->Indent();
272
273 // Only write 40 bytes per line.
274 static const int kBytesPerLine = 40;
275 for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
276 if (i > 0) {
277 // Every 400 lines, start a new string literal, in order to avoid the
278 // 64k length limit.
279 if (i % 400 == 0) {
280 printer->Print(",\n");
281 } else {
282 printer->Print(" +\n");
283 }
284 }
285 printer->Print("\"$data$\"",
286 "data", CEscape(file_data.substr(i, kBytesPerLine)));
287 }
288
289 printer->Outdent();
290 printer->Print("\n};\n");
291
292 // -----------------------------------------------------------------
293 // Create the InternalDescriptorAssigner.
294
295 printer->Print(
296 "com.google.protobuf.Descriptors.FileDescriptor."
297 "InternalDescriptorAssigner assigner =\n"
298 " new com.google.protobuf.Descriptors.FileDescriptor."
299 "InternalDescriptorAssigner() {\n"
300 " public com.google.protobuf.ExtensionRegistry assignDescriptors(\n"
301 " com.google.protobuf.Descriptors.FileDescriptor root) {\n"
302 " descriptor = root;\n");
303
304 printer->Indent();
305 printer->Indent();
306 printer->Indent();
307
308 for (int i = 0; i < file_->message_type_count(); i++) {
309 // TODO(kenton): Reuse MessageGenerator objects?
310 MessageGenerator(file_->message_type(i))
311 .GenerateStaticVariableInitializers(printer);
312 }
313
314 for (int i = 0; i < file_->extension_count(); i++) {
315 // TODO(kenton): Reuse ExtensionGenerator objects?
316 ExtensionGenerator(file_->extension(i))
317 .GenerateInitializationCode(printer);
318 }
319
320 if (UsesExtensions(file_proto)) {
321 // Must construct an ExtensionRegistry containing all possible extensions
322 // and return it.
323 printer->Print(
324 "com.google.protobuf.ExtensionRegistry registry =\n"
325 " com.google.protobuf.ExtensionRegistry.newInstance();\n"
326 "registerAllExtensions(registry);\n");
327 for (int i = 0; i < file_->dependency_count(); i++) {
328 printer->Print(
329 "$dependency$.registerAllExtensions(registry);\n",
330 "dependency", ClassName(file_->dependency(i)));
331 }
332 printer->Print(
333 "return registry;\n");
334 } else {
335 printer->Print(
336 "return null;\n");
337 }
338
339 printer->Outdent();
340 printer->Outdent();
341 printer->Outdent();
342
343 printer->Print(
344 " }\n"
345 " };\n");
346
347 // -----------------------------------------------------------------
348 // Invoke internalBuildGeneratedFileFrom() to build the file.
349
350 printer->Print(
351 "com.google.protobuf.Descriptors.FileDescriptor\n"
352 " .internalBuildGeneratedFileFrom(descriptorData,\n"
353 " new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
354
355 for (int i = 0; i < file_->dependency_count(); i++) {
356 if (ShouldIncludeDependency(file_->dependency(i))) {
357 printer->Print(
358 " $dependency$.getDescriptor(),\n",
359 "dependency", ClassName(file_->dependency(i)));
360 }
361 }
362
363 printer->Print(
364 " }, assigner);\n");
365
366 printer->Outdent();
367 printer->Print(
368 "}\n");
369 }
370
371 template<typename GeneratorClass, typename DescriptorClass>
GenerateSibling(const string & package_dir,const string & java_package,const DescriptorClass * descriptor,OutputDirectory * output_directory,vector<string> * file_list)372 static void GenerateSibling(const string& package_dir,
373 const string& java_package,
374 const DescriptorClass* descriptor,
375 OutputDirectory* output_directory,
376 vector<string>* file_list) {
377 string filename = package_dir + descriptor->name() + ".java";
378 file_list->push_back(filename);
379
380 scoped_ptr<io::ZeroCopyOutputStream> output(
381 output_directory->Open(filename));
382 io::Printer printer(output.get(), '$');
383
384 printer.Print(
385 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
386 "\n");
387 if (!java_package.empty()) {
388 printer.Print(
389 "package $package$;\n"
390 "\n",
391 "package", java_package);
392 }
393
394 GeneratorClass(descriptor).Generate(&printer);
395 }
396
GenerateSiblings(const string & package_dir,OutputDirectory * output_directory,vector<string> * file_list)397 void FileGenerator::GenerateSiblings(const string& package_dir,
398 OutputDirectory* output_directory,
399 vector<string>* file_list) {
400 if (file_->options().java_multiple_files()) {
401 for (int i = 0; i < file_->enum_type_count(); i++) {
402 GenerateSibling<EnumGenerator>(package_dir, java_package_,
403 file_->enum_type(i),
404 output_directory, file_list);
405 }
406 for (int i = 0; i < file_->message_type_count(); i++) {
407 GenerateSibling<MessageGenerator>(package_dir, java_package_,
408 file_->message_type(i),
409 output_directory, file_list);
410 }
411 if (HasGenericServices(file_)) {
412 for (int i = 0; i < file_->service_count(); i++) {
413 GenerateSibling<ServiceGenerator>(package_dir, java_package_,
414 file_->service(i),
415 output_directory, file_list);
416 }
417 }
418 }
419 }
420
ShouldIncludeDependency(const FileDescriptor * descriptor)421 bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) {
422 return true;
423 }
424
425 } // namespace java
426 } // namespace compiler
427 } // namespace protobuf
428 } // namespace google
429