text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

#include <map>
#include <string>

#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum.h>
#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
                             bool immutable_api,
                             Context* context)
  : descriptor_(descriptor), immutable_api_(immutable_api),
    context_(context),
    name_resolver_(context->GetNameResolver())  {
  for (int i = 0; i < descriptor_->value_count(); i++) {
    const EnumValueDescriptor* value = descriptor_->value(i);
    const EnumValueDescriptor* canonical_value =
      descriptor_->FindValueByNumber(value->number());

    if (value == canonical_value) {
      canonical_values_.push_back(value);
    } else {
      Alias alias;
      alias.value = value;
      alias.canonical_value = canonical_value;
      aliases_.push_back(alias);
    }
  }
}

EnumGenerator::~EnumGenerator() {}

void EnumGenerator::Generate(io::Printer* printer) {
  WriteEnumDocComment(printer, descriptor_);
  MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
  printer->Print(
      "public enum $classname$\n"
      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
      "classname", descriptor_->name());
  printer->Annotate("classname", descriptor_);
  printer->Indent();

  bool ordinal_is_index = true;
  string index_text = "ordinal()";
  for (int i = 0; i < canonical_values_.size(); i++) {
    if (canonical_values_[i]->index() != i) {
      ordinal_is_index = false;
      index_text = "index";
      break;
    }
  }

  for (int i = 0; i < canonical_values_.size(); i++) {
    std::map<string, string> vars;
    vars["name"] = canonical_values_[i]->name();
    vars["index"] = SimpleItoa(canonical_values_[i]->index());
    vars["number"] = SimpleItoa(canonical_values_[i]->number());
    WriteEnumValueDocComment(printer, canonical_values_[i]);
    if (canonical_values_[i]->options().deprecated()) {
      printer->Print("@java.lang.Deprecated\n");
    }
    if (ordinal_is_index) {
      printer->Print(vars,
        "$name$($number$),\n");
    } else {
      printer->Print(vars,
        "$name$($index$, $number$),\n");
    }
    printer->Annotate("name", canonical_values_[i]);
  }

  if (SupportUnknownEnumValue(descriptor_->file())) {
    if (ordinal_is_index) {
      printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", "");
    } else {
      printer->Print("${$UNRECOGNIZED$}$(-1, -1),\n", "{", "", "}", "");
    }
    printer->Annotate("{", "}", descriptor_);
  }

  printer->Print(
    ";\n"
    "\n");

  // -----------------------------------------------------------------

  for (int i = 0; i < aliases_.size(); i++) {
    std::map<string, string> vars;
    vars["classname"] = descriptor_->name();
    vars["name"] = aliases_[i].value->name();
    vars["canonical_name"] = aliases_[i].canonical_value->name();
    WriteEnumValueDocComment(printer, aliases_[i].value);
    printer->Print(vars,
      "public static final $classname$ $name$ = $canonical_name$;\n");
    printer->Annotate("name", aliases_[i].value);
  }

  for (int i = 0; i < descriptor_->value_count(); i++) {
    std::map<string, string> vars;
    vars["name"] = descriptor_->value(i)->name();
    vars["number"] = SimpleItoa(descriptor_->value(i)->number());
    vars["{"] = "";
    vars["}"] = "";
    WriteEnumValueDocComment(printer, descriptor_->value(i));
    printer->Print(vars,
      "public static final int ${$$name$_VALUE$}$ = $number$;\n");
    printer->Annotate("{", "}", descriptor_->value(i));
  }
  printer->Print("\n");

  // -----------------------------------------------------------------

  printer->Print(
    "\n"
    "public final int getNumber() {\n");
  if (SupportUnknownEnumValue(descriptor_->file())) {
    if (ordinal_is_index) {
      printer->Print(
        "  if (this == UNRECOGNIZED) {\n"
        "    throw new java.lang.IllegalArgumentException(\n"
        "        \"Can't get the number of an unknown enum value.\");\n"
        "  }\n");
    } else {
      printer->Print(
        "  if (index == -1) {\n"
        "    throw new java.lang.IllegalArgumentException(\n"
        "        \"Can't get the number of an unknown enum value.\");\n"
        "  }\n");
    }
  }
  printer->Print(
    "  return value;\n"
    "}\n"
    "\n"
    "/**\n"
    " * @deprecated Use {@link #forNumber(int)} instead.\n"
    " */\n"
    "@java.lang.Deprecated\n"
    "public static $classname$ valueOf(int value) {\n"
    "  return forNumber(value);\n"
    "}\n"
    "\n"
    "public static $classname$ forNumber(int value) {\n"
    "  switch (value) {\n",
    "classname", descriptor_->name());
  printer->Indent();
  printer->Indent();

  for (int i = 0; i < canonical_values_.size(); i++) {
    printer->Print(
      "case $number$: return $name$;\n",
      "name", canonical_values_[i]->name(),
      "number", SimpleItoa(canonical_values_[i]->number()));
  }

  printer->Outdent();
  printer->Outdent();
  printer->Print(
    "    default: return null;\n"
    "  }\n"
    "}\n"
    "\n"
    "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
    "    internalGetValueMap() {\n"
    "  return internalValueMap;\n"
    "}\n"
    "private static final com.google.protobuf.Internal.EnumLiteMap<\n"
    "    $classname$> internalValueMap =\n"
    "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
    "        public $classname$ findValueByNumber(int number) {\n"
    "          return $classname$.forNumber(number);\n"
    "        }\n"
    "      };\n"
    "\n",
    "classname", descriptor_->name());

  // -----------------------------------------------------------------
  // Reflection

  if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
    printer->Print(
      "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
      "    getValueDescriptor() {\n"
      "  return getDescriptor().getValues().get($index_text$);\n"
      "}\n"
      "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
      "    getDescriptorForType() {\n"
      "  return getDescriptor();\n"
      "}\n"
      "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
      "    getDescriptor() {\n",
      "index_text", index_text);

    // TODO(kenton):  Cache statically?  Note that we can't access descriptors
    //   at module init time because it wouldn't work with descriptor.proto, but
    //   we can cache the value the first time getDescriptor() is called.
    if (descriptor_->containing_type() == NULL) {
      // The class generated for the File fully populates the descriptor with
      // extensions in both the mutable and immutable cases. (In the mutable api
      // this is accomplished by attempting to load the immutable outer class).
      printer->Print(
        "  return $file$.getDescriptor().getEnumTypes().get($index$);\n",
        "file", name_resolver_->GetClassName(descriptor_->file(),
                                             immutable_api_),
        "index", SimpleItoa(descriptor_->index()));
    } else {
      printer->Print(
          "  return $parent$.$descriptor$.getEnumTypes().get($index$);\n",
          "parent", name_resolver_->GetClassName(descriptor_->containing_type(),
                                                 immutable_api_),
          "descriptor", descriptor_->containing_type()->options()
                        .no_standard_descriptor_accessor()
                        ? "getDefaultInstance().getDescriptorForType()"
                        : "getDescriptor()",
          "index", SimpleItoa(descriptor_->index()));
    }

    printer->Print(
      "}\n"
      "\n"
      "private static final $classname$[] VALUES = ",
      "classname", descriptor_->name());

    if (CanUseEnumValues()) {
      // If the constants we are going to output are exactly the ones we
      // have declared in the Java enum in the same order, then we can use
      // the values() method that the Java compiler automatically generates
      // for every enum.
      printer->Print("values();\n");
    } else {
      printer->Print(
        "{\n"
        "  ");
      for (int i = 0; i < descriptor_->value_count(); i++) {
        printer->Print("$name$, ",
          "name", descriptor_->value(i)->name());
      }
      printer->Print(
          "\n"
          "};\n");
    }

    printer->Print(
      "\n"
      "public static $classname$ valueOf(\n"
      "    com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
      "  if (desc.getType() != getDescriptor()) {\n"
      "    throw new java.lang.IllegalArgumentException(\n"
      "      \"EnumValueDescriptor is not for this type.\");\n"
      "  }\n",
      "classname", descriptor_->name());
    if (SupportUnknownEnumValue(descriptor_->file())) {
      printer->Print(
        "  if (desc.getIndex() == -1) {\n"
        "    return UNRECOGNIZED;\n"
        "  }\n");
    }
    printer->Print(
      "  return VALUES[desc.getIndex()];\n"
      "}\n"
      "\n");

    if (!ordinal_is_index) {
      printer->Print("private final int index;\n");
    }
  }

  // -----------------------------------------------------------------

  printer->Print(
    "private final int value;\n\n");

  if (ordinal_is_index) {
    printer->Print(
      "private $classname$(int value) {\n",
      "classname", descriptor_->name());
  } else {
    printer->Print(
      "private $classname$(int index, int value) {\n",
      "classname", descriptor_->name());
  }
  if (HasDescriptorMethods(descriptor_, context_->EnforceLite()) &&
      !ordinal_is_index) {
    printer->Print("  this.index = index;\n");
  }
  printer->Print(
    "  this.value = value;\n"
    "}\n");

  printer->Print(
    "\n"
    "// @@protoc_insertion_point(enum_scope:$full_name$)\n",
    "full_name", descriptor_->full_name());

  printer->Outdent();
  printer->Print("}\n\n");
}

