temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 1 | // Protocol Buffers - Google's data interchange format |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 2 | // Copyright 2008 Google Inc. All rights reserved. |
Feng Xiao | e428862 | 2014-10-01 16:26:23 -0700 | [diff] [blame] | 3 | // https://developers.google.com/protocol-buffers/ |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 4 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 8 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 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. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 18 | // |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 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. |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 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> |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 36 | |
| 37 | #include <memory> |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 38 | #ifndef _SHARED_PTR_H |
| 39 | #include <google/protobuf/stubs/shared_ptr.h> |
| 40 | #endif |
Bo Yang | 5db2173 | 2015-05-21 14:28:59 -0700 | [diff] [blame] | 41 | #include <set> |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 42 | |
| 43 | #include <google/protobuf/compiler/java/java_context.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 44 | #include <google/protobuf/compiler/java/java_enum.h> |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 45 | #include <google/protobuf/compiler/java/java_enum_lite.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 46 | #include <google/protobuf/compiler/java/java_extension.h> |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 47 | #include <google/protobuf/compiler/java/java_generator_factory.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 48 | #include <google/protobuf/compiler/java/java_helpers.h> |
| 49 | #include <google/protobuf/compiler/java/java_message.h> |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 50 | #include <google/protobuf/compiler/java/java_name_resolver.h> |
| 51 | #include <google/protobuf/compiler/java/java_service.h> |
jieluo@google.com | 7db9c09 | 2014-08-07 19:03:12 +0000 | [diff] [blame] | 52 | #include <google/protobuf/compiler/java/java_shared_code_generator.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 53 | #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.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 57 | #include <google/protobuf/dynamic_message.h> |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 58 | #include <google/protobuf/stubs/strutil.h> |
| 59 | |
| 60 | namespace google { |
| 61 | namespace protobuf { |
| 62 | namespace compiler { |
| 63 | namespace java { |
| 64 | |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 65 | namespace { |
| 66 | |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 67 | struct FieldDescriptorCompare { |
| 68 | bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) { |
Daniel Martin | 153a226 | 2015-04-08 09:53:26 -0400 | [diff] [blame] | 69 | if(f1 == NULL) { |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 70 | return false; |
| 71 | } |
| 72 | if(f2 == NULL) { |
| 73 | return true; |
| 74 | } |
| 75 | return f1->full_name() < f2->full_name(); |
| 76 | } |
| 77 | }; |
| 78 | |
| 79 | typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> FieldDescriptorSet; |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 80 | |
| 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. |
| 86 | bool CollectExtensions(const Message& message, |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 87 | FieldDescriptorSet* extensions) { |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 88 | const Reflection* reflection = message.GetReflection(); |
| 89 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 90 | // There are unknown fields that could be extensions, thus this call fails. |
| 91 | if (reflection->GetUnknownFields(message).field_count() > 0) return false; |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 92 | |
| 93 | vector<const FieldDescriptor*> fields; |
| 94 | reflection->ListFields(message, &fields); |
| 95 | |
| 96 | for (int i = 0; i < fields.size(); i++) { |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 97 | if (fields[i]->is_extension()) extensions->insert(fields[i]); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 98 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 99 | if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 100 | 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.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 105 | if (!CollectExtensions(sub_message, extensions)) return false; |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 106 | } |
| 107 | } else { |
| 108 | const Message& sub_message = reflection->GetMessage(message, fields[i]); |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 109 | if (!CollectExtensions(sub_message, extensions)) return false; |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 110 | } |
| 111 | } |
| 112 | } |
| 113 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 114 | 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. |
| 122 | void CollectExtensions(const FileDescriptorProto& file_proto, |
| 123 | const DescriptorPool& alternate_pool, |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 124 | FieldDescriptorSet* extensions, |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 125 | 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 Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 139 | google::protobuf::scoped_ptr<Message> dynamic_file_proto( |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 140 | 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.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 155 | } |
| 156 | |
Bo Yang | 5db2173 | 2015-05-21 14:28:59 -0700 | [diff] [blame] | 157 | // Compare two field descriptors, returning true if the first should come |
| 158 | // before the second. |
| 159 | bool CompareFieldsByName(const FieldDescriptor *a, const FieldDescriptor *b) { |
| 160 | return a->full_name() < b->full_name(); |
| 161 | } |
| 162 | |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 163 | // 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. |
| 171 | void MaybeRestartJavaMethod(io::Printer* printer, |
| 172 | int *bytecode_estimate, |
| 173 | int *method_num, |
| 174 | const char *chain_statement, |
| 175 | const char *method_decl) { |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 176 | // 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.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 192 | |
Bo Yang | 5db2173 | 2015-05-21 14:28:59 -0700 | [diff] [blame] | 193 | |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 194 | } // namespace |
| 195 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 196 | FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) |
| 197 | : file_(file), |
| 198 | java_package_(FileJavaPackage(file, immutable_api)), |
| 199 | message_generators_( |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 200 | new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]), |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 201 | extension_generators_( |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 202 | new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]), |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 203 | 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.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 217 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 218 | |
| 219 | FileGenerator::~FileGenerator() {} |
| 220 | |
| 221 | bool 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.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 226 | if (name_resolver_->HasConflictingClassName(file_, classname_)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 227 | 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 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 237 | return true; |
| 238 | } |
| 239 | |
| 240 | void 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.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 245 | "// source: $filename$\n" |
| 246 | "\n", |
| 247 | "filename", file_->name()); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 248 | 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 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 262 | printer->Print( |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 263 | "public static void registerAllExtensions(\n" |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 264 | " com.google.protobuf.ExtensionRegistry$lite$ registry) {\n", |
| 265 | "lite", HasDescriptorMethods(file_) ? "" : "Lite"); |
| 266 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 267 | printer->Indent(); |
| 268 | |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 269 | for (int i = 0; i < file_->extension_count(); i++) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 270 | extension_generators_[i]->GenerateRegistrationCode(printer); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 271 | } |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 272 | |
| 273 | for (int i = 0; i < file_->message_type_count(); i++) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 274 | message_generators_[i]->GenerateExtensionRegistrationCode(printer); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 275 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 276 | |
| 277 | printer->Outdent(); |
| 278 | printer->Print( |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 279 | "}\n"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 280 | |
| 281 | // ----------------------------------------------------------------- |
| 282 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 283 | if (!MultipleJavaFiles(file_, immutable_api_)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 284 | for (int i = 0; i < file_->enum_type_count(); i++) { |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 285 | 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 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 292 | } |
| 293 | for (int i = 0; i < file_->message_type_count(); i++) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 294 | message_generators_[i]->GenerateInterface(printer); |
| 295 | message_generators_[i]->Generate(printer); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 296 | } |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 297 | if (HasGenericServices(file_)) { |
| 298 | for (int i = 0; i < file_->service_count(); i++) { |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 299 | google::protobuf::scoped_ptr<ServiceGenerator> generator( |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 300 | generator_factory_->NewServiceGenerator(file_->service(i))); |
| 301 | generator->Generate(printer); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 302 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 303 | } |
| 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.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 309 | extension_generators_[i]->Generate(printer); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | // Static variables. |
| 313 | for (int i = 0; i < file_->message_type_count(); i++) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 314 | message_generators_[i]->GenerateStaticVariables(printer); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 315 | } |
| 316 | |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 317 | printer->Print("\n"); |
| 318 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 319 | if (HasDescriptorMethods(file_)) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 320 | if (immutable_api_) { |
| 321 | GenerateDescriptorInitializationCodeForImmutable(printer); |
| 322 | } else { |
| 323 | GenerateDescriptorInitializationCodeForMutable(printer); |
| 324 | } |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 325 | } else { |
| 326 | printer->Print( |
| 327 | "static {\n"); |
| 328 | printer->Indent(); |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 329 | int bytecode_estimate = 0; |
| 330 | int method_num = 0; |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 331 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 332 | for (int i = 0; i < file_->message_type_count(); i++) { |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 333 | 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.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 339 | } |
| 340 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 341 | printer->Outdent(); |
| 342 | printer->Print( |
| 343 | "}\n"); |
| 344 | } |
| 345 | |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 346 | printer->Print( |
| 347 | "\n" |
| 348 | "// @@protoc_insertion_point(outer_class_scope)\n"); |
| 349 | |
kenton@google.com | 80b1d62 | 2009-07-29 01:13:20 +0000 | [diff] [blame] | 350 | printer->Outdent(); |
| 351 | printer->Print("}\n"); |
| 352 | } |
| 353 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 354 | void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( |
| 355 | io::Printer* printer) { |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 356 | printer->Print( |
| 357 | "public static com.google.protobuf.Descriptors.FileDescriptor\n" |
| 358 | " getDescriptor() {\n" |
| 359 | " return descriptor;\n" |
| 360 | "}\n" |
jieluo@google.com | d733931 | 2014-08-07 22:22:00 +0000 | [diff] [blame] | 361 | "private static com.google.protobuf.Descriptors.FileDescriptor\n" |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 362 | " descriptor;\n" |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 363 | "static {\n"); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 364 | printer->Indent(); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 365 | |
jieluo@google.com | 7db9c09 | 2014-08-07 19:03:12 +0000 | [diff] [blame] | 366 | SharedCodeGenerator shared_code_generator(file_); |
| 367 | shared_code_generator.GenerateDescriptors(printer); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 368 | |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 369 | int bytecode_estimate = 0; |
| 370 | int method_num = 0; |
Feng Xiao | 6ef984a | 2014-11-10 17:34:54 -0800 | [diff] [blame] | 371 | |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 372 | for (int i = 0; i < file_->message_type_count(); i++) { |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 373 | 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.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 379 | } |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 380 | for (int i = 0; i < file_->extension_count(); i++) { |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 381 | 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.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 387 | } |
| 388 | |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 389 | // 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.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 404 | FileDescriptorProto file_proto; |
| 405 | file_->CopyTo(&file_proto); |
| 406 | string file_data; |
| 407 | file_proto.SerializeToString(&file_data); |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 408 | FieldDescriptorSet extensions; |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 409 | 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.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 413 | // and use it to parse the descriptor data again to recognize extensions. |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 414 | printer->Print( |
| 415 | "com.google.protobuf.ExtensionRegistry registry =\n" |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 416 | " com.google.protobuf.ExtensionRegistry.newInstance();\n"); |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 417 | FieldDescriptorSet::iterator it; |
| 418 | for (it = extensions.begin(); it != extensions.end(); it++) { |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 419 | google::protobuf::scoped_ptr<ExtensionGenerator> generator( |
Daniel Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 420 | 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.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 428 | } |
| 429 | printer->Print( |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 430 | "com.google.protobuf.Descriptors.FileDescriptor\n" |
| 431 | " .internalUpdateFileDescriptor(descriptor, registry);\n"); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 432 | } |
| 433 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 434 | // Force descriptor initialization of all dependencies. |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 435 | for (int i = 0; i < file_->dependency_count(); i++) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 436 | if (ShouldIncludeDependency(file_->dependency(i), true)) { |
| 437 | string dependency = |
| 438 | name_resolver_->GetImmutableClassName(file_->dependency(i)); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 439 | printer->Print( |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 440 | "$dependency$.getDescriptor();\n", |
| 441 | "dependency", dependency); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 442 | } |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 443 | } |
| 444 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 445 | printer->Outdent(); |
kenton@google.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 446 | printer->Print( |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 447 | "}\n"); |
| 448 | } |
| 449 | |
| 450 | void 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 Martin | e2416ca | 2014-11-25 10:37:57 -0500 | [diff] [blame] | 479 | FieldDescriptorSet extensions; |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 480 | 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.com | 24bf56f | 2008-09-24 20:31:01 +0000 | [diff] [blame] | 511 | |
| 512 | printer->Outdent(); |
| 513 | printer->Print( |
| 514 | "}\n"); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 515 | } |
| 516 | |
| 517 | template<typename GeneratorClass, typename DescriptorClass> |
| 518 | static void GenerateSibling(const string& package_dir, |
| 519 | const string& java_package, |
| 520 | const DescriptorClass* descriptor, |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 521 | GeneratorContext* context, |
| 522 | vector<string>* file_list, |
| 523 | const string& name_suffix, |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 524 | GeneratorClass* generator, |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 525 | void (GeneratorClass::*pfn)(io::Printer* printer)) { |
| 526 | string filename = package_dir + descriptor->name() + name_suffix + ".java"; |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 527 | file_list->push_back(filename); |
| 528 | |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 529 | google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 530 | io::Printer printer(output.get(), '$'); |
| 531 | |
| 532 | printer.Print( |
| 533 | "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
xiaofeng@google.com | b55a20f | 2012-09-22 02:40:50 +0000 | [diff] [blame] | 534 | "// source: $filename$\n" |
| 535 | "\n", |
| 536 | "filename", descriptor->file()->name()); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 537 | if (!java_package.empty()) { |
| 538 | printer.Print( |
| 539 | "package $package$;\n" |
| 540 | "\n", |
| 541 | "package", java_package); |
| 542 | } |
| 543 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 544 | (generator->*pfn)(&printer); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 545 | } |
| 546 | |
| 547 | void FileGenerator::GenerateSiblings(const string& package_dir, |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 548 | GeneratorContext* context, |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 549 | vector<string>* file_list) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 550 | if (MultipleJavaFiles(file_, immutable_api_)) { |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 551 | for (int i = 0; i < file_->enum_type_count(); i++) { |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 552 | 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 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 569 | } |
| 570 | for (int i = 0; i < file_->message_type_count(); i++) { |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 571 | 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.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 579 | GenerateSibling<MessageGenerator>(package_dir, java_package_, |
| 580 | file_->message_type(i), |
| 581 | context, file_list, "", |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 582 | message_generators_[i].get(), |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 583 | &MessageGenerator::Generate); |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 584 | } |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 585 | if (HasGenericServices(file_)) { |
| 586 | for (int i = 0; i < file_->service_count(); i++) { |
Feng Xiao | f157a56 | 2014-11-14 11:50:31 -0800 | [diff] [blame] | 587 | google::protobuf::scoped_ptr<ServiceGenerator> generator( |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 588 | generator_factory_->NewServiceGenerator(file_->service(i))); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 589 | GenerateSibling<ServiceGenerator>(package_dir, java_package_, |
| 590 | file_->service(i), |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 591 | context, file_list, "", |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 592 | generator.get(), |
liujisi@google.com | 33165fe | 2010-11-02 13:14:58 +0000 | [diff] [blame] | 593 | &ServiceGenerator::Generate); |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 594 | } |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 595 | } |
| 596 | } |
| 597 | } |
| 598 | |
jieluo@google.com | 4de8f55 | 2014-07-18 00:47:59 +0000 | [diff] [blame] | 599 | bool FileGenerator::ShouldIncludeDependency( |
| 600 | const FileDescriptor* descriptor, bool immutable_api) { |
kenton@google.com | fccb146 | 2009-12-18 02:11:36 +0000 | [diff] [blame] | 601 | return true; |
| 602 | } |
| 603 | |
temporal | 40ee551 | 2008-07-10 02:12:20 +0000 | [diff] [blame] | 604 | } // namespace java |
| 605 | } // namespace compiler |
| 606 | } // namespace protobuf |
| 607 | } // namespace google |