~ubuntu-branches/debian/stretch/protobuf/stretch

« back to all changes in this revision

Viewing changes to src/google/protobuf/compiler/java/java_file.cc

  • Committer: Package Import Robot
  • Author(s): Robert S. Edmonds
  • Date: 2014-09-11 22:50:10 UTC
  • mfrom: (10.1.9 experimental)
  • Revision ID: package-import@ubuntu.com-20140911225010-wt4yo9dpc1fzuq5g
Tags: 2.6.0-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
//  Sanjay Ghemawat, Jeff Dean, and others.
34
34
 
35
35
#include <google/protobuf/compiler/java/java_file.h>
 
36
 
 
37
#include <memory>
 
38
 
 
39
#include <google/protobuf/compiler/java/java_context.h>
36
40
#include <google/protobuf/compiler/java/java_enum.h>
37
 
#include <google/protobuf/compiler/java/java_service.h>
38
41
#include <google/protobuf/compiler/java/java_extension.h>
 
42
#include <google/protobuf/compiler/java/java_generator_factory.h>
39
43
#include <google/protobuf/compiler/java/java_helpers.h>
40
44
#include <google/protobuf/compiler/java/java_message.h>
 
45
#include <google/protobuf/compiler/java/java_name_resolver.h>
 
46
#include <google/protobuf/compiler/java/java_service.h>
 
47
#include <google/protobuf/compiler/java/java_shared_code_generator.h>
41
48
#include <google/protobuf/compiler/code_generator.h>
42
49
#include <google/protobuf/io/printer.h>
43
50
#include <google/protobuf/io/zero_copy_stream.h>
132
139
 
133
140
}  // namespace
134
141
 
135
 
FileGenerator::FileGenerator(const FileDescriptor* file)
136
 
  : file_(file),
137
 
    java_package_(FileJavaPackage(file)),
138
 
    classname_(FileClassName(file)) {
 
142
FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
 
143
    : file_(file),
 
144
      java_package_(FileJavaPackage(file, immutable_api)),
 
145
      message_generators_(
 
146
          new scoped_ptr<MessageGenerator>[file->message_type_count()]),
 
147
      extension_generators_(
 
148
          new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
 
149
      context_(new Context(file)),
 
150
      name_resolver_(context_->GetNameResolver()),
 
151
      immutable_api_(immutable_api) {
 
152
  classname_ = name_resolver_->GetFileClassName(file, immutable_api);
 
153
  generator_factory_.reset(
 
154
      new ImmutableGeneratorFactory(context_.get()));
 
155
  for (int i = 0; i < file_->message_type_count(); ++i) {
 
156
    message_generators_[i].reset(
 
157
        generator_factory_->NewMessageGenerator(file_->message_type(i)));
 
158
  }
 
159
  for (int i = 0; i < file_->extension_count(); ++i) {
 
160
    extension_generators_[i].reset(
 
161
        generator_factory_->NewExtensionGenerator(file_->extension(i)));
 
162
  }
139
163
}
140
164
 
141
165
FileGenerator::~FileGenerator() {}
145
169
  // problem that leads to Java compile errors that can be hard to understand.
146
170
  // It's especially bad when using the java_multiple_files, since we would
147
171
  // end up overwriting the outer class with one of the inner ones.
148
 
 
149
 
  bool found_conflict = false;
150
 
  for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) {
151
 
    if (file_->enum_type(i)->name() == classname_) {
152
 
      found_conflict = true;
153
 
    }
154
 
  }
155
 
  for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) {
156
 
    if (file_->message_type(i)->name() == classname_) {
157
 
      found_conflict = true;
158
 
    }
159
 
  }
160
 
  for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
161
 
    if (file_->service(i)->name() == classname_) {
162
 
      found_conflict = true;
163
 
    }
164
 
  }
165
 
 
166
 
  if (found_conflict) {
 
172
  if (name_resolver_->HasConflictingClassName(file_, classname_)) {
167
173
    error->assign(file_->name());
168
174
    error->append(
169
175
      ": Cannot generate Java output because the file's outer class name, \"");
174
180
      "option to specify a different outer class name for the .proto file.");
175
181
    return false;
176
182
  }
177
 
 
 
183
  // If java_outer_classname option is not set and the default outer class name
 
184
  // conflicts with a type defined in the message, we will append a suffix to
 
185
  // avoid the conflict. This allows proto1 API protos to be dual-compiled into
 
186
  // proto2 API without code change. When this happens we'd like to issue an
 