bool EnumGenerator::CanUseEnumValues() {
  if (canonical_values_.size() != descriptor_->value_count()) {
    return false;
  }
  for (int i = 0; i < descriptor_->value_count(); i++) {
    if (descriptor_->value(i)->name() != canonical_values_[i]->name()) {
      return false;
    }
  }
  return true;
}

}  // namespace java
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/compiler/java/java_context.h>

#include <google/protobuf/compiler/java/java_field.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

Context::Context(const FileDescriptor* file, const Options& options)
    : name_resolver_(new ClassNameResolver), options_(options) {
  InitializeFieldGeneratorInfo(file);
}

Context::~Context() {
}

ClassNameResolver* Context::GetNameResolver() const {
  return name_resolver_.get();
}

namespace {
// Whether two fields have conflicting accessors (assuming name1 and name2
// are different). name1 and name2 are field1 and field2's camel-case name
// respectively.
bool IsConflicting(const FieldDescriptor* field1, const string& name1,
                   const FieldDescriptor* field2, const string& name2,
                   string* info) {
  if (field1->is_repeated()) {
    if (field2->is_repeated()) {
      // Both fields are repeated.
      return false;
    } else {
      // field1 is repeated, and field2 is not.
      if (name1 + "Count" == name2) {
        *info = "both repeated field \"" + field1->name() + "\" and singular " +
            "field \"" + field2->name() + "\" generates the method \"" +
            "get" + name1 + "Count()\"";
        return true;
      }
      if (name1 + "List" == name2) {
        *info = "both repeated field \"" + field1->name() + "\" and singular " +
            "field \"" + field2->name() + "\" generates the method \"" +
            "get" + name1 + "List()\"";
        return true;
      }
      // Well, there are obviously many more conflicting cases, but it probably
      // doesn't worth the effort to exhaust all of them because they rarely
      // happen and as we are continuing adding new methods/changing existing
      // methods the number of different conflicting cases will keep growing.
      // We can just add more cases here when they are found in the real world.
      return false;
    }
  } else {
    if (field2->is_repeated()) {
      return IsConflicting(field2, name2, field1, name1, info);
    } else {
      // None of the two fields are repeated.
      return false;
    }
  }
}
}  // namespace

void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) {
  for (int i = 0; i < file->message_type_count(); ++i) {
    InitializeFieldGeneratorInfoForMessage(file->message_type(i));
  }
}

void Context::InitializeFieldGeneratorInfoForMessage(
    const Descriptor* message) {
  for (int i = 0; i < message->nested_type_count(); ++i) {
    InitializeFieldGeneratorInfoForMessage(message->nested_type(i));
  }
  std::vector<const FieldDescriptor*> fields;
  for (int i = 0; i < message->field_count(); ++i) {
    fields.push_back(message->field(i));
  }
  InitializeFieldGeneratorInfoForFields(fields);

  for (int i = 0; i < message->oneof_decl_count(); ++i) {
    const OneofDescriptor* oneof = message->oneof_decl(i);
    OneofGeneratorInfo info;
    info.name = UnderscoresToCamelCase(oneof->name(), false);
    info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true);
    oneof_generator_info_map_[oneof] = info;
  }
}

