Add explicit binary type to Thrift

Summary: Identical to string in all languages except Java. Java String is NOT binary-safe, so we need to use raw byte[] in that case. PHP/RUBY/Python strings are all binary safe, and C++ std::string works fine and manages memory for you so it's the safest route. Java just needs this tweak.

Reviewed By: aditya

Test Plan: Use "binary" as a type instead of String.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665099 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index cc24610..3736ceb 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -1220,7 +1220,11 @@
           name;
         break;
       case t_base_type::TYPE_STRING:        
-        out << "readString();";
+        if (((t_base_type*)type)->is_binary()) {
+          out << "readBinary();";
+        } else {
+          out << "readString();";
+        }
         break;
       case t_base_type::TYPE_BOOL:
         out << "readBool();";
@@ -1431,7 +1435,11 @@
           "compiler error: cannot serialize void field in a struct: " + name;
         break;
       case t_base_type::TYPE_STRING:
-        out << "writeString(" << name << ");";
+        if (((t_base_type*)type)->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
         break;
       case t_base_type::TYPE_BOOL:
         out << "writeBool(" << name << ");";
@@ -1602,7 +1610,7 @@
   }
 
   if (ttype->is_base_type()) {
-    return base_type_name(((t_base_type*)ttype)->get_base(), in_container);
+    return base_type_name((t_base_type*)ttype, in_container);
   } else if (ttype->is_enum()) {
     return (in_container ? "Integer" : "int");
   } else if (ttype->is_map()) {
@@ -1642,13 +1650,19 @@
  * @param tbase The base type
  * @param container Is it going in a Java container?
  */
-string t_java_generator::base_type_name(t_base_type::t_base tbase,
+string t_java_generator::base_type_name(t_base_type* type,
                                         bool in_container) {
+  t_base_type::t_base tbase = type->get_base();
+
   switch (tbase) {
   case t_base_type::TYPE_VOID:
     return "void";
   case t_base_type::TYPE_STRING:
-    return "String";
+    if (type->is_binary()) {
+      return "byte[]";
+    } else {
+      return "String";
+    }
   case t_base_type::TYPE_BOOL:
     return "boolean";
   case t_base_type::TYPE_BYTE:
diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h
index 7afffdb..077000e 100644
--- a/compiler/cpp/src/generate/t_java_generator.h
+++ b/compiler/cpp/src/generate/t_java_generator.h
@@ -124,7 +124,7 @@
   std::string java_type_imports();
   std::string java_thrift_imports();
   std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false);
-  std::string base_type_name(t_base_type::t_base tbase, bool in_container=false);
+  std::string base_type_name(t_base_type* tbase, bool in_container=false);
   std::string declare_field(t_field* tfield, bool init=false);
   std::string function_signature(t_function* tfunction, std::string prefix="");
   std::string argument_list(t_struct* tstruct);
diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h
index dd1067f..afc41da 100644
--- a/compiler/cpp/src/globals.h
+++ b/compiler/cpp/src/globals.h
@@ -47,6 +47,7 @@
 
 extern t_type* g_type_void;
 extern t_type* g_type_string;
+extern t_type* g_type_binary;
 extern t_type* g_type_slist;
 extern t_type* g_type_bool;
 extern t_type* g_type_byte;
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index eb48cd0..51de7fd 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -42,6 +42,7 @@
 
 t_type* g_type_void;
 t_type* g_type_string;
+t_type* g_type_binary;
 t_type* g_type_slist;
 t_type* g_type_bool;
 t_type* g_type_byte;
@@ -644,6 +645,8 @@
   // Initialize global types
   g_type_void   = new t_base_type("void",   t_base_type::TYPE_VOID);
   g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
+  g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
+  ((t_base_type*)g_type_binary)->set_binary(true);
   g_type_slist  = new t_base_type("string", t_base_type::TYPE_STRING);
   ((t_base_type*)g_type_slist)->set_string_list(true);
   g_type_bool   = new t_base_type("bool",   t_base_type::TYPE_BOOL);
diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h
index c9548bb..f3c9d37 100644
--- a/compiler/cpp/src/parse/t_base_type.h
+++ b/compiler/cpp/src/parse/t_base_type.h
@@ -48,7 +48,15 @@
   }
 
   bool is_string_list() const {
-    return base_ == TYPE_STRING && string_list_;
+    return (base_ == TYPE_STRING) && string_list_;
+  }
+
+  void set_binary(bool val) {
+    binary_ = val;
+  }
+  
+  bool is_binary() const {
+    return (base_ == TYPE_STRING) && binary_;
   }
 
   void set_string_enum(bool val) {
@@ -75,6 +83,7 @@
   t_base base_;
 
   bool string_list_;
+  bool binary_;
   bool string_enum_;
   std::vector<std::string> string_enum_vals_;
 };
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index abda14f..ff1b201 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -76,6 +76,7 @@
 "i64"           { return tok_i64;           }
 "double"        { return tok_double;        }
 "string"        { return tok_string;        }
+"binary"        { return tok_binary;        }
 "slist"         { return tok_slist;         }
 "senum"         { return tok_senum;         }
 "map"           { return tok_map;           }
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index 019fb9d..c6f38a2 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -82,6 +82,7 @@
 %token tok_bool
 %token tok_byte
 %token tok_string
+%token tok_binary
 %token tok_slist
 %token tok_senum
 %token tok_i16
@@ -792,6 +793,11 @@
       pdebug("BaseType -> tok_string");
       $$ = g_type_string;
     }
+| tok_binary
+    {
+      pdebug("BaseType -> tok_binary");
+      $$ = g_type_binary;
+    }
 | tok_slist
     {
       pdebug("BaseType -> tok_slist");