1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc. All rights reserved.
3
// http://code.google.com/p/protobuf/
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
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
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.
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.
31
// Author: kenton@google.com (Kenton Varda)
32
// Based on original Protocol Buffers design by
33
// Sanjay Ghemawat, Jeff Dean, and others.
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>
54
// Recursively searches the given message to see if it contains any extensions.
55
bool UsesExtensions(const Message& message) {
56
const Reflection* reflection = message.GetReflection();
58
// We conservatively assume that unknown fields are extensions.
59
if (reflection->GetUnknownFields(message).field_count() > 0) return true;
61
vector<const FieldDescriptor*> fields;
62
reflection->ListFields(message, &fields);
64
for (int i = 0; i < fields.size(); i++) {
65
if (fields[i]->is_extension()) return true;
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;
76
const Message& sub_message = reflection->GetMessage(message, fields[i]);
77
if (UsesExtensions(sub_message)) return true;
88
FileGenerator::FileGenerator(const FileDescriptor* file)
90
java_package_(FileJavaPackage(file)),
91
classname_(FileClassName(file)) {}
93
FileGenerator::~FileGenerator() {}
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.
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;
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;
112
for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
113
if (file_->service(i)->name() == classname_) {
114
found_conflict = true;
118
if (found_conflict) {
119
error->assign(file_->name());
121
": Cannot generate Java output because the file's outer class name, \"");
122
error->append(classname_);
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.");
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.
137
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
138
"// source: $filename$\n"
140
"filename", file_->name());
141
if (!java_package_.empty()) {
143
"package $package$;\n"
145
"package", java_package_);
148
"public final class $classname$ {\n"
149
" private $classname$() {}\n",
150
"classname", classname_);
153
// -----------------------------------------------------------------
156
"public static void registerAllExtensions(\n"
157
" com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
158
"lite", HasDescriptorMethods(file_) ? "" : "Lite");
162
for (int i = 0; i < file_->extension_count(); i++) {
163
ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer);
166
for (int i = 0; i < file_->message_type_count(); i++) {
167
MessageGenerator(file_->message_type(i))
168
.GenerateExtensionRegistrationCode(printer);
175
// -----------------------------------------------------------------
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);
181
for (int i = 0; i < file_->message_type_count(); i++) {
182
MessageGenerator(file_->message_type(i)).Generate(printer);
184
if (HasGenericServices(file_)) {
185
for (int i = 0; i < file_->service_count(); i++) {
186
ServiceGenerator(file_->service(i)).Generate(printer);
191
// Extensions must be generated in the outer class since they are values,
193
for (int i = 0; i < file_->extension_count(); i++) {
194
ExtensionGenerator(file_->extension(i)).Generate(printer);
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);
203
printer->Print("\n");
205
if (HasDescriptorMethods(file_)) {
206
GenerateEmbeddedDescriptor(printer);
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);
218
for (int i = 0; i < file_->extension_count(); i++) {
219
// TODO(kenton): Reuse ExtensionGenerator objects?
220
ExtensionGenerator(file_->extension(i))
221
.GenerateInitializationCode(printer);
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.
234
"public static void internalForceInit() {}\n");
238
"// @@protoc_insertion_point(outer_class_scope)\n");
241
printer->Print("}\n");
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);
259
file_proto.SerializeToString(&file_data);
262
"public static com.google.protobuf.Descriptors.FileDescriptor\n"
263
" getDescriptor() {\n"
264
" return descriptor;\n"
266
"private static com.google.protobuf.Descriptors.FileDescriptor\n"
269
" java.lang.String[] descriptorData = {\n");
273
// Only write 40 bytes per line.
274
static const int kBytesPerLine = 40;
275
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
277
// Every 400 lines, start a new string literal, in order to avoid the
280
printer->Print(",\n");
282
printer->Print(" +\n");
285
printer->Print("\"$data$\"",
286
"data", CEscape(file_data.substr(i, kBytesPerLine)));
290
printer->Print("\n};\n");
292
// -----------------------------------------------------------------
293
// Create the InternalDescriptorAssigner.
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");
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);
314
for (int i = 0; i < file_->extension_count(); i++) {
315
// TODO(kenton): Reuse ExtensionGenerator objects?
316
ExtensionGenerator(file_->extension(i))
317
.GenerateInitializationCode(printer);
320
if (UsesExtensions(file_proto)) {
321
// Must construct an ExtensionRegistry containing all possible extensions
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++) {
329
"$dependency$.registerAllExtensions(registry);\n",
330
"dependency", ClassName(file_->dependency(i)));
333
"return registry;\n");
347
// -----------------------------------------------------------------
348
// Invoke internalBuildGeneratedFileFrom() to build the file.
351
"com.google.protobuf.Descriptors.FileDescriptor\n"
352
" .internalBuildGeneratedFileFrom(descriptorData,\n"
353
" new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
355
for (int i = 0; i < file_->dependency_count(); i++) {
356
if (ShouldIncludeDependency(file_->dependency(i))) {
358
" $dependency$.getDescriptor(),\n",
359
"dependency", ClassName(file_->dependency(i)));
371
template<typename GeneratorClass, typename DescriptorClass>
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);
380
scoped_ptr<io::ZeroCopyOutputStream> output(
381
output_directory->Open(filename));
382
io::Printer printer(output.get(), '$');
385
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
387
if (!java_package.empty()) {
389
"package $package$;\n"
391
"package", java_package);
394
GeneratorClass(descriptor).Generate(&printer);
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_,
404
output_directory, file_list);
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);
411
if (HasGenericServices(file_)) {
412
for (int i = 0; i < file_->service_count(); i++) {
413
GenerateSibling<ServiceGenerator>(package_dir, java_package_,
415
output_directory, file_list);
421
bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) {
426
} // namespace compiler
427
} // namespace protobuf
428
} // namespace google