void Context::InitializeFieldGeneratorInfoForFields(
    const std::vector<const FieldDescriptor*>& fields) {
  // Find out all fields that conflict with some other field in the same
  // message.
  std::vector<bool> is_conflict(fields.size());
  std::vector<string> conflict_reason(fields.size());
  for (int i = 0; i < fields.size(); ++i) {
    const FieldDescriptor* field = fields[i];
    const string& name = UnderscoresToCapitalizedCamelCase(field);
    for (int j = i + 1; j < fields.size(); ++j) {
      const FieldDescriptor* other = fields[j];
      const string& other_name = UnderscoresToCapitalizedCamelCase(other);
      if (name == other_name) {
        is_conflict[i] = is_conflict[j] = true;
        conflict_reason[i] = conflict_reason[j] =
            "capitalized name of field \"" + field->name() +
            "\" conflicts with field \"" + other->name() + "\"";
      } else if (IsConflicting(field, name, other, other_name,
                               &conflict_reason[j])) {
        is_conflict[i] = is_conflict[j] = true;
        conflict_reason[i] = conflict_reason[j];
      }
    }
    if (is_conflict[i]) {
      GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting "
                   << "with another field: " << conflict_reason[i];
    }
  }
  for (int i = 0; i < fields.size(); ++i) {
    const FieldDescriptor* field = fields[i];
    FieldGeneratorInfo info;
    info.name = CamelCaseFieldName(field);
    info.capitalized_name = UnderscoresToCapitalizedCamelCase(field);
    // For fields conflicting with some other fields, we append the field
    // number to their field names in generated code to avoid conflicts.
    if (is_conflict[i]) {
      info.name += SimpleItoa(field->number());
      info.capitalized_name += SimpleItoa(field->number());
      info.disambiguated_reason = conflict_reason[i];
    }
    field_generator_info_map_[field] = info;
  }
}

const FieldGeneratorInfo* Context::GetFieldGeneratorInfo(
    const FieldDescriptor* field) const {
  const FieldGeneratorInfo* result =
      FindOrNull(field_generator_info_map_, field);
  if (result == NULL) {
    GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: "
               << field->full_name();
  }
  return result;
}

const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
    const OneofDescriptor* oneof) const {
  const OneofGeneratorInfo* result =
      FindOrNull(oneof_generator_info_map_, oneof);
  if (result == NULL) {
    GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: "
               << oneof->name();
  }
  return result;
}

// Does this message class have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
  return options_.enforce_lite ||
         descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE;
}

}  // namespace java
}  // namespace compiler
}  // namespace protobuf
}  // namespace google

mime_type: text/plain


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: liujisi@google.com (Pherl Liu)

#include <google/protobuf/compiler/java/java_generator_factory.h>

#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_enum_field.h>
#include <google/protobuf/compiler/java/java_extension.h>
#include <google/protobuf/compiler/java/java_extension_lite.h>
#include <google/protobuf/compiler/java/java_field.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_message.h>
#include <google/protobuf/compiler/java/java_message_lite.h>
#include <google/protobuf/compiler/java/java_service.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

GeneratorFactory::GeneratorFactory() {}
GeneratorFactory::~GeneratorFactory() {}

// ===================================================================

ImmutableGeneratorFactory::ImmutableGeneratorFactory(
    Context* context) : context_(context) {
}
ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {}

MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
    const Descriptor* descriptor) const {
  if (HasDescriptorMethods(descriptor, context_->EnforceLite())) {
    return new ImmutableMessageGenerator(descriptor, context_);
  } else {
    return new ImmutableMessageLiteGenerator(descriptor, context_);
  }
}

ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
    const FieldDescriptor* descriptor) const {
  if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) {
    return new ImmutableExtensionGenerator(descriptor, context_);
  } else {
    return new ImmutableExtensionLiteGenerator(descriptor, context_);
  }
}

ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator(
    const ServiceDescriptor* descriptor) const {
  return new ImmutableServiceGenerator(descriptor, context_);
}

}  // namespace java
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

#include <map>
#include <string>

#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_enum_field_lite.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

namespace {

void SetEnumVariables(const FieldDescriptor* descriptor,
                      int messageBitIndex,
                      int builderBitIndex,
                      const FieldGeneratorInfo* info,
                      ClassNameResolver* name_resolver,
                      std::map<string, string>* variables) {
  SetCommonFieldVariables(descriptor, info, variables);

  (*variables)["type"] =
      name_resolver->GetImmutableClassName(descriptor->enum_type());
  (*variables)["mutable_type"] =
      name_resolver->GetMutableClassName(descriptor->enum_type());
  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
  (*variables)["default_number"] = SimpleItoa(
      descriptor->default_value_enum()->number());
  (*variables)["tag"] =
      SimpleItoa(static_cast<int32>(internal::WireFormat::MakeTag(descriptor)));
  (*variables)["tag_size"] = SimpleItoa(
      internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
  // by the proto compiler
  (*variables)["deprecation"] = descriptor->options().deprecated()
      ? "@java.lang.Deprecated " : "";
  (*variables)["required"] = descriptor->is_required() ? "true" : "false";

  if (SupportFieldPresence(descriptor->file())) {
    // For singular messages and builders, one bit is used for the hasField bit.
    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);

    // Note that these have a trailing ";".
    (*variables)["set_has_field_bit_message"] =
        GenerateSetBit(messageBitIndex) + ";";
    (*variables)["clear_has_field_bit_message"] =
        GenerateClearBit(messageBitIndex) + ";";

    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
  } else {
    (*variables)["set_has_field_bit_message"] = "";
    (*variables)["clear_has_field_bit_message"] = "";

    (*variables)["is_field_present_message"] =
        (*variables)["name"] + "_ != " +
        (*variables)["default"] + ".getNumber()";
  }

  // For repeated builders, the underlying list tracks mutability state.
  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";

  (*variables)["get_has_field_bit_from_local"] =
      GenerateGetBitFromLocal(builderBitIndex);
  (*variables)["set_has_field_bit_to_local"] =
      GenerateSetBitToLocal(messageBitIndex);

  if (SupportUnknownEnumValue(descriptor->file())) {
    (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED";
  } else {
    (*variables)["unknown"] = (*variables)["default"];
  }
}

}  // namespace

// ===================================================================

ImmutableEnumFieldLiteGenerator::
ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
                            int messageBitIndex,
                            int builderBitIndex,
                            Context* context)
  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
    builderBitIndex_(builderBitIndex),
    name_resolver_(context->GetNameResolver()) {
  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
                   context->GetFieldGeneratorInfo(descriptor),
                   name_resolver_, &variables_);
}

ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}

int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
  return 1;
}

int ImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
  return 0;
}

void ImmutableEnumFieldLiteGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
  if (SupportFieldPresence(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$boolean has$capitalized_name$();\n");
  }
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$int get$capitalized_name$Value();\n");
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$$type$ get$capitalized_name$();\n");
}

