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

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

Powered by Google App Engine
This is Rietveld 408576698