THRIFT-2637 "java:fullcamel_service_methods" option to automatically camel-case Java service methods
Patch: Tom Lee
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index 2975353..4c755ac 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -138,6 +138,8 @@
void generate_java_bean_boilerplate(std::ofstream& out, t_struct* tstruct);
void generate_function_helpers(t_function* tfunction);
+ std::string as_camel_case(std::string name, bool ucfirst=true);
+ std::string get_rpc_method_name(std::string name);
std::string get_cap_name(std::string name);
std::string generate_isset_check(t_field* field);
std::string generate_isset_check(std::string field);
@@ -2382,11 +2384,17 @@
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
string funname = (*f_iter)->get_name();
+ string sep = "_";
+ string javaname = funname;
+ if (fullcamel_style_) {
+ sep = "";
+ javaname = as_camel_case(funname);
+ }
// Open function
indent(f_service_) << "public " << function_signature(*f_iter) << endl;
scope_up(f_service_);
- indent(f_service_) << "send_" << funname << "(";
+ indent(f_service_) << "send" << sep << javaname << "(";
// Get the struct of function call params
t_struct* arg_struct = (*f_iter)->get_arglist();
@@ -2411,13 +2419,13 @@
f_service_ << "return ";
}
f_service_ <<
- "recv_" << funname << "();" << endl;
+ "recv" << sep << javaname << "();" << endl;
}
scope_down(f_service_);
f_service_ << endl;
t_function send_function(g_type_void,
- string("send_") + (*f_iter)->get_name(),
+ string("send") + sep + javaname,
(*f_iter)->get_arglist());
string argsname = (*f_iter)->get_name() + "_args";
@@ -2444,7 +2452,7 @@
t_struct noargs(program_);
t_function recv_function((*f_iter)->get_returntype(),
- string("recv_") + (*f_iter)->get_name(),
+ string("recv") + sep + javaname,
&noargs,
(*f_iter)->get_xceptions());
// Open function
@@ -2525,6 +2533,12 @@
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
string funname = (*f_iter)->get_name();
+ string sep = "_";
+ string javaname = funname;
+ if (fullcamel_style_) {
+ sep = "";
+ javaname = as_camel_case(javaname);
+ }
t_type* ret_type = (*f_iter)->get_returntype();
t_struct* arg_struct = (*f_iter)->get_arglist();
string funclassname = funname + "_call";
@@ -2607,7 +2621,7 @@
if (!ret_type->is_void()) {
f_service_ << "return ";
}
- f_service_ << "(new Client(prot)).recv_" + funname + "();" << endl;
+ f_service_ << "(new Client(prot)).recv" + sep + javaname + "();" << endl;
}
// Close function
@@ -2883,7 +2897,7 @@
vector<t_field*>::const_iterator f_iter;
f_service_ << indent();
- f_service_ << "iface." << tfunction->get_name() << "(";
+ f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "(";
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
@@ -2966,7 +2980,7 @@
if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
f_service_ << "result.success = ";
}
- f_service_ << "iface." << tfunction->get_name() << "(";
+ f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "(";
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
@@ -3643,8 +3657,9 @@
string t_java_generator::function_signature(t_function* tfunction,
string prefix) {
t_type* ttype = tfunction->get_returntype();
+ std::string fn_name = get_rpc_method_name(tfunction->get_name());
std::string result =
- type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
+ type_name(ttype) + " " + prefix + fn_name + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
t_struct* xs = tfunction->get_xceptions();
const std::vector<t_field*>& xceptions = xs->get_members();
vector<t_field*>::const_iterator x_iter;
@@ -3670,7 +3685,9 @@
}
ret_type += tfunction->get_name() + "_call";
- std::string result = prefix + "void " + tfunction->get_name() + "(" + arglist + ")";
+ std::string fn_name = get_rpc_method_name(tfunction->get_name());
+
+ std::string result = prefix + "void " + fn_name + "(" + arglist + ")";
return result;
}
@@ -3826,6 +3843,40 @@
}
+std::string t_java_generator::as_camel_case(std::string name, bool ucfirst) {
+ std::string new_name;
+ size_t i = 0;
+ for (i = 0; i < name.size(); i++) {
+ if (name[i] != '_') break;
+ }
+ if (ucfirst) {
+ new_name += toupper(name[i++]);
+ }
+ else {
+ new_name += tolower(name[i++]);
+ }
+ for (; i < name.size(); i++) {
+ if (name[i] == '_') {
+ if (i < name.size()-1) {
+ i++;
+ new_name += toupper(name[i]);
+ }
+ }
+ else {
+ new_name += name[i];
+ }
+ }
+ return new_name;
+}
+
+std::string t_java_generator::get_rpc_method_name(std::string name) {
+ if (fullcamel_style_) {
+ return as_camel_case(name, false);
+ } else {
+ return name;
+ }
+}
+
/**
* Applies the correct style to a string based on the value of nocamel_style_
* and/or fullcamel_style_
@@ -3833,21 +3884,8 @@
std::string t_java_generator::get_cap_name(std::string name){
if (nocamel_style_) {
return "_" + name;
- } if (fullcamel_style_) {
- std::string new_name;
- new_name += toupper(name[0]);
- for (size_t i = 1; i < name.size(); i++) {
- if (name[i] == '_') {
- if (i < name.size()-1) {
- i++;
- new_name += toupper(name[i]);
- }
- }
- else {
- new_name += name[i];
- }
- }
- return new_name;
+ } else if (fullcamel_style_) {
+ return as_camel_case(name);
} else {
name[0] = toupper(name[0]);
return name;
@@ -4537,7 +4575,7 @@
" beans: Members will be private, and setter methods will return void.\n"
" private-members: Members will be private, but setter methods will return 'this' like usual.\n"
" nocamel: Do not use CamelCase field accessors with beans.\n"
-" fullcamel: Convert underscored_field_names to CamelCase.\n"
+" fullcamel: Convert underscored_accessor_or_service_names to camelCase.\n"
" android_legacy: Do not use java.io.IOException(throwable) (available for Android 2.3 and above).\n"
" java5: Generate Java 1.5 compliant code (includes android_legacy flag).\n"
" reuse-objects: Data objects will not be allocated, but existing instances will be used (read and write).\n"
diff --git a/lib/java/test/org/apache/thrift/TestFullCamel.java b/lib/java/test/org/apache/thrift/TestFullCamel.java
index d6fd001..1681fb8 100644
--- a/lib/java/test/org/apache/thrift/TestFullCamel.java
+++ b/lib/java/test/org/apache/thrift/TestFullCamel.java
@@ -27,6 +27,7 @@
import org.apache.thrift.protocol.TType;
import thrift.test.OneOfEachZZ;
+import thrift.test.UnderscoreSrv;
// Sanity check for the code generated by 'fullcamel'.
//
@@ -45,5 +46,14 @@
assertTrue( obj.isImFalse() == true );
}
+ public void testCamelCaseRpcMethods() throws Exception {
+ final UnderscoreSrv.Iface srv = new UnderscoreSrv.Iface() {
+ @Override
+ public long someRpcCall(String message) {
+ return 1l;
+ }
+ };
+ assertTrue(1l == srv.someRpcCall("test"));
+ }
}
diff --git a/test/DenseLinkingTest.thrift b/test/DenseLinkingTest.thrift
index f18234b..3a5b957 100644
--- a/test/DenseLinkingTest.thrift
+++ b/test/DenseLinkingTest.thrift
@@ -91,3 +91,8 @@
service Srv {
i32 Janky(1: i32 arg)
}
+
+service UnderscoreSrv {
+ i64 some_rpc_call(1: string message)
+}
+