void ImmutableEnumFieldLiteGenerator::
GenerateMembers(io::Printer* printer) const {
  printer->Print(variables_,
    "private int $name$_;\n");
  PrintExtraFieldInfo(variables_, printer);
  if (SupportFieldPresence(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
      "  return $get_has_field_bit_message$;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
      "  return $name$_;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
    "  $type$ result = $type$.forNumber($name$_);\n"
    "  return result == null ? $unknown$ : result;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);

  // Generate private setters for the builder to proxy into.
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "private void set$capitalized_name$Value(int value) {\n"
      "  $set_has_field_bit_message$"
      "  $name$_ = value;\n"
      "}\n");
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void set$capitalized_name$($type$ value) {\n"
    "  if (value == null) {\n"
    "    throw new NullPointerException();\n"
    "  }\n"
    "  $set_has_field_bit_message$\n"
    "  $name$_ = value.getNumber();\n"
    "}\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void clear$capitalized_name$() {\n"
    "  $clear_has_field_bit_message$\n"
    "  $name$_ = $default_number$;\n"
    "}\n");
}

void ImmutableEnumFieldLiteGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
  if (SupportFieldPresence(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
      "  return instance.has$capitalized_name$();\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
      "  return instance.get$capitalized_name$Value();\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public Builder "
      "${$set$capitalized_name$Value$}$(int value) {\n"
      "  copyOnWrite();\n"
      "  instance.set$capitalized_name$Value(value);\n"
      "  return this;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
    "  return instance.get$capitalized_name$();\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$set$capitalized_name$$}$($type$ value) {\n"
    "  copyOnWrite();\n"
    "  instance.set$capitalized_name$(value);\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
    "  copyOnWrite();\n"
    "  instance.clear$capitalized_name$();\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
}

void ImmutableEnumFieldLiteGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
  // noop for enums
}

void ImmutableEnumFieldLiteGenerator::
GenerateInitializationCode(io::Printer* printer) const {
  if (!IsDefaultValueJavaDefault(descriptor_)) {
    printer->Print(variables_, "$name$_ = $default_number$;\n");
  }
}

void ImmutableEnumFieldLiteGenerator::
GenerateVisitCode(io::Printer* printer) const {
  if (SupportFieldPresence(descriptor_->file())) {
    printer->Print(variables_,
      "$name$_ = visitor.visitInt(has$capitalized_name$(), $name$_,\n"
      "    other.has$capitalized_name$(), other.$name$_);\n");
  } else if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "$name$_ = visitor.visitInt($name$_ != $default_number$, $name$_,"
      "    other.$name$_ != $default_number$, other.$name$_);\n");
  } else {
    GOOGLE_LOG(FATAL) << "Can't reach here.";
  }
}

void ImmutableEnumFieldLiteGenerator::
GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
  // noop for scalars
}

void ImmutableEnumFieldLiteGenerator::
GenerateParsingCode(io::Printer* printer) const {
  if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "int rawValue = input.readEnum();\n"
      "$set_has_field_bit_message$\n"
      "$name$_ = rawValue;\n");
  } else {
    printer->Print(variables_,
      "int rawValue = input.readEnum();\n"
      "$type$ value = $type$.forNumber(rawValue);\n"
      "if (value == null) {\n"
      "  super.mergeVarintField($number$, rawValue);\n"
      "} else {\n"
      "  $set_has_field_bit_message$\n"
      "  $name$_ = rawValue;\n"
      "}\n");
  }
}

void ImmutableEnumFieldLiteGenerator::
GenerateParsingDoneCode(io::Printer* printer) const {
  // noop for enums
}

void ImmutableEnumFieldLiteGenerator::
GenerateSerializationCode(io::Printer* printer) const {
  printer->Print(variables_,
    "if ($is_field_present_message$) {\n"
    "  output.writeEnum($number$, $name$_);\n"
    "}\n");
}

void ImmutableEnumFieldLiteGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
  printer->Print(variables_,
    "if ($is_field_present_message$) {\n"
    "  size += com.google.protobuf.CodedOutputStream\n"
    "    .computeEnumSize($number$, $name$_);\n"
    "}\n");
}

void ImmutableEnumFieldLiteGenerator::
GenerateEqualsCode(io::Printer* printer) const {
  printer->Print(variables_,
    "result = result && $name$_ == other.$name$_;\n");
}

void ImmutableEnumFieldLiteGenerator::
GenerateHashCode(io::Printer* printer) const {
  printer->Print(variables_,
    "hash = (37 * hash) + $constant_name$;\n"
    "hash = (53 * hash) + $name$_;\n");
}

string ImmutableEnumFieldLiteGenerator::GetBoxedType() const {
  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}

// ===================================================================

ImmutableEnumOneofFieldLiteGenerator::
ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
                                 int messageBitIndex,
                                 int builderBitIndex,
                                 Context* context)
    : ImmutableEnumFieldLiteGenerator(
          descriptor, messageBitIndex, builderBitIndex, context) {
  const OneofGeneratorInfo* info =
      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
  SetCommonOneofVariables(descriptor, info, &variables_);
}