187
  // warning to let the user know that the outer class name has been changed.
 
188
  // Although we only do this automatic naming fix for immutable API, mutable
 
189
  // outer class name will also be affected as it's contructed from immutable
 
190
  // outer class name with an additional "Mutable" prefix. Since the naming
 
191
  // change in mutable API is not caused by a naming conflict, we generate the
 
192
  // warning for immutable API only.
 
193
  if (immutable_api_ && !file_->options().has_java_outer_classname()) {
 
194
    string default_classname =
 
195
        name_resolver_->GetFileDefaultImmutableClassName(file_);
 
196
    if (default_classname != classname_) {
 
197
      GOOGLE_LOG(WARNING) << file_->name() << ": The default outer class name, \""
 
198
                   << default_classname << "\", conflicts with a type "
 
199
                   << "declared in the proto file and an alternative outer "
 
200
                   << "class name is used: \"" << classname_ << "\". To avoid "
 
201
                   << "this warning, please use the java_outer_classname "
 
202
                   << "option to specify a different outer class name for "
 
203
                   << "the .proto file.";
 
204
    }
 
205
  }
178
206
  return true;
179
207
}
180
208
 
208
236
  printer->Indent();
209
237
 
210
238
  for (int i = 0; i < file_->extension_count(); i++) {
211
 
    ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer);
 
239
    extension_generators_[i]->GenerateRegistrationCode(printer);
212
240
  }
213
241
 
214
242
  for (int i = 0; i < file_->message_type_count(); i++) {
215
 
    MessageGenerator(file_->message_type(i))
216
 
      .GenerateExtensionRegistrationCode(printer);
 
243
    message_generators_[i]->GenerateExtensionRegistrationCode(printer);
217
244
  }
218
245
 
219
246
  printer->Outdent();
222
249
 
223
250
  // -----------------------------------------------------------------
224
251
 
225
 
  if (!file_->options().java_multiple_files()) {
 
252
  if (!MultipleJavaFiles(file_, immutable_api_)) {
226
253
    for (int i = 0; i < file_->enum_type_count(); i++) {
227
 
      EnumGenerator(file_->enum_type(i)).Generate(printer);
 
254
      EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
 
255
          .Generate(printer);
228
256
    }
229
257
    for (int i = 0; i < file_->message_type_count(); i++) {
230
 
      MessageGenerator messageGenerator(file_->message_type(i));
231
 
      messageGenerator.GenerateInterface(printer);
232
 
      messageGenerator.Generate(printer);
 
258
      message_generators_[i]->GenerateInterface(printer);
 
259
      message_generators_[i]->Generate(printer);
233
260
    }
234
261
    if (HasGenericServices(file_)) {
235
262
      for (int i = 0; i < file_->service_count(); i++) {
236
 
        ServiceGenerator(file_->service(i)).Generate(printer);
 
263
        scoped_ptr<ServiceGenerator> generator(
 
264
            generator_factory_->NewServiceGenerator(file_->service(i)));
 
265
        generator->Generate(printer);
237
266
      }
238
267
    }
239
268
  }
241
270
  // Extensions must be generated in the outer class since they are values,
242
271
  // not classes.
243
272
  for (int i = 0; i < file_->extension_count(); i++) {
244
 
    ExtensionGenerator(file_->extension(i)).Generate(printer);
 
273
    extension_generators_[i]->Generate(printer);
245
274
  }
246
275
 
247
276
  // Static variables.
248
277
  for (int i = 0; i < file_->message_type_count(); i++) {
249
 
    // TODO(kenton):  Reuse MessageGenerator objects?
250
 
    MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer);
 
278
    message_generators_[i]->GenerateStaticVariables(printer);
251
279
  }
252
280
 
253
281
  printer->Print("\n");
254
282
 
255
283
  if (HasDescriptorMethods(file_)) {
256
 
    GenerateEmbeddedDescriptor(printer);
 
284
    if (immutable_api_) {
 
285
      GenerateDescriptorInitializationCodeForImmutable(printer);
 
286
    } else {
 
287
      GenerateDescriptorInitializationCodeForMutable(printer);
 
288
    }
257
289
  } else {
258
290
    printer->Print(
259
291
      "static {\n");
260
292
    printer->Indent();
261
293
 
262
294
    for (int i = 0; i < file_->message_type_count(); i++) {
263
 
      // TODO(kenton):  Reuse MessageGenerator objects?
264
 
      MessageGenerator(file_->message_type(i))
265
 
        .GenerateStaticVariableInitializers(printer);
 
295
      message_generators_[i]->GenerateStaticVariableInitializers(printer);
266
296
    }
267
297
 
268
298
    printer->Outdent();
278
308
  printer->Print("}\n");
279
309
}
280
310
 
