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@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_doc_comment.h>
40#include <google/protobuf/compiler/java/java_helpers.h>
41#include <google/protobuf/io/printer.h>
42#include <google/protobuf/descriptor.pb.h>
43#include <google/protobuf/stubs/strutil.h>
44
45namespace google {
46namespace protobuf {
47namespace compiler {
48namespace java {
49
50EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
51  : descriptor_(descriptor) {
52  for (int i = 0; i < descriptor_->value_count(); i++) {
53    const EnumValueDescriptor* value = descriptor_->value(i);
54    const EnumValueDescriptor* canonical_value =
55      descriptor_->FindValueByNumber(value->number());
56
57    if (value == canonical_value) {
58      canonical_values_.push_back(value);
59    } else {
60      Alias alias;
61      alias.value = value;
62      alias.canonical_value = canonical_value;
63      aliases_.push_back(alias);
64    }
65  }
66}
67
68EnumGenerator::~EnumGenerator() {}
69
70void EnumGenerator::Generate(io::Printer* printer) {
71  WriteEnumDocComment(printer, descriptor_);
72  if (HasDescriptorMethods(descriptor_)) {
73    printer->Print(
74      "public enum $classname$\n"
75      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
76      "classname", descriptor_->name());
77  } else {
78    printer->Print(
79      "public enum $classname$\n"
80      "    implements com.google.protobuf.Internal.EnumLite {\n",
81      "classname", descriptor_->name());
82  }
83  printer->Indent();
84
85  for (int i = 0; i < canonical_values_.size(); i++) {
86    map<string, string> vars;
87    vars["name"] = canonical_values_[i]->name();
88    vars["index"] = SimpleItoa(canonical_values_[i]->index());
89    vars["number"] = SimpleItoa(canonical_values_[i]->number());
90    WriteEnumValueDocComment(printer, canonical_values_[i]);
91    printer->Print(vars,
92      "$name$($index$, $number$),\n");
93  }
94
95  printer->Print(
96    ";\n"
97    "\n");
98
99  // -----------------------------------------------------------------
100
101  for (int i = 0; i < aliases_.size(); i++) {
102    map<string, string> vars;
103    vars["classname"] = descriptor_->name();
104    vars["name"] = aliases_[i].value->name();
105    vars["canonical_name"] = aliases_[i].canonical_value->name();
106    WriteEnumValueDocComment(printer, aliases_[i].value);
107    printer->Print(vars,
108      "public static final $classname$ $name$ = $canonical_name$;\n");
109  }
110
111  for (int i = 0; i < descriptor_->value_count(); i++) {
112    map<string, string> vars;
113    vars["name"] = descriptor_->value(i)->name();
114    vars["number"] = SimpleItoa(descriptor_->value(i)->number());
115    WriteEnumValueDocComment(printer, descriptor_->value(i));
116    printer->Print(vars,
117      "public static final int $name$_VALUE = $number$;\n");
118  }
119  printer->Print("\n");
120
121  // -----------------------------------------------------------------
122
123  printer->Print(
124    "\n"
125    "public final int getNumber() { return value; }\n"
126    "\n"
127    "public static $classname$ valueOf(int value) {\n"
128    "  switch (value) {\n",
129    "classname", descriptor_->name());
130  printer->Indent();
131  printer->Indent();
132
133  for (int i = 0; i < canonical_values_.size(); i++) {
134    printer->Print(
135      "case $number$: return $name$;\n",
136      "name", canonical_values_[i]->name(),
137      "number", SimpleItoa(canonical_values_[i]->number()));
138  }
139
140  printer->Outdent();
141  printer->Outdent();
142  printer->Print(
143    "    default: return null;\n"
144    "  }\n"
145    "}\n"
146    "\n"
147    "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
148    "    internalGetValueMap() {\n"
149    "  return internalValueMap;\n"
150    "}\n"
151    "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
152    "    internalValueMap =\n"
153    "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
154    "        public $classname$ findValueByNumber(int number) {\n"
155    "          return $classname$.valueOf(number);\n"
156    "        }\n"
157    "      };\n"
158    "\n",
159    "classname", descriptor_->name());
160
161  // -----------------------------------------------------------------
162  // Reflection
163
164  if (HasDescriptorMethods(descriptor_)) {
165    printer->Print(
166      "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
167      "    getValueDescriptor() {\n"
168      "  return getDescriptor().getValues().get(index);\n"
169      "}\n"
170      "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
171      "    getDescriptorForType() {\n"
172      "  return getDescriptor();\n"
173      "}\n"
174      "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
175      "    getDescriptor() {\n");
176
177    // TODO(kenton):  Cache statically?  Note that we can't access descriptors
178    //   at module init time because it wouldn't work with descriptor.proto, but
179    //   we can cache the value the first time getDescriptor() is called.
180    if (descriptor_->containing_type() == NULL) {
181      printer->Print(
182        "  return $file$.getDescriptor().getEnumTypes().get($index$);\n",
183        "file", ClassName(descriptor_->file()),
184        "index", SimpleItoa(descriptor_->index()));
185    } else {
186      printer->Print(
187        "  return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
188        "parent", ClassName(descriptor_->containing_type()),
189        "index", SimpleItoa(descriptor_->index()));
190    }
191
192    printer->Print(
193      "}\n"
194      "\n"
195      "private static final $classname$[] VALUES = ",
196      "classname", descriptor_->name());
197
198    if (CanUseEnumValues()) {
199      // If the constants we are going to output are exactly the ones we
200      // have declared in the Java enum in the same order, then we can use
201      // the values() method that the Java compiler automatically generates
202      // for every enum.
203      printer->Print("values();\n");
204    } else {
205      printer->Print(
206        "{\n"
207        "  ");
208      for (int i = 0; i < descriptor_->value_count(); i++) {
209        printer->Print("$name$, ",
210          "name", descriptor_->value(i)->name());
211      }
212      printer->Print(
213          "\n"
214          "};\n");
215    }
216
217    printer->Print(
218      "\n"
219      "public static $classname$ valueOf(\n"
220      "    com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
221      "  if (desc.getType() != getDescriptor()) {\n"
222      "    throw new java.lang.IllegalArgumentException(\n"
223      "      \"EnumValueDescriptor is not for this type.\");\n"
224      "  }\n"
225      "  return VALUES[desc.getIndex()];\n"
226      "}\n"
227      "\n",
228      "classname", descriptor_->name());
229
230    // index is only used for reflection; lite implementation does not need it
231    printer->Print("private final int index;\n");
232  }
233
234  // -----------------------------------------------------------------
235
236  printer->Print(
237    "private final int value;\n\n"
238    "private $classname$(int index, int value) {\n",
239    "classname", descriptor_->name());
240  if (HasDescriptorMethods(descriptor_)) {
241    printer->Print("  this.index = index;\n");
242  }
243  printer->Print(
244    "  this.value = value;\n"
245    "}\n");
246
247  printer->Print(
248    "\n"
249    "// @@protoc_insertion_point(enum_scope:$full_name$)\n",
250    "full_name", descriptor_->full_name());
251
252  printer->Outdent();
253  printer->Print("}\n\n");
254}
255
256bool EnumGenerator::CanUseEnumValues() {
257  if (canonical_values_.size() != descriptor_->value_count()) {
258    return false;
259  }
260  for (int i = 0; i < descriptor_->value_count(); i++) {
261    if (descriptor_->value(i)->name() != canonical_values_[i]->name()) {
262      return false;
263    }
264  }
265  return true;
266}
267
268}  // namespace java
269}  // namespace compiler
270}  // namespace protobuf
271}  // namespace google
272