ImmutableEnumOneofFieldLiteGenerator::
~ImmutableEnumOneofFieldLiteGenerator() {}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateMembers(io::Printer* printer) const {
  PrintExtraFieldInfo(variables_, printer);
  if (SupportFieldPresence(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
      "  return $has_oneof_case_message$;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
      "  if ($has_oneof_case_message$) {\n"
      "    return (java.lang.Integer) $oneof_name$_;\n"
      "  }\n"
      "  return $default_number$;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
    "  if ($has_oneof_case_message$) {\n"
    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
    "    return result == null ? $unknown$ : result;\n"
    "  }\n"
    "  return $default$;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);

  // Generate private setters for the builder to proxy into.
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "private void set$capitalized_name$Value(int value) {\n"
      "  $set_oneof_case_message$;\n"
      "  $oneof_name$_ = value;\n"
      "}\n");
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void set$capitalized_name$($type$ value) {\n"
    "  if (value == null) {\n"
    "    throw new NullPointerException();\n"
    "  }\n"
    "  $set_oneof_case_message$;\n"
    "  $oneof_name$_ = value.getNumber();\n"
    "}\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void clear$capitalized_name$() {\n"
    "  if ($has_oneof_case_message$) {\n"
    "    $clear_oneof_case_message$;\n"
    "    $oneof_name$_ = null;\n"
    "  }\n"
    "}\n");
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
  if (SupportFieldPresence(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
      "  return instance.has$capitalized_name$();\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
      "  return instance.get$capitalized_name$Value();\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public Builder "
      "${$set$capitalized_name$Value$}$(int value) {\n"
      "  copyOnWrite();\n"
      "  instance.set$capitalized_name$Value(value);\n"
      "  return this;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
    "  return instance.get$capitalized_name$();\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$set$capitalized_name$$}$($type$ value) {\n"
    "  copyOnWrite();\n"
    "  instance.set$capitalized_name$(value);\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
    "  copyOnWrite();\n"
    "  instance.clear$capitalized_name$();\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateVisitCode(io::Printer* printer) const {
  printer->Print(variables_,
    "$oneof_name$_ = visitor.visitOneofInt(\n"
    "   $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n");
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateParsingCode(io::Printer* printer) const {
  if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "int rawValue = input.readEnum();\n"
      "$set_oneof_case_message$;\n"
      "$oneof_name$_ = rawValue;\n");
  } else {
    printer->Print(variables_,
      "int rawValue = input.readEnum();\n"
      "$type$ value = $type$.forNumber(rawValue);\n"
      "if (value == null) {\n"
      "  super.mergeVarintField($number$, rawValue);\n"
      "} else {\n"
      "  $set_oneof_case_message$;\n"
      "  $oneof_name$_ = rawValue;\n"
      "}\n");
  }
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateSerializationCode(io::Printer* printer) const {
  printer->Print(variables_,
    "if ($has_oneof_case_message$) {\n"
    "  output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n"
    "}\n");
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
  printer->Print(variables_,
    "if ($has_oneof_case_message$) {\n"
    "  size += com.google.protobuf.CodedOutputStream\n"
    "    .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n"
    "}\n");
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateEqualsCode(io::Printer* printer) const {
  if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "result = result && get$capitalized_name$Value()\n"
      "    == other.get$capitalized_name$Value();\n");
  } else {
    printer->Print(variables_,
      "result = result && get$capitalized_name$()\n"
      "    .equals(other.get$capitalized_name$());\n");
  }
}

void ImmutableEnumOneofFieldLiteGenerator::
GenerateHashCode(io::Printer* printer) const {
  if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "hash = (37 * hash) + $constant_name$;\n"
      "hash = (53 * hash) + get$capitalized_name$Value();\n");
  } else {
    printer->Print(variables_,
      "hash = (37 * hash) + $constant_name$;\n"
      "hash = (53 * hash) + get$capitalized_name$().getNumber();\n");
  }
}

// ===================================================================

RepeatedImmutableEnumFieldLiteGenerator::
RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
                                    int messageBitIndex,
                                    int builderBitIndex,
                                    Context* context)
  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
    builderBitIndex_(builderBitIndex), context_(context),
    name_resolver_(context->GetNameResolver()) {
  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
                   context->GetFieldGeneratorInfo(descriptor),
                   name_resolver_, &variables_);
}

RepeatedImmutableEnumFieldLiteGenerator::
~RepeatedImmutableEnumFieldLiteGenerator() {}

int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
  return 0;
}