281
 
void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
282
 
  // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
283
 
  // and embed it as a string literal, which is parsed and built into real
284
 
  // descriptors at initialization time.  We unfortunately have to put it in
285
 
  // a string literal, not a byte array, because apparently using a literal
286
 
  // byte array causes the Java compiler to generate *instructions* to
287
 
  // initialize each and every byte of the array, e.g. as if you typed:
288
 
  //   b[0] = 123; b[1] = 456; b[2] = 789;
289
 
  // This makes huge bytecode files and can easily hit the compiler's internal
290
 
  // code size limits (error "code to large").  String literals are apparently
291
 
  // embedded raw, which is what we want.
292
 
  FileDescriptorProto file_proto;
293
 
  file_->CopyTo(&file_proto);
294
 
 
295
 
  string file_data;
296
 
  file_proto.SerializeToString(&file_data);
297
 
 
 
311
void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
 
312
    io::Printer* printer) {
298
313
  printer->Print(
299
314
    "public static com.google.protobuf.Descriptors.FileDescriptor\n"
300
315
    "    getDescriptor() {\n"
302
317
    "}\n"
303
318
    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
304
319
    "    descriptor;\n"
305
 
    "static {\n"
306
 
    "  java.lang.String[] descriptorData = {\n");
307
 
  printer->Indent();
308
 
  printer->Indent();
309
 
 
310
 
  // Only write 40 bytes per line.
311
 
  static const int kBytesPerLine = 40;
312
 
  for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
313
 
    if (i > 0) {
314
 
      // Every 400 lines, start a new string literal, in order to avoid the
315
 
      // 64k length limit.
316
 
      if (i % 400 == 0) {
317
 
        printer->Print(",\n");
318
 
      } else {
319
 
        printer->Print(" +\n");
320
 
      }
321
 
    }
322
 
    printer->Print("\"$data$\"",
323
 
      "data", CEscape(file_data.substr(i, kBytesPerLine)));
324
 
  }
325
 
 
326
 
  printer->Outdent();
327
 
  printer->Print("\n};\n");
328
 
 
329
 
  // -----------------------------------------------------------------
330
 
  // Create the InternalDescriptorAssigner.
331
 
 
332
 
  printer->Print(
333
 
    "com.google.protobuf.Descriptors.FileDescriptor."
334
 
      "InternalDescriptorAssigner assigner =\n"
335
 
    "  new com.google.protobuf.Descriptors.FileDescriptor."
336
 
      "InternalDescriptorAssigner() {\n"
337
 
    "    public com.google.protobuf.ExtensionRegistry assignDescriptors(\n"
338
 
    "        com.google.protobuf.Descriptors.FileDescriptor root) {\n"
339
 
    "      descriptor = root;\n");
340
 
 
341
 
  printer->Indent();
342
 
  printer->Indent();
343
 
  printer->Indent();
 
320
    "static {\n");
 
321
  printer->Indent();
 
322
 
 
323
  SharedCodeGenerator shared_code_generator(file_);
 
324
  shared_code_generator.GenerateDescriptors(printer);
344
325
 
345
326
  for (int i = 0; i < file_->message_type_count(); i++) {
346
 
    // TODO(kenton):  Reuse MessageGenerator objects?
347
 
    MessageGenerator(file_->message_type(i))
348
 
      .GenerateStaticVariableInitializers(printer);
 
327
    message_generators_[i]->GenerateStaticVariableInitializers(printer);
349
328
  }
350
329
  for (int i = 0; i < file_->extension_count(); i++) {
351
 
    // TODO(kenton):  Reuse ExtensionGenerator objects?
352
 
    ExtensionGenerator(file_->extension(i))
353
 
        .GenerateNonNestedInitializationCode(printer);
 
330
    extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
354
331
  }
355
332
 
356
333
  // Proto compiler builds a DescriptorPool, which holds all the descriptors to
368
345
  // To find those extensions, we need to parse the data into a dynamic message
369
346
  // of the FileDescriptor based on the builder-pool, then we can use
370
347
  // reflections to find all extension fields
 
348
  FileDescriptorProto file_proto;
 
349
  file_->CopyTo(&file_proto);
 
350
  string file_data;
 
351
  file_proto.SerializeToString(&file_data);
371
352
  vector<const FieldDescriptor*> extensions;
