Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: content/browser/renderer_host/java_bound_object.cc

Issue 8509019: Add JavaBoundObject (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed a superfluous string::reserve() Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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_bound_object.h"
8
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/string_number_conversions.h"
12 #include "base/stringprintf.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
14
15 using base::StringPrintf;
16 using base::android::AttachCurrentThread;
17 using base::android::ConvertUTF8ToJavaString;
18 using base::android::GetMethodIDFromClassName;
19 using base::android::JavaRef;
20 using base::android::ScopedJavaGlobalRef;
21 using base::android::ScopedJavaLocalRef;
22 using WebKit::WebBindings;
23
24 // The conversion between JavaScript and Java types is based on the Live
25 // Connect 2 spec. See
26 // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS.
27
28 // Note that in some cases, we differ from from the spec in order to maintain
29 // existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may
30 // revisit this decision in the future.
31
32 namespace {
33
34 std::string NPIdentifierToString(NPIdentifier identifier) {
35 const NPUTF8* string;
36 int32_t number;
37 bool is_string;
38 WebBindings::extractIdentifierData(identifier, string, number, is_string);
39 DCHECK(is_string);
40 return string;
41 }
42
43 // Our special NPObject type. We extend an NPObject with a pointer to a
44 // JavaBoundObject. We also add static methods for each of the NPObject
45 // callbacks, which are registered by our NPClass. These methods simply
46 // delegate to the private implementation methods of JavaBoundObject.
47 struct JavaNPObject : public NPObject {
48 JavaBoundObject* bound_object;
49
50 static const NPClass kNPClass;
51
52 static NPObject* Allocate(NPP npp, NPClass* np_class);
53 static void Deallocate(NPObject* np_object);
54 static bool HasMethod(NPObject* np_object, NPIdentifier np_identifier);
55 static bool Invoke(NPObject* np_object, NPIdentifier np_identifier,
56 const NPVariant *args, uint32_t arg_count,
57 NPVariant *result);
58 static bool HasProperty(NPObject* np_object, NPIdentifier np_identifier);
59 static bool GetProperty(NPObject* np_object, NPIdentifier np_identifier,
60 NPVariant *result);
61 };
62
63 const NPClass JavaNPObject::kNPClass = {
64 NP_CLASS_STRUCT_VERSION,
65 JavaNPObject::Allocate,
66 JavaNPObject::Deallocate,
67 NULL, // NPInvalidate
68 JavaNPObject::HasMethod,
69 JavaNPObject::Invoke,
70 NULL, // NPInvokeDefault
71 JavaNPObject::HasProperty,
72 JavaNPObject::GetProperty,
73 NULL, // NPSetProperty,
74 NULL, // NPRemoveProperty
75 };
76
77 NPObject* JavaNPObject::Allocate(NPP npp, NPClass* np_class) {
78 JavaNPObject* obj = new JavaNPObject;
79 return obj;
80 }
81
82 void JavaNPObject::Deallocate(NPObject* np_object) {
83 JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
84 delete obj->bound_object;
85 delete obj;
86 }
87
88 bool JavaNPObject::HasMethod(NPObject* np_object, NPIdentifier np_identifier) {
89 std::string name = NPIdentifierToString(np_identifier);
90 JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
91 return obj->bound_object->HasMethod(name);
92 }
93
94 bool JavaNPObject::Invoke(NPObject* np_object, NPIdentifier np_identifier,
95 const NPVariant* args, uint32_t arg_count,
96 NPVariant* result) {
97 std::string name = NPIdentifierToString(np_identifier);
98 JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
99 return obj->bound_object->Invoke(name, args, arg_count, result);
100 }
101
102 bool JavaNPObject::HasProperty(NPObject* np_object,
103 NPIdentifier np_identifier) {
104 // LIVECONNECT_COMPLIANCE: Return false to indicate that the property is not
105 // present. We should support this correctly.
106 return false;
107 }
108
109 bool JavaNPObject::GetProperty(NPObject* np_object,
110 NPIdentifier np_identifier,
111 NPVariant* result) {
112 // LIVECONNECT_COMPLIANCE: Return false to indicate that the property is
113 // undefined. We should support this correctly.
114 return false;
115 }
116
117 // Calls a Java method through JNI and returns the result as an NPVariant. Note
118 // that this method does not do any type coercion. The Java return value is
119 // simply converted to the corresponding NPAPI type.
120 NPVariant CallJNIMethod(jobject object, JavaType::Type return_type,
121 jmethodID id, jvalue* parameters) {
122 JNIEnv* env = AttachCurrentThread();
123 NPVariant result;
124 switch (return_type) {
125 case JavaType::TypeBoolean:
126 BOOLEAN_TO_NPVARIANT(env->CallBooleanMethodA(object, id, parameters),
127 result);
128 break;
129 case JavaType::TypeByte:
130 INT32_TO_NPVARIANT(env->CallByteMethodA(object, id, parameters), result);
131 break;
132 case JavaType::TypeChar:
133 INT32_TO_NPVARIANT(env->CallCharMethodA(object, id, parameters), result);
134 break;
135 case JavaType::TypeShort:
136 INT32_TO_NPVARIANT(env->CallShortMethodA(object, id, parameters), result);
137 break;
138 case JavaType::TypeInt:
139 INT32_TO_NPVARIANT(env->CallIntMethodA(object, id, parameters), result);
140 break;
141 case JavaType::TypeLong:
142 DOUBLE_TO_NPVARIANT(env->CallLongMethodA(object, id, parameters), result);
143 break;
144 case JavaType::TypeFloat:
145 DOUBLE_TO_NPVARIANT(env->CallFloatMethodA(object, id, parameters),
146 result);
147 break;
148 case JavaType::TypeDouble:
149 DOUBLE_TO_NPVARIANT(env->CallDoubleMethodA(object, id, parameters),
150 result);
151 break;
152 case JavaType::TypeVoid:
153 env->CallVoidMethodA(object, id, parameters);
154 VOID_TO_NPVARIANT(result);
155 break;
156 case JavaType::TypeArray:
157 // TODO(steveblock): Handle arrays
158 VOID_TO_NPVARIANT(result);
159 break;
160 case JavaType::TypeString: {
161 ScopedJavaLocalRef<jstring> java_string(env, static_cast<jstring>(
162 env->CallObjectMethodA(object, id, parameters)));
163 if (!java_string.obj()) {
164 // LIVECONNECT_COMPLIANCE: Return undefined to maintain existing
165 // behavior. We should return a null string.
166 VOID_TO_NPVARIANT(result);
167 break;
168 }
169 std::string str =
170 base::android::ConvertJavaStringToUTF8(env, java_string.obj());
171 // Take a copy and pass ownership to the variant. We must allocate using
172 // NPN_MemAlloc, to match NPN_ReleaseVariant, which uses NPN_MemFree.
173 size_t length = str.length();
174 char* buffer = static_cast<char*>(NPN_MemAlloc(length));
175 str.copy(buffer, length, 0);
176 STRINGN_TO_NPVARIANT(buffer, length, result);
177 break;
178 }
179 case JavaType::TypeObject: {
180 ScopedJavaLocalRef<jobject> java_object(
181 env,
182 env->CallObjectMethodA(object, id, parameters));
183 if (!java_object.obj()) {
184 NULL_TO_NPVARIANT(result);
185 break;
186 }
187 OBJECT_TO_NPVARIANT(JavaBoundObject::Create(java_object), result);
188 break;
189 }
190 }
191 return result;
192 }
193
194 jvalue CoerceJavaScriptNumberToJavaValue(const NPVariant& variant,
195 JavaType::Type target_type) {
196 // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
197 jvalue result;
198 DCHECK(variant.type == NPVariantType_Int32 ||
199 variant.type == NPVariantType_Double);
200 bool is_double = variant.type == NPVariantType_Double;
201 switch (target_type) {
202 case JavaType::TypeByte:
203 result.b = is_double ? static_cast<jbyte>(NPVARIANT_TO_DOUBLE(variant)) :
204 static_cast<jbyte>(NPVARIANT_TO_INT32(variant));
205 break;
206 case JavaType::TypeChar:
207 // LIVECONNECT_COMPLIANCE: Convert double to 0 to maintain existing
208 // behavior.
209 result.c = is_double ? 0 :
210 static_cast<jchar>(NPVARIANT_TO_INT32(variant));
211 break;
212 case JavaType::TypeShort:
213 result.s = is_double ? static_cast<jshort>(NPVARIANT_TO_DOUBLE(variant)) :
214 static_cast<jshort>(NPVARIANT_TO_INT32(variant));
215 break;
216 case JavaType::TypeInt:
217 result.i = is_double ? static_cast<jint>(NPVARIANT_TO_DOUBLE(variant)) :
218 NPVARIANT_TO_INT32(variant);
219 break;
220 case JavaType::TypeLong:
221 result.j = is_double ? static_cast<jlong>(NPVARIANT_TO_DOUBLE(variant)) :
222 NPVARIANT_TO_INT32(variant);
223 break;
224 case JavaType::TypeFloat:
225 result.f = is_double ? static_cast<jfloat>(NPVARIANT_TO_DOUBLE(variant)) :
226 NPVARIANT_TO_INT32(variant);
227 break;
228 case JavaType::TypeDouble:
229 result.d = is_double ? NPVARIANT_TO_DOUBLE(variant) :
230 NPVARIANT_TO_INT32(variant);
231 break;
232 case JavaType::TypeObject:
233 // LIVECONNECT_COMPLIANCE: Convert to null to maintain existing behavior.
234 // We should handle object equivalents of primitive types.
235 result.l = NULL;
236 break;
237 case JavaType::TypeString:
238 result.l = ConvertUTF8ToJavaString(
239 AttachCurrentThread(),
240 is_double ? StringPrintf("%.6lg", NPVARIANT_TO_DOUBLE(variant)) :
241 base::IntToString(NPVARIANT_TO_INT32(variant)));
242 break;
243 case JavaType::TypeBoolean:
244 // LIVECONNECT_COMPLIANCE: Convert to false to maintain existing behavior.
245 // We should convert to false for o or NaN, true otherwise.
246 result.z = JNI_FALSE;
247 break;
248 case JavaType::TypeArray:
249 // LIVECONNECT_COMPLIANCE: Convert to null to maintain existing behavior.
250 // We should raise a JavaScript exception.
251 result.l = NULL;
252 break;
253 case JavaType::TypeVoid:
254 // Conversion to void must never happen.
255 NOTREACHED();
256 break;
257 }
258 return result;
259 }
260
261 jvalue CoerceJavaScriptBooleanToJavaValue(const NPVariant& variant,
262 JavaType::Type target_type) {
263 // See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES.
264 DCHECK_EQ(NPVariantType_Bool, variant.type);
265 bool boolean_value = NPVARIANT_TO_BOOLEAN(variant);
266 jvalue result;
267 switch (target_type) {
268 case JavaType::TypeBoolean:
269 result.z = boolean_value ? JNI_TRUE : JNI_FALSE;
270 break;
271 case JavaType::TypeObject:
272 // LIVECONNECT_COMPLIANCE: Convert to NULL to maintain existing behavior.
273 // We should handle java.lang.Boolean and java.lang.Object.
274 result.l = NULL;
275 break;
276 case JavaType::TypeString:
277 result.l = ConvertUTF8ToJavaString(AttachCurrentThread(),
278 boolean_value ? "true" : "false");
279 break;
280 case JavaType::TypeByte:
281 case JavaType::TypeChar:
282 case JavaType::TypeShort:
283 case JavaType::TypeInt:
284 case JavaType::TypeLong:
285 case JavaType::TypeFloat:
286 case JavaType::TypeDouble: {
287 // LIVECONNECT_COMPLIANCE: Convert to 0 to maintain existing behavior. We
288 // should convert to 0 or 1.
289 jvalue null_value = {0};
290 result = null_value;
291 break;
292 }
293 case JavaType::TypeArray:
294 // LIVECONNECT_COMPLIANCE: Convert to NULL to maintain existing behavior.
295 // We should raise a JavaScript exception.
296 result.l = NULL;
297 break;
298 case JavaType::TypeVoid:
299 // Conversion to void must never happen.
300 NOTREACHED();
301 break;
302 }
303 return result;
304 }
305
306 jvalue CoerceJavaScriptStringToJavaValue(const NPVariant& variant,
307 JavaType::Type target_type) {
308 // See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES.
309 DCHECK_EQ(NPVariantType_String, variant.type);
310 jvalue result;
311 switch (target_type) {
312 case JavaType::TypeString:
313 result.l = ConvertUTF8ToJavaString(
314 AttachCurrentThread(),
315 base::StringPiece(NPVARIANT_TO_STRING(variant).UTF8Characters,
316 NPVARIANT_TO_STRING(variant).UTF8Length));
317 break;
318 case JavaType::TypeObject:
319 // LIVECONNECT_COMPLIANCE: Convert to NULL to maintain existing behavior.
320 // We should handle java.lang.Object.
321 result.l = NULL;
322 break;
323 case JavaType::TypeByte:
324 case JavaType::TypeShort:
325 case JavaType::TypeInt:
326 case JavaType::TypeLong:
327 case JavaType::TypeFloat:
328 case JavaType::TypeDouble: {
329 // LIVECONNECT_COMPLIANCE: Convert to 0 to maintain existing behavior. we
330 // should use valueOf() method of corresponding object type.
331 jvalue null_value = {0};
332 result = null_value;
333 break;
334 }
335 case JavaType::TypeChar:
336 // LIVECONNECT_COMPLIANCE: Convert to 0 to maintain existing behavior. we
337 // should use java.lang.Short.decode().
338 result.c = 0;
339 break;
340 case JavaType::TypeBoolean:
341 // LIVECONNECT_COMPLIANCE: Convert to false to maintain existing behavior.
342 // We should convert the empty string to false, otherwise true.
343 result.z = JNI_FALSE;
344 break;
345 case JavaType::TypeArray:
346 // LIVECONNECT_COMPLIANCE: Convert to NULL to maintain existing behavior.
347 // We should raise a JavaScript exception.
348 result.l = NULL;
349 break;
350 case JavaType::TypeVoid:
351 // Conversion to void must never happen.
352 NOTREACHED();
353 break;
354 }
355 return result;
356 }
357
358 jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant,
359 JavaType::Type target_type) {
360 // We only handle Java objects. See
361 // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_OBJECTS.
362 // TODO(steveblock): Handle arrays.
363 // TODO(steveblock): Handle JavaScript objects.
364 DCHECK_EQ(NPVariantType_Object, variant.type);
365
366 // The only type of object we should encounter is a Java object, as
367 // other objects should have been converted to NULL in the renderer.
368 // See CreateNPVariantParam().
369 // TODO(steveblock): This will have to change once we support arrays and
370 // JavaScript objects.
371 NPObject* object = NPVARIANT_TO_OBJECT(variant);
372 DCHECK_EQ(&JavaNPObject::kNPClass, object->_class);
373
374 jvalue result;
375 switch (target_type) {
376 case JavaType::TypeObject:
377 // LIVECONNECT_COMPLIANCE: Pass all Java objects to maintain existing
378 // behavior. We should pass only Java objects which are
379 // assignment-compatibile.
380 result.l = AttachCurrentThread()->NewLocalRef(
381 JavaBoundObject::GetJavaObject(object));
382 break;
383 case JavaType::TypeString:
384 // LIVECONNECT_COMPLIANCE: Convert to "undefined" to maintain existing
385 // behavior. We should call toString() on the Java object.
386 result.l = ConvertUTF8ToJavaString(AttachCurrentThread(), "undefined");
387 break;
388 case JavaType::TypeByte:
389 case JavaType::TypeShort:
390 case JavaType::TypeInt:
391 case JavaType::TypeLong:
392 case JavaType::TypeFloat:
393 case JavaType::TypeDouble:
394 case JavaType::TypeChar: {
395 // LIVECONNECT_COMPLIANCE: Convert to 0 to maintain existing behavior. We
396 // should raise a JavaScript exception.
397 jvalue null_value = {0};
398 result = null_value;
399 break;
400 }
401 case JavaType::TypeBoolean:
402 // LIVECONNECT_COMPLIANCE: Convert to false to maintain existing behavior.
403 // We should raise a JavaScript exception.
404 result.z = JNI_FALSE;
405 break;
406 case JavaType::TypeArray:
407 // LIVECONNECT_COMPLIANCE: Convert to NULL to maintain existing behavior.
408 // We should raise a JavaScript exception.
409 result.l = NULL;
410 break;
411 case JavaType::TypeVoid:
412 // Conversion to void must never happen.
413 NOTREACHED();
414 break;
415 }
416 return result;
417 }
418
419 jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(const NPVariant& variant,
420 JavaType::Type target_type) {
421 // See http://jdk6.java.net/plugin2/liveconnect/#JS_NULL.
422 DCHECK(variant.type == NPVariantType_Null ||
423 variant.type == NPVariantType_Void);
424 jvalue result;
425 switch (target_type) {
426 case JavaType::TypeObject:
427 result.l = NULL;
428 break;
429 case JavaType::TypeString:
430 if (variant.type == NPVariantType_Void) {
431 // LIVECONNECT_COMPLIANCE: Convert undefined to "undefined" to maintain
432 // existing behavior. We should convert undefined to NULL.
433 result.l = ConvertUTF8ToJavaString(AttachCurrentThread(), "undefined");
434 } else {
435 result.l = NULL;
436 }
437 break;
438 case JavaType::TypeByte:
439 case JavaType::TypeChar:
440 case JavaType::TypeShort:
441 case JavaType::TypeInt:
442 case JavaType::TypeLong:
443 case JavaType::TypeFloat:
444 case JavaType::TypeDouble: {
445 jvalue null_value = {0};
446 result = null_value;
447 break;
448 }
449 case JavaType::TypeBoolean:
450 result.z = JNI_FALSE;
451 break;
452 case JavaType::TypeArray:
453 // LIVECONNECT_COMPLIANCE: Convert to NULL to maintain existing behavior.
454 // We should raise a JavaScript exception.
455 result.l = NULL;
456 break;
457 case JavaType::TypeVoid:
458 // Conversion to void must never happen.
459 NOTREACHED();
460 break;
461 }
462 return result;
463 }
464
465 jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant,
466 JavaType::Type target_type) {
467 // Note that in all these conversions, the relevant field of the jvalue must
468 // always be explicitly set, as jvalue does not initialize its fields.
469
470 // Some of these methods create new Java Strings. Note that we don't
471 // explicitly release the local ref to these new objects, as there's no simple
472 // way to do so.
473 switch (variant.type) {
474 case NPVariantType_Int32:
475 case NPVariantType_Double:
476 return CoerceJavaScriptNumberToJavaValue(variant, target_type);
477 case NPVariantType_Bool:
478 return CoerceJavaScriptBooleanToJavaValue(variant, target_type);
479 case NPVariantType_String:
480 return CoerceJavaScriptStringToJavaValue(variant, target_type);
481 case NPVariantType_Object:
482 return CoerceJavaScriptObjectToJavaValue(variant, target_type);
483 case NPVariantType_Null:
484 case NPVariantType_Void:
485 return CoerceJavaScriptNullOrUndefinedToJavaValue(variant, target_type);
486 }
487 NOTREACHED();
488 return jvalue();
489 }
490
491 static jmethodID g_object_get_class_id = NULL;
492 jmethodID GetObjectGetClassID() {
493 if (!g_object_get_class_id) {
494 g_object_get_class_id = GetMethodIDFromClassName(AttachCurrentThread(),
495 "java/lang/Object",
496 "getClass",
497 "()Ljava/lang/Class;");
498 }
499 return g_object_get_class_id;
500 }
501
502 static jmethodID g_class_get_methods_id = NULL;
503 jmethodID ClassGetMethodsID() {
504 if (!g_class_get_methods_id) {
505 g_class_get_methods_id = GetMethodIDFromClassName(
506 AttachCurrentThread(),
507 "java/lang/Class",
508 "getMethods",
509 "()[Ljava/lang/reflect/Method;");
510 }
511 return g_class_get_methods_id;
512 }
513
514 } // namespace
515
516
517 NPObject* JavaBoundObject::Create(const JavaRef<jobject>& object) {
518 // The first argument (a plugin's instance handle) is passed through to the
519 // allocate function directly, and we don't use it, so it's ok to be 0.
520 // The object is created with a ref count of one.
521 NPObject* np_object = WebBindings::createObject(0, const_cast<NPClass*>(
522 &JavaNPObject::kNPClass));
523 // The NPObject takes ownership of the JavaBoundObject.
524 reinterpret_cast<JavaNPObject*>(np_object)->bound_object =
525 new JavaBoundObject(object);
526 return np_object;
527 }
528
529 JavaBoundObject::JavaBoundObject(const JavaRef<jobject>& object)
530 : java_object_(object),
531 are_methods_set_up_(false) {
532 // We don't do anything with our Java object when first created. We do it all
533 // lazily when a method is first invoked.
534 }
535
536 JavaBoundObject::~JavaBoundObject() {
537 // Use the current thread's JNI env to release our global ref to the Java
538 // object.
539 AttachCurrentThread()->DeleteGlobalRef(java_object_.Release());
540 }
541
542 jobject JavaBoundObject::GetJavaObject(NPObject* object) {
543 DCHECK_EQ(&JavaNPObject::kNPClass, object->_class);
544 JavaBoundObject* jbo = reinterpret_cast<JavaNPObject*>(object)->bound_object;
545 return jbo->java_object_.obj();
546 }
547
548 bool JavaBoundObject::HasMethod(const std::string& name) const {
549 const_cast<JavaBoundObject*>(this)->EnsureMethodsAreSetUp();
550 return methods_.find(name) != methods_.end();
551 }
552
553 bool JavaBoundObject::Invoke(const std::string& name, const NPVariant* args,
554 size_t arg_count, NPVariant* result) {
555 EnsureMethodsAreSetUp();
556
557 // Get all methods with the correct name.
558 std::pair<JavaMethodMap::const_iterator, JavaMethodMap::const_iterator>
559 iters = methods_.equal_range(name);
560 if (iters.first == iters.second) {
561 return false;
562 }
563
564 // Take the first method with the correct number of arguments.
565 JavaMethod* method = NULL;
566 for (JavaMethodMap::const_iterator iter = iters.first; iter != iters.second;
567 ++iter) {
568 if (iter->second->num_parameters() == arg_count) {
569 method = iter->second.get();
570 break;
571 }
572 }
573 if (!method) {
574 return false;
575 }
576
577 // Coerce
578 std::vector<jvalue> parameters(arg_count);
579 for (size_t i = 0; i < arg_count; ++i) {
580 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i],
581 method->parameter_type(i));
582 }
583
584 // Call
585 *result = CallJNIMethod(java_object_.obj(), method->return_type(),
586 method->id(), &parameters[0]);
587 return true;
588 }
589
590 void JavaBoundObject::EnsureMethodsAreSetUp() {
591 if (are_methods_set_up_) {
592 return;
593 }
594 are_methods_set_up_ = true;
595
596 JNIEnv* env = AttachCurrentThread();
597 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>(
598 env->CallObjectMethod(java_object_.obj(), GetObjectGetClassID())));
599 ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>(
600 env->CallObjectMethod(clazz.obj(), ClassGetMethodsID())));
601 size_t num_methods = env->GetArrayLength(methods.obj());
602 for (size_t i = 0; i < num_methods; ++i) {
603 ScopedJavaLocalRef<jobject> java_method(
604 env,
605 env->GetObjectArrayElement(methods.obj(), i));
606 JavaMethod* method = new JavaMethod(java_method);
607 methods_.insert(std::make_pair(method->name(), method));
608 }
609 }
610
611 #endif // defined(ENABLE_JAVA_BRIDGE)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698