int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
  return 0;
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$int get$capitalized_name$Count();\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$$type$ get$capitalized_name$(int index);\n");
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$java.util.List<java.lang.Integer>\n"
      "get$capitalized_name$ValueList();\n");
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$int get$capitalized_name$Value(int index);\n");
  }
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateMembers(io::Printer* printer) const {
  printer->Print(variables_,
    "private com.google.protobuf.Internal.IntList $name$_;\n"
    "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
    "    java.lang.Integer, $type$> $name$_converter_ =\n"
    "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
    "            java.lang.Integer, $type$>() {\n"
    "          public $type$ convert(java.lang.Integer from) {\n"
    "            $type$ result = $type$.forNumber(from);\n"
    "            return result == null ? $unknown$ : result;\n"
    "          }\n"
    "        };\n");
  PrintExtraFieldInfo(variables_, printer);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public java.util.List<$type$> "
    "${$get$capitalized_name$List$}$() {\n"
    "  return new com.google.protobuf.Internal.ListAdapter<\n"
    "      java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
    "  return $name$_.size();\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
    "  return $name$_converter_.convert($name$_.getInt(index));\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public java.util.List<java.lang.Integer>\n"
      "${$get$capitalized_name$ValueList$}$() {\n"
      "  return $name$_;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public int ${$get$capitalized_name$Value$}$(int index) {\n"
      "  return $name$_.getInt(index);\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }

  if (descriptor_->is_packed() &&
      context_->HasGeneratedMethods(descriptor_->containing_type())) {
    printer->Print(variables_,
      "private int $name$MemoizedSerializedSize;\n");
  }

  // Generate private setters for the builder to proxy into.
  printer->Print(variables_,
    "private void ensure$capitalized_name$IsMutable() {\n"
    "  if (!$is_mutable$) {\n"
    "    $name$_ =\n"
    "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
    "  }\n"
    "}\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void set$capitalized_name$(\n"
    "    int index, $type$ value) {\n"
    "  if (value == null) {\n"
    "    throw new NullPointerException();\n"
    "  }\n"
    "  ensure$capitalized_name$IsMutable();\n"
    "  $name$_.setInt(index, value.getNumber());\n"
    "}\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void add$capitalized_name$($type$ value) {\n"
    "  if (value == null) {\n"
    "    throw new NullPointerException();\n"
    "  }\n"
    "  ensure$capitalized_name$IsMutable();\n"
    "  $name$_.addInt(value.getNumber());\n"
    "}\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void addAll$capitalized_name$(\n"
    "    java.lang.Iterable<? extends $type$> values) {\n"
    "  ensure$capitalized_name$IsMutable();\n"
    "  for ($type$ value : values) {\n"
    "    $name$_.addInt(value.getNumber());\n"
    "  }\n"
    "}\n");
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "private void clear$capitalized_name$() {\n"
    "  $name$_ = emptyIntList();\n"
    "}\n");

  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "private void set$capitalized_name$Value(\n"
      "    int index, int value) {\n"
      "  ensure$capitalized_name$IsMutable();\n"
      "  $name$_.setInt(index, value);\n"
      "}\n");
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "private void add$capitalized_name$Value(int value) {\n"
      "  ensure$capitalized_name$IsMutable();\n"
      "  $name$_.addInt(value);\n"
      "}\n");
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "private void addAll$capitalized_name$Value(\n"
      "    java.lang.Iterable<java.lang.Integer> values) {\n"
      "  ensure$capitalized_name$IsMutable();\n"
      "  for (int value : values) {\n"
      "    $name$_.addInt(value);\n"
      "  }\n"
      "}\n");
  }
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public java.util.List<$type$> "
    "${$get$capitalized_name$List$}$() {\n"
    "  return instance.get$capitalized_name$List();\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
    "  return instance.get$capitalized_name$Count();\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
    "  return instance.get$capitalized_name$(index);\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
    "    int index, $type$ value) {\n"
    "  copyOnWrite();\n"
    "  instance.set$capitalized_name$(index, value);\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$add$capitalized_name$$}$($type$ value) {\n"
    "  copyOnWrite();\n"
    "  instance.add$capitalized_name$(value);\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n"
    "    java.lang.Iterable<? extends $type$> values) {\n"
    "  copyOnWrite();\n"
    "  instance.addAll$capitalized_name$(values);"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);
  WriteFieldDocComment(printer, descriptor_);
  printer->Print(variables_,
    "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
    "  copyOnWrite();\n"
    "  instance.clear$capitalized_name$();\n"
    "  return this;\n"
    "}\n");
  printer->Annotate("{", "}", descriptor_);

  if (SupportUnknownEnumValue(descriptor_->file())) {
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public java.util.List<java.lang.Integer>\n"
      "${$get$capitalized_name$ValueList$}$() {\n"
      "  return java.util.Collections.unmodifiableList(\n"
      "      instance.get$capitalized_name$ValueList());\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public int ${$get$capitalized_name$Value$}$(int index) {\n"
      "  return instance.get$capitalized_name$Value(index);\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public Builder ${$set$capitalized_name$Value$}$(\n"
      "    int index, int value) {\n"
      "  copyOnWrite();\n"
      "  instance.set$capitalized_name$Value(index, value);\n"
      "  return this;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public Builder "
      "${$add$capitalized_name$Value$}$(int value) {\n"
      "  instance.add$capitalized_name$Value(value);\n"
      "  return this;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
    WriteFieldDocComment(printer, descriptor_);
    printer->Print(variables_,
      "$deprecation$public Builder ${$addAll$capitalized_name$Value$}$(\n"
      "    java.lang.Iterable<java.lang.Integer> values) {\n"
      "  copyOnWrite();\n"
      "  instance.addAll$capitalized_name$Value(values);\n"
      "  return this;\n"
      "}\n");
    printer->Annotate("{", "}", descriptor_);
  }
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
  // noop for enums
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateInitializationCode(io::Printer* printer) const {
  printer->Print(variables_, "$name$_ = emptyIntList();\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateVisitCode(io::Printer* printer) const {
  printer->Print(variables_,
    "$name$_= visitor.visitIntList($name$_, other.$name$_);\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
  printer->Print(variables_,
    "$name$_.makeImmutable();\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateParsingCode(io::Printer* printer) const {
  // Read and store the enum
  printer->Print(variables_,
    "if (!$is_mutable$) {\n"
    "  $name$_ =\n"
    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
    "}\n");

  if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "$name$_.addInt(input.readEnum());\n");
  } else {
    printer->Print(variables_,
      "int rawValue = input.readEnum();\n"
      "$type$ value = $type$.forNumber(rawValue);\n"
      "if (value == null) {\n"
      // We store the unknown value in unknown fields.
      "  super.mergeVarintField($number$, rawValue);\n"
      "} else {\n"
      "  $name$_.addInt(rawValue);\n"
      "}\n");
  }
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateParsingCodeFromPacked(io::Printer* printer) const {
  printer->Print(variables_,
    "if (!$is_mutable$) {\n"
    "  $name$_ =\n"
    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
    "}\n");

  printer->Print(variables_,
    "int length = input.readRawVarint32();\n"
    "int oldLimit = input.pushLimit(length);\n"
    "while(input.getBytesUntilLimit() > 0) {\n");
  printer->Indent();

  // Read and store the enum
  if (SupportUnknownEnumValue(descriptor_->file())) {
    printer->Print(variables_,
      "$name$_.addInt(input.readEnum());\n");
  } else {
    printer->Print(variables_,
      "int rawValue = input.readEnum();\n"
      "$type$ value = $type$.forNumber(rawValue);\n"
      "if (value == null) {\n"
      // We store the unknown value in unknown fields.
      "  super.mergeVarintField($number$, rawValue);\n"
      "} else {\n"
      "  $name$_.addInt(rawValue);\n"
      "}\n");
  }

  printer->Outdent();
  printer->Print(variables_,
    "}\n"
    "input.popLimit(oldLimit);\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateParsingDoneCode(io::Printer* printer) const {
  printer->Print(variables_,
    "if ($is_mutable$) {\n"
    "  $name$_.makeImmutable();\n"
    "}\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateSerializationCode(io::Printer* printer) const {
  if (descriptor_->is_packed()) {
    printer->Print(variables_,
      "if (get$capitalized_name$List().size() > 0) {\n"
      "  output.writeUInt32NoTag($tag$);\n"
      "  output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
      "}\n"
      "for (int i = 0; i < $name$_.size(); i++) {\n"
      "  output.writeEnumNoTag($name$_.getInt(i));\n"
      "}\n");
  } else {
    printer->Print(variables_,
      "for (int i = 0; i < $name$_.size(); i++) {\n"
      "  output.writeEnum($number$, $name$_.getInt(i));\n"
      "}\n");
  }
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
  printer->Print(variables_,
    "{\n"
    "  int dataSize = 0;\n");
  printer->Indent();

  printer->Print(variables_,
    "for (int i = 0; i < $name$_.size(); i++) {\n"
    "  dataSize += com.google.protobuf.CodedOutputStream\n"
    "    .computeEnumSizeNoTag($name$_.getInt(i));\n"
    "}\n");
  printer->Print(
    "size += dataSize;\n");
  if (descriptor_->is_packed()) {
    printer->Print(variables_,
      "if (!get$capitalized_name$List().isEmpty()) {"
      "  size += $tag_size$;\n"
      "  size += com.google.protobuf.CodedOutputStream\n"
      "    .computeUInt32SizeNoTag(dataSize);\n"
      "}");
  } else {
    printer->Print(variables_,
      "size += $tag_size$ * $name$_.size();\n");
  }

  // cache the data size for packed fields.
  if (descriptor_->is_packed()) {
    printer->Print(variables_,
      "$name$MemoizedSerializedSize = dataSize;\n");
  }

  printer->Outdent();
  printer->Print("}\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateEqualsCode(io::Printer* printer) const {
  printer->Print(variables_,
    "result = result && $name$_.equals(other.$name$_);\n");
}

void RepeatedImmutableEnumFieldLiteGenerator::
GenerateHashCode(io::Printer* printer) const {
  printer->Print(variables_,
    "if (get$capitalized_name$Count() > 0) {\n"
    "  hash = (37 * hash) + $constant_name$;\n"
    "  hash = (53 * hash) + $name$_.hashCode();\n"
    "}\n");
}

string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}

}  // namespace java
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

#include <google/protobuf/compiler/java/java_service.h>

#include <google/protobuf/compiler/java/java_context.h>
#include <google/protobuf/compiler/java/java_doc_comment.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
  : descriptor_(descriptor) {}

ServiceGenerator::~ServiceGenerator() {}

// ===================================================================
ImmutableServiceGenerator::ImmutableServiceGenerator(
    const ServiceDescriptor* descriptor, Context* context)
    : ServiceGenerator(descriptor), context_(context),
    name_resolver_(context->GetNameResolver()) {}

ImmutableServiceGenerator::~ImmutableServiceGenerator() {}

void ImmutableServiceGenerator::Generate(io::Printer* printer) {
  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
  WriteServiceDocComment(printer, descriptor_);
  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
                                /* immutable = */ true);
  printer->Print(
    "public $static$ abstract class $classname$\n"
    "    implements com.google.protobuf.Service {\n",
    "static", is_own_file ? "" : "static",
    "classname", descriptor_->name());
  printer->Indent();

  printer->Print(
    "protected $classname$() {}\n\n",
    "classname", descriptor_->name());

  GenerateInterface(printer);

  GenerateNewReflectiveServiceMethod(printer);
  GenerateNewReflectiveBlockingServiceMethod(printer);

  GenerateAbstractMethods(printer);

  // Generate getDescriptor() and getDescriptorForType().
  printer->Print(
    "public static final\n"
    "    com.google.protobuf.Descriptors.ServiceDescriptor\n"
    "    getDescriptor() {\n"
    "  return $file$.getDescriptor().getServices().get($index$);\n"
    "}\n",
    "file", name_resolver_->GetImmutableClassName(descriptor_->file()),
    "index", SimpleItoa(descriptor_->index()));
  GenerateGetDescriptorForType(printer);

  // Generate more stuff.
  GenerateCallMethod(printer);
  GenerateGetPrototype(REQUEST, printer);
  GenerateGetPrototype(RESPONSE, printer);
  GenerateStub(printer);
  GenerateBlockingStub(printer);

  // Add an insertion point.
  printer->Print(
    "\n"
    "// @@protoc_insertion_point(class_scope:$full_name$)\n",
    "full_name", descriptor_->full_name());

  printer->Outdent();
  printer->Print("}\n\n");
}

void ImmutableServiceGenerator::GenerateGetDescriptorForType(
    io::Printer* printer) {
  printer->Print(
    "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
    "    getDescriptorForType() {\n"
    "  return getDescriptor();\n"
    "}\n");
}

void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) {
  printer->Print("public interface Interface {\n");
  printer->Indent();
  GenerateAbstractMethods(printer);
  printer->Outdent();
  printer->Print("}\n\n");
}

void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod(
    io::Printer* printer) {
  printer->Print(
    "public static com.google.protobuf.Service newReflectiveService(\n"
    "    final Interface impl) {\n"
    "  return new $classname$() {\n",
    "classname", descriptor_->name());
  printer->Indent();
  printer->Indent();

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    printer->Print("@java.lang.Override\n");
    GenerateMethodSignature(printer, method, IS_CONCRETE);
    printer->Print(
      " {\n"
      "  impl.$method$(controller, request, done);\n"
      "}\n\n",
      "method", UnderscoresToCamelCase(method));
  }

  printer->Outdent();
  printer->Print("};\n");
  printer->Outdent();
  printer->Print("}\n\n");
}