372
353
  CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
373
354
 
374
355
  if (extensions.size() > 0) {
375
356
    // Must construct an ExtensionRegistry containing all existing extensions
376
 
    // and return it.
 
357
    // and use it to parse the descriptor data again to recognize extensions.
377
358
    printer->Print(
378
359
      "com.google.protobuf.ExtensionRegistry registry =\n"
379
 
      "  com.google.protobuf.ExtensionRegistry.newInstance();\n");
 
360
      "    com.google.protobuf.ExtensionRegistry.newInstance();\n");
380
361
    for (int i = 0; i < extensions.size(); i++) {
381
 
      ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer);
382
 
    }
383
 
    printer->Print(
384
 
      "return registry;\n");
385
 
  } else {
386
 
    printer->Print(
387
 
      "return null;\n");
388
 
  }
389
 
 
390
 
  printer->Outdent();
391
 
  printer->Outdent();
392
 
  printer->Outdent();
393
 
 
394
 
  printer->Print(
395
 
    "    }\n"
396
 
    "  };\n");
397
 
 
398
 
  // -----------------------------------------------------------------
399
 
  // Invoke internalBuildGeneratedFileFrom() to build the file.
400
 
 
401
 
  printer->Print(
402
 
    "com.google.protobuf.Descriptors.FileDescriptor\n"
403
 
    "  .internalBuildGeneratedFileFrom(descriptorData,\n"
404
 
    "    new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
405
 
 
406
 
  for (int i = 0; i < file_->dependency_count(); i++) {
407
 
    if (ShouldIncludeDependency(file_->dependency(i))) {
408
 
      printer->Print(
409
 
        "      $dependency$.getDescriptor(),\n",
410
 
        "dependency", ClassName(file_->dependency(i)));
411
 
    }
412
 
  }
413
 
 
414
 
  printer->Print(
415
 
    "    }, assigner);\n");
 
362
      scoped_ptr<ExtensionGenerator> generator(
 
363
          generator_factory_->NewExtensionGenerator(extensions[i]));
 
364
      generator->GenerateRegistrationCode(printer);
 
365
    }
 
366
    printer->Print(
 
367
      "com.google.protobuf.Descriptors.FileDescriptor\n"
 
368
      "    .internalUpdateFileDescriptor(descriptor, registry);\n");
 
369
  }
 
370
 
 
371
  // Force descriptor initialization of all dependencies.
 
372
  for (int i = 0; i < file_->dependency_count(); i++) {
 
373
    if (ShouldIncludeDependency(file_->dependency(i), true)) {
 
374
      string dependency =
 
375
          name_resolver_->GetImmutableClassName(file_->dependency(i));
 
376
      printer->Print(
 
377
        "$dependency$.getDescriptor();\n",
 
378
        "dependency", dependency);
 
379
    }
 
380
  }
 
381
 
 
382
  printer->Outdent();
 
383
  printer->Print(
 
384
    "}\n");
 
385
}
 
