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