void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
    io::Printer* printer) {
  printer->Print(
    "public static com.google.protobuf.BlockingService\n"
    "    newReflectiveBlockingService(final BlockingInterface impl) {\n"
    "  return new com.google.protobuf.BlockingService() {\n");
  printer->Indent();
  printer->Indent();

  GenerateGetDescriptorForType(printer);

  GenerateCallBlockingMethod(printer);
  GenerateGetPrototype(REQUEST, printer);
  GenerateGetPrototype(RESPONSE, printer);

  printer->Outdent();
  printer->Print("};\n");
  printer->Outdent();
  printer->Print("}\n\n");
}

void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    WriteMethodDocComment(printer, method);
    GenerateMethodSignature(printer, method, IS_ABSTRACT);
    printer->Print(";\n\n");
  }
}

string ImmutableServiceGenerator::GetOutput(const MethodDescriptor* method) {
  return name_resolver_->GetImmutableClassName(method->output_type());
}

void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) {
  printer->Print(
    "\n"
    "public final void callMethod(\n"
    "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
    "    com.google.protobuf.RpcController controller,\n"
    "    com.google.protobuf.Message request,\n"
    "    com.google.protobuf.RpcCallback<\n"
    "      com.google.protobuf.Message> done) {\n"
    "  if (method.getService() != getDescriptor()) {\n"
    "    throw new java.lang.IllegalArgumentException(\n"
    "      \"Service.callMethod() given method descriptor for wrong \" +\n"
    "      \"service type.\");\n"
    "  }\n"
    "  switch(method.getIndex()) {\n");
  printer->Indent();
  printer->Indent();

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    std::map<string, string> vars;
    vars["index"] = SimpleItoa(i);
    vars["method"] = UnderscoresToCamelCase(method);
    vars["input"] = name_resolver_->GetImmutableClassName(
        method->input_type());
    vars["output"] = GetOutput(method);
    printer->Print(vars,
      "case $index$:\n"
      "  this.$method$(controller, ($input$)request,\n"
      "    com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n"
      "      done));\n"
      "  return;\n");
  }

  printer->Print(
    "default:\n"
    "  throw new java.lang.AssertionError(\"Can't get here.\");\n");

  printer->Outdent();
  printer->Outdent();

  printer->Print(
    "  }\n"
    "}\n"
    "\n");
}

void ImmutableServiceGenerator::GenerateCallBlockingMethod(
    io::Printer* printer) {
  printer->Print(
    "\n"
    "public final com.google.protobuf.Message callBlockingMethod(\n"
    "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
    "    com.google.protobuf.RpcController controller,\n"
    "    com.google.protobuf.Message request)\n"
    "    throws com.google.protobuf.ServiceException {\n"
    "  if (method.getService() != getDescriptor()) {\n"
    "    throw new java.lang.IllegalArgumentException(\n"
    "      \"Service.callBlockingMethod() given method descriptor for \" +\n"
    "      \"wrong service type.\");\n"
    "  }\n"
    "  switch(method.getIndex()) {\n");
  printer->Indent();
  printer->Indent();

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    std::map<string, string> vars;
    vars["index"] = SimpleItoa(i);
    vars["method"] = UnderscoresToCamelCase(method);
    vars["input"] = name_resolver_->GetImmutableClassName(
        method->input_type());
    vars["output"] = GetOutput(method);
    printer->Print(vars,
      "case $index$:\n"
      "  return impl.$method$(controller, ($input$)request);\n");
  }

  printer->Print(
    "default:\n"
    "  throw new java.lang.AssertionError(\"Can't get here.\");\n");

  printer->Outdent();
  printer->Outdent();

  printer->Print(
    "  }\n"
    "}\n"
    "\n");
}

