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 <limits>
     36 #include <vector>
     37 
     38 #include <google/protobuf/compiler/java/java_helpers.h>
     39 #include <google/protobuf/descriptor.pb.h>
     40 #include <google/protobuf/stubs/strutil.h>
     41 #include <google/protobuf/stubs/substitute.h>
     42 
     43 namespace google {
     44 namespace protobuf {
     45 namespace compiler {
     46 namespace java {
     47 
     48 const char kThickSeparator[] =
     49   "// ===================================================================\n";
     50 const char kThinSeparator[] =
     51   "// -------------------------------------------------------------------\n";
     52 
     53 namespace {
     54 
     55 const char* kDefaultPackage = "";
     56 
     57 const string& FieldName(const FieldDescriptor* field) {
     58   // Groups are hacky:  The name of the field is just the lower-cased name
     59   // of the group type.  In Java, though, we would like to retain the original
     60   // capitalization of the type name.
     61   if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
     62     return field->message_type()->name();
     63   } else {
     64     return field->name();
     65   }
     66 }
     67 
     68 string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
     69   string result;
     70   // Note:  I distrust ctype.h due to locales.
     71   for (int i = 0; i < input.size(); i++) {
     72     if ('a' <= input[i] && input[i] <= 'z') {
     73       if (cap_next_letter) {
     74         result += input[i] + ('A' - 'a');
     75       } else {
     76         result += input[i];
     77       }
     78       cap_next_letter = false;
     79     } else if ('A' <= input[i] && input[i] <= 'Z') {
     80       if (i == 0 && !cap_next_letter) {
     81         // Force first letter to lower-case unless explicitly told to
     82         // capitalize it.
     83         result += input[i] + ('a' - 'A');
     84       } else {
     85         // Capital letters after the first are left as-is.
     86         result += input[i];
     87       }
     88       cap_next_letter = false;
     89     } else if ('0' <= input[i] && input[i] <= '9') {
     90       result += input[i];
     91       cap_next_letter = true;
     92     } else {
     93       cap_next_letter = true;
     94     }
     95   }
     96   return result;
     97 }
     98 
     99 }  // namespace
    100 
    101 string UnderscoresToCamelCase(const FieldDescriptor* field) {
    102   return UnderscoresToCamelCaseImpl(FieldName(field), false);
    103 }
    104 
    105 string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
    106   return UnderscoresToCamelCaseImpl(FieldName(field), true);
    107 }
    108 
    109 string UnderscoresToCamelCase(const MethodDescriptor* method) {
    110   return UnderscoresToCamelCaseImpl(method->name(), false);
    111 }
    112 
    113 string StripProto(const string& filename) {
    114   if (HasSuffixString(filename, ".protodevel")) {
    115     return StripSuffixString(filename, ".protodevel");
    116   } else {
    117     return StripSuffixString(filename, ".proto");
    118   }
    119 }
    120 
    121 string FileClassName(const FileDescriptor* file) {
    122   if (file->options().has_java_outer_classname()) {
    123     return file->options().java_outer_classname();
    124   } else {
    125     string basename;
    126     string::size_type last_slash = file->name().find_last_of('/');
    127     if (last_slash == string::npos) {
    128       basename = file->name();
    129     } else {
    130       basename = file->name().substr(last_slash + 1);
    131     }
    132     return UnderscoresToCamelCaseImpl(StripProto(basename), true);
    133   }
    134 }
    135 
    136 string FileJavaPackage(const FileDescriptor* file) {
    137   if (file->options().has_java_package()) {
    138     return file->options().java_package();
    139   } else {
    140     string result = kDefaultPackage;
    141     if (!file->package().empty()) {
    142       if (!result.empty()) result += '.';
    143       result += file->package();
    144     }
    145     return result;
    146   }
    147 }
    148 
    149 string ToJavaName(const string& full_name, const FileDescriptor* file) {
    150   string result;
    151   if (file->options().java_multiple_files()) {
    152     result = FileJavaPackage(file);
    153   } else {
    154     result = ClassName(file);
    155   }
    156   if (!result.empty()) {
    157     result += '.';
    158   }
    159   if (file->package().empty()) {
    160     result += full_name;
    161   } else {
    162     // Strip the proto package from full_name since we've replaced it with
    163     // the Java package.
    164     result += full_name.substr(file->package().size() + 1);
    165   }
    166   return result;
    167 }
    168 
    169 string ClassName(const FileDescriptor* descriptor) {
    170   string result = FileJavaPackage(descriptor);
    171   if (!result.empty()) result += '.';
    172   result += FileClassName(descriptor);
    173   return result;
    174 }
    175 
    176 string FieldConstantName(const FieldDescriptor *field) {
    177   string name = field->name() + "_FIELD_NUMBER";
    178   UpperString(&name);
    179   return name;
    180 }
    181 
    182 FieldDescriptor::Type GetType(const FieldDescriptor* field) {
    183   return field->type();
    184 }
    185 
    186 JavaType GetJavaType(const FieldDescriptor* field) {
    187   switch (GetType(field)) {
    188     case FieldDescriptor::TYPE_INT32:
    189     case FieldDescriptor::TYPE_UINT32:
    190     case FieldDescriptor::TYPE_SINT32:
    191     case FieldDescriptor::TYPE_FIXED32:
    192     case FieldDescriptor::TYPE_SFIXED32:
    193       return JAVATYPE_INT;
    194 
    195     case FieldDescriptor::TYPE_INT64:
    196     case FieldDescriptor::TYPE_UINT64:
    197     case FieldDescriptor::TYPE_SINT64:
    198     case FieldDescriptor::TYPE_FIXED64:
    199     case FieldDescriptor::TYPE_SFIXED64:
    200       return JAVATYPE_LONG;
    201 
    202     case FieldDescriptor::TYPE_FLOAT:
    203       return JAVATYPE_FLOAT;
    204 
    205     case FieldDescriptor::TYPE_DOUBLE:
    206       return JAVATYPE_DOUBLE;
    207 
    208     case FieldDescriptor::TYPE_BOOL:
    209       return JAVATYPE_BOOLEAN;
    210 
    211     case FieldDescriptor::TYPE_STRING:
    212       return JAVATYPE_STRING;
    213 
    214     case FieldDescriptor::TYPE_BYTES:
    215       return JAVATYPE_BYTES;
    216 
    217     case FieldDescriptor::TYPE_ENUM:
    218       return JAVATYPE_ENUM;
    219 
    220     case FieldDescriptor::TYPE_GROUP:
    221     case FieldDescriptor::TYPE_MESSAGE:
    222       return JAVATYPE_MESSAGE;
    223 
    224     // No default because we want the compiler to complain if any new
    225     // types are added.
    226   }
    227 
    228   GOOGLE_LOG(FATAL) << "Can't get here.";
    229   return JAVATYPE_INT;
    230 }
    231 
    232 const char* BoxedPrimitiveTypeName(JavaType type) {
    233   switch (type) {
    234     case JAVATYPE_INT    : return "java.lang.Integer";
    235     case JAVATYPE_LONG   : return "java.lang.Long";
    236     case JAVATYPE_FLOAT  : return "java.lang.Float";
    237     case JAVATYPE_DOUBLE : return "java.lang.Double";
    238     case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
    239     case JAVATYPE_STRING : return "java.lang.String";
    240     case JAVATYPE_BYTES  : return "com.google.protobuf.ByteString";
    241     case JAVATYPE_ENUM   : return NULL;
    242     case JAVATYPE_MESSAGE: return NULL;
    243 
    244     // No default because we want the compiler to complain if any new
    245     // JavaTypes are added.
    246   }
    247 
    248   GOOGLE_LOG(FATAL) << "Can't get here.";
    249   return NULL;
    250 }
    251 
    252 bool AllAscii(const string& text) {
    253   for (int i = 0; i < text.size(); i++) {
    254     if ((text[i] & 0x80) != 0) {
    255       return false;
    256     }
    257   }
    258   return true;
    259 }
    260 
    261 string DefaultValue(const FieldDescriptor* field) {
    262   // Switch on CppType since we need to know which default_value_* method
    263   // of FieldDescriptor to call.
    264   switch (field->cpp_type()) {
    265     case FieldDescriptor::CPPTYPE_INT32:
    266       return SimpleItoa(field->default_value_int32());
    267     case FieldDescriptor::CPPTYPE_UINT32:
    268       // Need to print as a signed int since Java has no unsigned.
    269       return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
    270     case FieldDescriptor::CPPTYPE_INT64:
    271       return SimpleItoa(field->default_value_int64()) + "L";
    272     case FieldDescriptor::CPPTYPE_UINT64:
    273       return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
    274              "L";
    275     case FieldDescriptor::CPPTYPE_DOUBLE: {
    276       double value = field->default_value_double();
    277       if (value == numeric_limits<double>::infinity()) {
    278         return "Double.POSITIVE_INFINITY";
    279       } else if (value == -numeric_limits<double>::infinity()) {
    280         return "Double.NEGATIVE_INFINITY";
    281       } else if (value != value) {
    282         return "Double.NaN";
    283       } else {
    284         return SimpleDtoa(value) + "D";
    285       }
    286     }
    287     case FieldDescriptor::CPPTYPE_FLOAT: {
    288       float value = field->default_value_float();
    289       if (value == numeric_limits<float>::infinity()) {
    290         return "Float.POSITIVE_INFINITY";
    291       } else if (value == -numeric_limits<float>::infinity()) {
    292         return "Float.NEGATIVE_INFINITY";
    293       } else if (value != value) {
    294         return "Float.NaN";
    295       } else {
    296         return SimpleFtoa(value) + "F";
    297       }
    298     }
    299     case FieldDescriptor::CPPTYPE_BOOL:
    300       return field->default_value_bool() ? "true" : "false";
    301     case FieldDescriptor::CPPTYPE_STRING:
    302       if (GetType(field) == FieldDescriptor::TYPE_BYTES) {
    303         if (field->has_default_value()) {
    304           // See comments in Internal.java for gory details.
    305           return strings::Substitute(
    306             "com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
    307             CEscape(field->default_value_string()));
    308         } else {
    309           return "com.google.protobuf.ByteString.EMPTY";
    310         }
    311       } else {
    312         if (AllAscii(field->default_value_string())) {
    313           // All chars are ASCII.  In this case CEscape() works fine.
    314           return "\"" + CEscape(field->default_value_string()) + "\"";
    315         } else {
    316           // See comments in Internal.java for gory details.
    317           return strings::Substitute(
    318             "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
    319             CEscape(field->default_value_string()));
    320         }
    321       }
    322 
    323     case FieldDescriptor::CPPTYPE_ENUM:
    324       return ClassName(field->enum_type()) + "." +
    325              field->default_value_enum()->name();
    326 
    327     case FieldDescriptor::CPPTYPE_MESSAGE:
    328       return ClassName(field->message_type()) + ".getDefaultInstance()";
    329 
    330     // No default because we want the compiler to complain if any new
    331     // types are added.
    332   }
    333 
    334   GOOGLE_LOG(FATAL) << "Can't get here.";
    335   return "";
    336 }
    337 
    338 }  // namespace java
    339 }  // namespace compiler
    340 }  // namespace protobuf
    341 }  // namespace google
    342