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

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

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

Powered by Google App Engine
This is Rietveld 408576698