void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
                                            io::Printer* printer) {
  /*
   * TODO(cpovirk): The exception message says "Service.foo" when it may be
   * "BlockingService.foo."  Consider fixing.
   */
  printer->Print(
    "public final com.google.protobuf.Message\n"
    "    get$request_or_response$Prototype(\n"
    "    com.google.protobuf.Descriptors.MethodDescriptor method) {\n"
    "  if (method.getService() != getDescriptor()) {\n"
    "    throw new java.lang.IllegalArgumentException(\n"
    "      \"Service.get$request_or_response$Prototype() given method \" +\n"
    "      \"descriptor for wrong service type.\");\n"
    "  }\n"
    "  switch(method.getIndex()) {\n",
    "request_or_response", (which == REQUEST) ? "Request" : "Response");
  printer->Indent();
  printer->Indent();

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    std::map<string, string> vars;
    vars["index"] = SimpleItoa(i);
    vars["type"] = name_resolver_->GetImmutableClassName(
      (which == REQUEST) ? method->input_type() : method->output_type());
    printer->Print(vars,
      "case $index$:\n"
      "  return $type$.getDefaultInstance();\n");
  }

  printer->Print(
    "default:\n"
    "  throw new java.lang.AssertionError(\"Can't get here.\");\n");

  printer->Outdent();
  printer->Outdent();

  printer->Print(
    "  }\n"
    "}\n"
    "\n");
}

void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) {
  printer->Print(
    "public static Stub newStub(\n"
    "    com.google.protobuf.RpcChannel channel) {\n"
    "  return new Stub(channel);\n"
    "}\n"
    "\n"
    "public static final class Stub extends $classname$ implements Interface {"
    "\n",
    "classname", name_resolver_->GetImmutableClassName(descriptor_));
  printer->Indent();

  printer->Print(
    "private Stub(com.google.protobuf.RpcChannel channel) {\n"
    "  this.channel = channel;\n"
    "}\n"
    "\n"
    "private final com.google.protobuf.RpcChannel channel;\n"
    "\n"
    "public com.google.protobuf.RpcChannel getChannel() {\n"
    "  return channel;\n"
    "}\n");

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    printer->Print("\n");
    GenerateMethodSignature(printer, method, IS_CONCRETE);
    printer->Print(" {\n");
    printer->Indent();

    std::map<string, string> vars;
    vars["index"] = SimpleItoa(i);
    vars["output"] = GetOutput(method);
    printer->Print(vars,
      "channel.callMethod(\n"
      "  getDescriptor().getMethods().get($index$),\n"
      "  controller,\n"
      "  request,\n"
      "  $output$.getDefaultInstance(),\n"
      "  com.google.protobuf.RpcUtil.generalizeCallback(\n"
      "    done,\n"
      "    $output$.class,\n"
      "    $output$.getDefaultInstance()));\n");

    printer->Outdent();
    printer->Print("}\n");
  }

  printer->Outdent();
  printer->Print(
    "}\n"
    "\n");
}

void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
  printer->Print(
    "public static BlockingInterface newBlockingStub(\n"
    "    com.google.protobuf.BlockingRpcChannel channel) {\n"
    "  return new BlockingStub(channel);\n"
    "}\n"
    "\n");

  printer->Print(
    "public interface BlockingInterface {");
  printer->Indent();

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    GenerateBlockingMethodSignature(printer, method);
    printer->Print(";\n");
  }

  printer->Outdent();
  printer->Print(
    "}\n"
    "\n");

  printer->Print(
    "private static final class BlockingStub implements BlockingInterface {\n");
  printer->Indent();

  printer->Print(
    "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
    "  this.channel = channel;\n"
    "}\n"
    "\n"
    "private final com.google.protobuf.BlockingRpcChannel channel;\n");

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    GenerateBlockingMethodSignature(printer, method);
    printer->Print(" {\n");
    printer->Indent();

    std::map<string, string> vars;
    vars["index"] = SimpleItoa(i);
    vars["output"] = GetOutput(method);
    printer->Print(vars,
      "return ($output$) channel.callBlockingMethod(\n"
      "  getDescriptor().getMethods().get($index$),\n"
      "  controller,\n"
      "  request,\n"
      "  $output$.getDefaultInstance());\n");

    printer->Outdent();
    printer->Print(
      "}\n"
      "\n");
  }

  printer->Outdent();
  printer->Print("}\n");
}

void ImmutableServiceGenerator::GenerateMethodSignature(io::Printer* printer,
                                               const MethodDescriptor* method,
                                               IsAbstract is_abstract) {
  std::map<string, string> vars;
  vars["name"] = UnderscoresToCamelCase(method);
  vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
  vars["output"] = GetOutput(method);
  vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
  printer->Print(vars,
    "public $abstract$ void $name$(\n"
    "    com.google.protobuf.RpcController controller,\n"
    "    $input$ request,\n"
    "    com.google.protobuf.RpcCallback<$output$> done)");
}

void ImmutableServiceGenerator::GenerateBlockingMethodSignature(
    io::Printer* printer,
    const MethodDescriptor* method) {
  std::map<string, string> vars;
  vars["method"] = UnderscoresToCamelCase(method);
  vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
  vars["output"] = GetOutput(method);
  printer->Print(vars,
    "\n"
    "public $output$ $method$(\n"
    "    com.google.protobuf.RpcController controller,\n"
    "    $input$ request)\n"
    "    throws com.google.protobuf.ServiceException");
}

}  // namespace java
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__

#include <string>

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

// Generator options
struct Options {
  Options()
      : generate_immutable_code(false),
        generate_mutable_code(false),
        generate_shared_code(false),
        enforce_lite(false),
        annotate_code(false) {
  }

  bool generate_immutable_code;
  bool generate_mutable_code;
  bool generate_shared_code;
  // When set, the protoc will generate the current files and all the transitive
  // dependencies as lite runtime.
  bool enforce_lite;
  // If true, we should build .meta files and emit @Generated annotations into
  // generated code.
  bool annotate_code;
  // Name of a file where we will write a list of generated .meta file names,
  // one per line.
  std::string annotation_list_file;
  // Name of a file where we will write a list of generated file names, one
  // per line.
  std::string output_list_file;
};

}  // namespace java
}  // namespace compiler
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__