386
 
 
387
void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* printer) {
 
388
  printer->Print(
 
389
    "public static com.google.protobuf.Descriptors.FileDescriptor\n"
 
390
    "    getDescriptor() {\n"
 
391
    "  return descriptor;\n"
 
392
    "}\n"
 
393
    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
 
394
    "    descriptor;\n"
 
395
    "static {\n");
 
396
  printer->Indent();
 
397
 
 
398
  printer->Print(
 
399
    "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n",
 
400
    "immutable_package", FileJavaPackage(file_, true),
 
401
    "descriptor_classname", name_resolver_->GetDescriptorClassName(file_));
 
402
 
 
403
  for (int i = 0; i < file_->message_type_count(); i++) {
 
404
    message_generators_[i]->GenerateStaticVariableInitializers(printer);
 
405
  }
 
406
  for (int i = 0; i < file_->extension_count(); i++) {
 
407
    extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
 
408
  }
 
409
 
 
410
  // Check if custom options exist. If any, try to load immutable classes since
 
411
  // custom options are only represented with immutable messages.
 
412
  FileDescriptorProto file_proto;
 
413
  file_->CopyTo(&file_proto);
 
414
  string file_data;
 
415
  file_proto.SerializeToString(&file_data);
 
416
  vector<const FieldDescriptor*> extensions;
 
417
  CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
 
418
 
 
419
  if (extensions.size() > 0) {
 
420
    // Try to load immutable messages' outer class. Its initialization code
 
421
    // will take care of interpreting custom options.
 
422
    printer->Print(
 
423
      "try {\n"
 
424
      // Note that we have to load the immutable class dynamically here as
 
425
      // we want the mutable code to be independent from the immutable code
 
426
      // at compile time. It is required to implement dual-compile for
 
427
      // mutable and immutable API in blaze.
 
428
      "  java.lang.Class immutableClass = java.lang.Class.forName(\n"
 
429
      "      \"$immutable_classname$\");\n"
 
430
      "} catch (java.lang.ClassNotFoundException e) {\n"
 
431
      // The immutable class can not be found. Custom options are left
 
432
      // as unknown fields.
 
433
      // TODO(xiaofeng): inform the user with a warning?
 
434
      "}\n",
 
435
      "immutable_classname", name_resolver_->GetImmutableClassName(file_));
 
436
  }
 
437
 
 
438
  // Force descriptor initialization of all dependencies.
 
439
  for (int i = 0; i < file_->dependency_count(); i++) {
 
440
    if (ShouldIncludeDependency(file_->dependency(i), false)) {
 
441
      string dependency = name_resolver_->GetMutableClassName(
 
442
          file_->dependency(i));
 
443
      printer->Print(
 
444
        "$dependency$.getDescriptor();\n",
 
445
        "dependency", dependency);
 
446
    }
 
447
  }
416
448
 
417
449
  printer->Outdent();
418
450
  printer->Print(
426
458
                            GeneratorContext* context,
427
459
                            vector<string>* file_list,
428
460
                            const string& name_suffix,
 
461
                            GeneratorClass* generator,
429
462
                            void (GeneratorClass::*pfn)(io::Printer* printer)) {
430
463
  string filename = package_dir + descriptor->name() + name_suffix + ".java";
431
464
  file_list->push_back(filename);
445
478
      "package", java_package);
446
479
  }
447
480
 
448
 
  GeneratorClass generator(descriptor);
449
 
  (generator.*pfn)(&printer);
 
481
  (generator->*pfn)(&printer);
450
482
}
451
483
 
452
484
void FileGenerator::GenerateSiblings(const string& package_dir,
453
485
                                     GeneratorContext* context,
454
486
                                     vector<string>* file_list) {
455
 
  if (file_->options().java_multiple_files()) {
 
487
  if (MultipleJavaFiles(file_, immutable_api_)) {
456
488
    for (int i = 0; i < file_->enum_type_count(); i++) {
 
489
      EnumGenerator generator(file_->enum_type(i), immutable_api_,
 
490
                              context_.get());
457
491
      GenerateSibling<EnumGenerator>(package_dir, java_package_,
458
492
                                     file_->enum_type(i),
459
493
                                     context, file_list, "",
 
494
                                     &generator,
460
495
                                     &EnumGenerator::Generate);
461
496
    }
462
497
    for (int i = 0; i < file_->message_type_count(); i++) {
463
 
      GenerateSibling<MessageGenerator>(package_dir, java_package_,
464
 
                                        file_->message_type(i),
465
 
                                        context, file_list, "OrBuilder",
466
 
                                        &MessageGenerator::GenerateInterface);
 
498
      if (immutable_api_) {
 
499
        GenerateSibling<MessageGenerator>(package_dir, java_package_,
 
500
                                          file_->message_type(i),
 
501
                                          context, file_list,
 
502
                                          "OrBuilder",
 
503
                                          message_generators_[i].get(),
 
504
                                          &MessageGenerator::GenerateInterface);
 
505
      }
467
506
      GenerateSibling<MessageGenerator>(package_dir, java_package_,
468
507
                                        file_->message_type(i),
469
508
                                        context, file_list, "",
 
509
                                        message_generators_[i].get(),
470
510
                                        &MessageGenerator::Generate);
471
511
    }
472
512
    if (HasGenericServices(file_)) {
473
513
      for (int i = 0; i < file_->service_count(); i++) {
 
514
        scoped_ptr<ServiceGenerator> generator(
 
515
            generator_factory_->NewServiceGenerator(file_->service(i)));
474
516
        GenerateSibling<ServiceGenerator>(package_dir, java_package_,
475
517
                                          file_->service(i),
476
518
                                          context, file_list, "",
 
519
                                          generator.get(),
477
520
                                          &ServiceGenerator::Generate);
478
521
      }
479
522
    }
480
523
  }
481
524
}
482
525
 
483
 
bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) {
 
526
bool FileGenerator::ShouldIncludeDependency(
 
527
    const FileDescriptor* descriptor, bool immutable_api) {
484
528
  return true;
485
529
}
486
530