OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #if defined(ENABLE_JAVA_BRIDGE) | |
jam
2011/11/10 17:30:20
ditto
| |
6 | |
7 #include "content/browser/renderer_host/java_method.h" | |
8 | |
9 #include "base/android/jni_android.h" | |
10 #include "base/android/jni_string.h" | |
11 #include "base/string_util.h" // For ReplaceSubstringsAfterOffset | |
12 | |
13 using base::android::AttachCurrentThread; | |
14 using base::android::ConvertJavaStringToUTF8; | |
15 using base::android::GetMethodIDFromClassName; | |
16 using base::android::ScopedJavaLocalRef; | |
17 | |
18 namespace { | |
19 | |
20 // Java's reflection API represents types as a string using an extended 'binary | |
21 // name'. This converts to an enum which we store in place of the binary name | |
22 // for simplicity. | |
23 JavaType::Type BinaryNameToType(const std::string& binary_name) { | |
24 if (binary_name == "boolean") { | |
25 return JavaType::TypeBoolean; | |
26 } else if (binary_name == "byte") { | |
27 return JavaType::TypeByte; | |
28 } else if (binary_name == "char") { | |
29 return JavaType::TypeChar; | |
30 } else if (binary_name == "short") { | |
31 return JavaType::TypeShort; | |
32 } else if (binary_name == "int") { | |
33 return JavaType::TypeInt; | |
34 } else if (binary_name == "long") { | |
35 return JavaType::TypeLong; | |
36 } else if (binary_name == "float") { | |
37 return JavaType::TypeFloat; | |
38 } else if (binary_name == "double") { | |
39 return JavaType::TypeDouble; | |
40 } else if (binary_name == "void") { | |
41 return JavaType::TypeVoid; | |
42 } else if (binary_name[0] == '[') { | |
43 return JavaType::TypeArray; | |
44 } else if (binary_name == "java.lang.String") { | |
45 return JavaType::TypeString; | |
46 } | |
47 return JavaType::TypeObject; | |
48 } | |
49 | |
50 std::string BinaryNameToJNIName(const std::string& binary_name, | |
51 JavaType::Type* type) { | |
52 DCHECK(type); | |
53 *type = BinaryNameToType(binary_name); | |
54 switch (*type) { | |
55 case JavaType::TypeBoolean: | |
56 return "Z"; | |
57 case JavaType::TypeByte: | |
58 return "B"; | |
59 case JavaType::TypeChar: | |
60 return "C"; | |
61 case JavaType::TypeShort: | |
62 return "S"; | |
63 case JavaType::TypeInt: | |
64 return "I"; | |
65 case JavaType::TypeLong: | |
66 return "J"; | |
67 case JavaType::TypeFloat: | |
68 return "F"; | |
69 case JavaType::TypeDouble: | |
70 return "D"; | |
71 case JavaType::TypeVoid: | |
72 return "V"; | |
73 case JavaType::TypeArray: | |
74 return "["; | |
75 default: | |
76 DCHECK (*type == JavaType::TypeString || *type == JavaType::TypeObject); | |
77 std::string jni_name = "L" + binary_name + ";"; | |
78 ReplaceSubstringsAfterOffset(&jni_name, 0, ".", "/"); | |
79 return jni_name; | |
80 } | |
81 } | |
82 | |
83 static jmethodID g_method_get_parameter_types_id = NULL; | |
84 jmethodID GetMethodGetParameterTypesID() { | |
85 if (!g_method_get_parameter_types_id) { | |
86 g_method_get_parameter_types_id = GetMethodIDFromClassName( | |
87 AttachCurrentThread(), | |
88 "java/lang/reflect/Method", | |
89 "getParameterTypes", | |
90 "()[Ljava/lang/Class;"); | |
91 } | |
92 return g_method_get_parameter_types_id; | |
93 } | |
94 | |
95 static jmethodID g_method_get_name_id = NULL; | |
96 jmethodID GetMethodGetNameID() { | |
97 if (!g_method_get_name_id) { | |
98 g_method_get_name_id = GetMethodIDFromClassName(AttachCurrentThread(), | |
99 "java/lang/reflect/Method", | |
100 "getName", | |
101 "()Ljava/lang/String;"); | |
102 } | |
103 return g_method_get_name_id; | |
104 } | |
105 | |
106 static jmethodID g_method_get_return_type_id = NULL; | |
107 jmethodID GetMethodGetReturnTypeID() { | |
108 if (!g_method_get_return_type_id) { | |
109 g_method_get_return_type_id = GetMethodIDFromClassName( | |
110 AttachCurrentThread(), | |
111 "java/lang/reflect/Method", | |
112 "getReturnType", | |
113 "()Ljava/lang/Class;"); | |
114 } | |
115 return g_method_get_return_type_id; | |
116 } | |
117 | |
118 static jmethodID g_method_get_declaring_class_id = NULL; | |
119 jmethodID GetMethodGetDeclaringClassID() { | |
120 if (!g_method_get_declaring_class_id) { | |
121 g_method_get_declaring_class_id = GetMethodIDFromClassName( | |
122 AttachCurrentThread(), | |
123 "java/lang/reflect/Method", | |
124 "getDeclaringClass", | |
125 "()Ljava/lang/Class;"); | |
126 } | |
127 return g_method_get_declaring_class_id; | |
128 } | |
129 | |
130 static jmethodID g_class_get_name_id = NULL; | |
131 jmethodID GetClassGetNameID() { | |
132 if (!g_class_get_name_id) { | |
133 g_class_get_name_id = GetMethodIDFromClassName(AttachCurrentThread(), | |
134 "java/lang/Class", | |
135 "getName", | |
136 "()Ljava/lang/String;"); | |
137 } | |
138 return g_class_get_name_id; | |
139 } | |
140 | |
141 } // namespace | |
142 | |
143 JavaMethod::JavaMethod(const base::android::JavaRef<jobject>& method) | |
144 : java_method_(method), | |
145 have_calculated_num_parameters_(false), | |
146 id_(NULL) { | |
147 JNIEnv* env = AttachCurrentThread(); | |
148 // On construction, we do nothing except get the name. Everything else is | |
149 // done lazily. | |
150 ScopedJavaLocalRef<jstring> name(env, static_cast<jstring>( | |
151 env->CallObjectMethod(java_method_.obj(), | |
152 GetMethodGetNameID()))); | |
153 name_ = ConvertJavaStringToUTF8(env, name.obj()); | |
154 } | |
155 | |
156 std::string JavaMethod::name() const { | |
157 return name_; | |
158 } | |
159 | |
160 size_t JavaMethod::num_parameters() const { | |
161 const_cast<JavaMethod*>(this)->EnsureNumParametersIsSetUp(); | |
162 return num_parameters_; | |
163 } | |
164 | |
165 JavaType::Type JavaMethod::parameter_type(size_t index) const { | |
166 const_cast<JavaMethod*>(this)->EnsureTypesAndIDAreSetUp(); | |
167 return parameter_types_[index]; | |
168 } | |
169 | |
170 JavaType::Type JavaMethod::return_type() const { | |
171 const_cast<JavaMethod*>(this)->EnsureTypesAndIDAreSetUp(); | |
172 return return_type_; | |
173 } | |
174 | |
175 jmethodID JavaMethod::id() const { | |
176 const_cast<JavaMethod*>(this)->EnsureTypesAndIDAreSetUp(); | |
177 return id_; | |
178 } | |
179 | |
180 void JavaMethod::EnsureNumParametersIsSetUp() { | |
181 if (have_calculated_num_parameters_) { | |
182 return; | |
183 } | |
184 have_calculated_num_parameters_ = true; | |
185 | |
186 // The number of parameters will be used frequently when determining | |
187 // whether to call this method. We don't get the ID etc until actually | |
188 // required. | |
189 JNIEnv* env = AttachCurrentThread(); | |
190 ScopedJavaLocalRef<jarray> parameters(env, static_cast<jarray>( | |
191 env->CallObjectMethod(java_method_.obj(), | |
192 GetMethodGetParameterTypesID()))); | |
193 num_parameters_ = env->GetArrayLength(parameters.obj()); | |
194 } | |
195 | |
196 void JavaMethod::EnsureTypesAndIDAreSetUp() { | |
197 if (id_) { | |
198 return; | |
199 } | |
200 | |
201 // Get the parameters | |
202 JNIEnv* env = AttachCurrentThread(); | |
203 ScopedJavaLocalRef<jobjectArray> parameters(env, static_cast<jobjectArray>( | |
204 env->CallObjectMethod(java_method_.obj(), | |
205 GetMethodGetParameterTypesID()))); | |
206 // Usually, this will already have been called. | |
207 EnsureNumParametersIsSetUp(); | |
208 DCHECK_EQ(num_parameters_, | |
209 static_cast<size_t>(env->GetArrayLength(parameters.obj()))); | |
210 | |
211 // Java gives us the argument type using an extended version of the 'binary | |
212 // name'. See | |
213 // http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Class.html#getNa me(). | |
214 // If we build the signature now, there's no need to store the binary name | |
215 // of the arguments. We just store the simple type. | |
216 std::string signature("("); | |
217 | |
218 // Form the signature and record the parameter types. | |
219 parameter_types_.resize(num_parameters_); | |
220 for (size_t i = 0; i < num_parameters_; ++i) { | |
221 ScopedJavaLocalRef<jobject> parameter(env, env->GetObjectArrayElement( | |
222 parameters.obj(), i)); | |
223 ScopedJavaLocalRef<jstring> name(env, static_cast<jstring>( | |
224 env->CallObjectMethod(parameter.obj(), GetClassGetNameID()))); | |
225 std::string name_utf8 = ConvertJavaStringToUTF8(env, name.obj()); | |
226 signature += BinaryNameToJNIName(name_utf8, ¶meter_types_[i]); | |
227 } | |
228 signature += ")"; | |
229 | |
230 // Get the return type | |
231 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( | |
232 env->CallObjectMethod(java_method_.obj(), GetMethodGetReturnTypeID()))); | |
233 ScopedJavaLocalRef<jstring> name(env, static_cast<jstring>( | |
234 env->CallObjectMethod(clazz.obj(), GetClassGetNameID()))); | |
235 signature += BinaryNameToJNIName(ConvertJavaStringToUTF8(env, name.obj()), | |
236 &return_type_); | |
237 | |
238 // Get the ID for this method. | |
239 ScopedJavaLocalRef<jclass> declaring_class(env, static_cast<jclass>( | |
240 env->CallObjectMethod(java_method_.obj(), | |
241 GetMethodGetDeclaringClassID()))); | |
242 id_ = base::android::GetMethodID(env, declaring_class.obj(), name_.c_str(), | |
243 signature.c_str()); | |
244 | |
245 java_method_.Reset(); | |
246 } | |
247 | |
248 #endif // defined(ENABLE_JAVA_BRIDGE) | |
OLD | NEW |