Home | History | Annotate | Download | only in java
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Author: kenton (at) google.com (Kenton Varda)
     32 //  Based on original Protocol Buffers design by
     33 //  Sanjay Ghemawat, Jeff Dean, and others.
     34 
     35 #include <map>
     36 #include <string>
     37 
     38 #include <google/protobuf/compiler/java/java_enum.h>
     39 #include <google/protobuf/compiler/java/java_helpers.h>
     40 #include <google/protobuf/io/printer.h>
     41 #include <google/protobuf/descriptor.pb.h>
     42 #include <google/protobuf/stubs/strutil.h>
     43 
     44 namespace google {
     45 namespace protobuf {
     46 namespace compiler {
     47 namespace java {
     48 
     49 EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
     50   : descriptor_(descriptor) {
     51   for (int i = 0; i < descriptor_->value_count(); i++) {
     52     const EnumValueDescriptor* value = descriptor_->value(i);
     53     const EnumValueDescriptor* canonical_value =
     54       descriptor_->FindValueByNumber(value->number());
     55 
     56     if (value == canonical_value) {
     57       canonical_values_.push_back(value);
     58     } else {
     59       Alias alias;
     60       alias.value = value;
     61       alias.canonical_value = canonical_value;
     62       aliases_.push_back(alias);
     63     }
     64   }
     65 }
     66 
     67 EnumGenerator::~EnumGenerator() {}
     68 
     69 void EnumGenerator::Generate(io::Printer* printer) {
     70   if (HasDescriptorMethods(descriptor_)) {
     71     printer->Print(
     72       "public enum $classname$\n"
     73       "    implements com.google.protobuf.ProtocolMessageEnum {\n",
     74       "classname", descriptor_->name());
     75   } else {
     76     printer->Print(
     77       "public enum $classname$\n"
     78       "    implements com.google.protobuf.Internal.EnumLite {\n",
     79       "classname", descriptor_->name());
     80   }
     81   printer->Indent();
     82 
     83   for (int i = 0; i < canonical_values_.size(); i++) {
     84     map<string, string> vars;
     85     vars["name"] = canonical_values_[i]->name();
     86     vars["index"] = SimpleItoa(canonical_values_[i]->index());
     87     vars["number"] = SimpleItoa(canonical_values_[i]->number());
     88     printer->Print(vars,
     89       "$name$($index$, $number$),\n");
     90   }
     91 
     92   printer->Print(
     93     ";\n"
     94     "\n");
     95 
     96   // -----------------------------------------------------------------
     97 
     98   for (int i = 0; i < aliases_.size(); i++) {
     99     map<string, string> vars;
    100     vars["classname"] = descriptor_->name();
    101     vars["name"] = aliases_[i].value->name();
    102     vars["canonical_name"] = aliases_[i].canonical_value->name();
    103     printer->Print(vars,
    104       "public static final $classname$ $name$ = $canonical_name$;\n");
    105   }
    106 
    107   // -----------------------------------------------------------------
    108 
    109   printer->Print(
    110     "\n"
    111     "public final int getNumber() { return value; }\n"
    112     "\n"
    113     "public static $classname$ valueOf(int value) {\n"
    114     "  switch (value) {\n",
    115     "classname", descriptor_->name());
    116   printer->Indent();
    117   printer->Indent();
    118 
    119   for (int i = 0; i < canonical_values_.size(); i++) {
    120     printer->Print(
    121       "case $number$: return $name$;\n",
    122       "name", canonical_values_[i]->name(),
    123       "number", SimpleItoa(canonical_values_[i]->number()));
    124   }
    125 
    126   printer->Outdent();
    127   printer->Outdent();
    128   printer->Print(
    129     "    default: return null;\n"
    130     "  }\n"
    131     "}\n"
    132     "\n"
    133     "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
    134     "    internalGetValueMap() {\n"
    135     "  return internalValueMap;\n"
    136     "}\n"
    137     "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
    138     "    internalValueMap =\n"
    139     "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
    140     "        public $classname$ findValueByNumber(int number) {\n"
    141     "          return $classname$.valueOf(number)\n;"
    142     "        }\n"
    143     "      };\n"
    144     "\n",
    145     "classname", descriptor_->name());
    146 
    147   // -----------------------------------------------------------------
    148   // Reflection
    149 
    150   if (HasDescriptorMethods(descriptor_)) {
    151     printer->Print(
    152       "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
    153       "    getValueDescriptor() {\n"
    154       "  return getDescriptor().getValues().get(index);\n"
    155       "}\n"
    156       "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
    157       "    getDescriptorForType() {\n"
    158       "  return getDescriptor();\n"
    159       "}\n"
    160       "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
    161       "    getDescriptor() {\n");
    162 
    163     // TODO(kenton):  Cache statically?  Note that we can't access descriptors
    164     //   at module init time because it wouldn't work with descriptor.proto, but
    165     //   we can cache the value the first time getDescriptor() is called.
    166     if (descriptor_->containing_type() == NULL) {
    167       printer->Print(
    168         "  return $file$.getDescriptor().getEnumTypes().get($index$);\n",
    169         "file", ClassName(descriptor_->file()),
    170         "index", SimpleItoa(descriptor_->index()));
    171     } else {
    172       printer->Print(
    173         "  return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
    174         "parent", ClassName(descriptor_->containing_type()),
    175         "index", SimpleItoa(descriptor_->index()));
    176     }
    177 
    178     printer->Print(
    179       "}\n"
    180       "\n"
    181       "private static final $classname$[] VALUES = {\n"
    182       "  ",
    183       "classname", descriptor_->name());
    184 
    185     for (int i = 0; i < descriptor_->value_count(); i++) {
    186       printer->Print("$name$, ",
    187         "name", descriptor_->value(i)->name());
    188     }
    189 
    190     printer->Print(
    191       "\n"
    192       "};\n"
    193       "public static $classname$ valueOf(\n"
    194       "    com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
    195       "  if (desc.getType() != getDescriptor()) {\n"
    196       "    throw new java.lang.IllegalArgumentException(\n"
    197       "      \"EnumValueDescriptor is not for this type.\");\n"
    198       "  }\n"
    199       "  return VALUES[desc.getIndex()];\n"
    200       "}\n",
    201       "classname", descriptor_->name());
    202   }
    203 
    204   // -----------------------------------------------------------------
    205 
    206   printer->Print(
    207     "private final int index;\n"
    208     "private final int value;\n"
    209     "private $classname$(int index, int value) {\n"
    210     "  this.index = index;\n"
    211     "  this.value = value;\n"
    212     "}\n",
    213     "classname", descriptor_->name());
    214 
    215   if (HasDescriptorMethods(descriptor_)) {
    216     // Force the static initialization code for the file to run, since it may
    217     // initialize static variables declared in this class.
    218     printer->Print(
    219       "\n"
    220       "static {\n"
    221       "  $file$.getDescriptor();\n"
    222       "}\n",
    223       "file", ClassName(descriptor_->file()));
    224   }
    225 
    226   printer->Print(
    227     "\n"
    228     "// @@protoc_insertion_point(enum_scope:$full_name$)\n",
    229     "full_name", descriptor_->full_name());
    230 
    231   printer->Outdent();
    232   printer->Print("}\n\n");
    233 }
    234 
    235 }  // namespace java
    236 }  // namespace compiler
    237 }  // namespace protobuf
    238 }  // namespace google
    239