#include "content/browser/android/java/java_method.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "content/browser/android/java/jni_reflect.h"
using base::android::AttachCurrentThread;
using base::android::MethodID;
using base::android::ScopedJavaLocalRef;
namespace content {
namespace {
std::string BinaryNameToJNISignature(const std::string& binary_name,
JavaType* type) {
DCHECK(type);
*type = JavaType::CreateFromBinaryName(binary_name);
return type->JNISignature();
}
}
JavaMethod::JavaMethod(const base::android::JavaRef<jobject>& method)
: java_method_(method),
have_calculated_num_parameters_(false),
id_(NULL) {
JNIEnv* env = AttachCurrentThread();
name_ = GetMethodName(env, java_method_);
}
JavaMethod::~JavaMethod() {
}
size_t JavaMethod::num_parameters() const {
EnsureNumParametersIsSetUp();
return num_parameters_;
}
bool JavaMethod::is_static() const {
EnsureTypesAndIDAreSetUp();
return is_static_;
}
const JavaType& JavaMethod::parameter_type(size_t index) const {
EnsureTypesAndIDAreSetUp();
return parameter_types_[index];
}
const JavaType& JavaMethod::return_type() const {
EnsureTypesAndIDAreSetUp();
return return_type_;
}
jmethodID JavaMethod::id() const {
EnsureTypesAndIDAreSetUp();
return id_;
}
void JavaMethod::EnsureNumParametersIsSetUp() const {
if (have_calculated_num_parameters_) {
return;
}
have_calculated_num_parameters_ = true;
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> parameters(
GetMethodParameterTypes(env, java_method_));
num_parameters_ = env->GetArrayLength(parameters.obj());
}
void JavaMethod::EnsureTypesAndIDAreSetUp() const {
if (id_) {
return;
}
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> parameters(
GetMethodParameterTypes(env, java_method_));
EnsureNumParametersIsSetUp();
DCHECK_EQ(num_parameters_,
static_cast<size_t>(env->GetArrayLength(parameters.obj())));
std::string signature("(");
parameter_types_.resize(num_parameters_);
for (size_t i = 0; i < num_parameters_; ++i) {
ScopedJavaLocalRef<jclass> parameter(
env,
static_cast<jclass>(env->GetObjectArrayElement(parameters.obj(), i)));
signature += BinaryNameToJNISignature(GetClassName(env, parameter),
¶meter_types_[i]);
if (parameter_types_[i].type == JavaType::TypeObject) {
parameter_types_[i].class_ref.Reset(parameter);
}
}
signature += ")";
ScopedJavaLocalRef<jclass> clazz(GetMethodReturnType(env, java_method_));
signature +=
BinaryNameToJNISignature(GetClassName(env, clazz), &return_type_);
is_static_ = IsMethodStatic(env, java_method_);
ScopedJavaLocalRef<jclass> declaring_class(
GetMethodDeclaringClass(env, java_method_));
id_ = is_static_ ?
MethodID::Get<MethodID::TYPE_STATIC>(
env, declaring_class.obj(), name_.c_str(), signature.c_str()) :
MethodID::Get<MethodID::TYPE_INSTANCE>(
env, declaring_class.obj(), name_.c_str(), signature.c_str());
java_method_.Reset();
}
}