Implement Class.getDeclared(Constructors|Fields|Methods).
This required making sure that a Method* that represents a constructor
has java.lang.reflect.Constructor as its class.
Change-Id: I25908845a2b8d686d5404ac584693db0edd5853c
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index c334f04..d77e3f0 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -18,6 +18,7 @@
#include "class_linker.h"
#include "class_loader.h"
#include "object.h"
+#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -53,6 +54,107 @@
return AddLocalReference<jclass>(env, c);
}
+template<typename T>
+jobjectArray ToArray(JNIEnv* env, const char* array_class_name, const std::vector<T*>& objects) {
+ jclass array_class = env->FindClass(array_class_name);
+ jobjectArray result = env->NewObjectArray(objects.size(), array_class, NULL);
+ for (size_t i = 0; i < objects.size(); ++i) {
+ ScopedLocalRef<jobject> object(env, AddLocalReference<jobject>(env, objects[i]));
+ env->SetObjectArrayElement(result, i, object.get());
+ }
+ return result;
+}
+
+bool IsVisibleConstructor(Method* m, bool public_only) {
+ if (public_only && !m->IsPublic()) {
+ return false;
+ }
+ if (m->IsMiranda() || m->IsStatic()) {
+ return false;
+ }
+ if (m->GetName()->CharAt(0) != '<') {
+ return false;
+ }
+ m->InitJavaFields();
+ return true;
+}
+
+jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
+ Class* c = Decode<Class*>(env, javaClass);
+
+ std::vector<Method*> constructors;
+ for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+ Method* m = c->GetDirectMethod(i);
+ if (IsVisibleConstructor(m, publicOnly)) {
+ constructors.push_back(m);
+ }
+ }
+
+ return ToArray(env, "java/lang/reflect/Constructor", constructors);
+}
+
+bool IsVisibleField(Field* f, bool public_only) {
+ if (public_only && ~f->IsPublic()) {
+ return false;
+ }
+ f->InitJavaFields();
+ return true;
+}
+
+jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
+ Class* c = Decode<Class*>(env, javaClass);
+
+ std::vector<Field*> fields;
+ for (size_t i = 0; i < c->NumInstanceFields(); ++i) {
+ Field* f = c->GetInstanceField(i);
+ if (IsVisibleField(f, publicOnly)) {
+ fields.push_back(f);
+ }
+ }
+ for (size_t i = 0; i < c->NumStaticFields(); ++i) {
+ Field* f = c->GetStaticField(i);
+ if (IsVisibleField(f, publicOnly)) {
+ fields.push_back(f);
+ }
+ }
+
+ return ToArray(env, "java/lang/reflect/Field", fields);
+}
+
+bool IsVisibleMethod(Method* m, bool public_only) {
+ if (public_only && !m->IsPublic()) {
+ return false;
+ }
+ if (m->IsMiranda()) {
+ return false;
+ }
+ if (m->GetName()->CharAt(0) == '<') {
+ return false;
+ }
+ m->InitJavaFields();
+ return true;
+}
+
+jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
+ Class* c = Decode<Class*>(env, javaClass);
+
+ std::vector<Method*> methods;
+ for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
+ Method* m = c->GetVirtualMethod(i);
+ if (IsVisibleMethod(m, publicOnly)) {
+ methods.push_back(m);
+ }
+ }
+ for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+ Method* m = c->GetDirectMethod(i);
+ if (IsVisibleMethod(m, publicOnly)) {
+ methods.push_back(m);
+ }
+ }
+
+ return ToArray(env, "java/lang/reflect/Method", methods);
+}
+
jboolean Class_desiredAssertionStatus(JNIEnv* env, jobject javaThis) {
return JNI_FALSE;
}
@@ -115,15 +217,17 @@
String* name = Decode<String*>(env, jname);
DCHECK(name->IsString());
- for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
+ for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
Field* f = klass->GetInstanceField(i);
if (f->GetName()->Equals(name)) {
+ f->InitJavaFields();
return AddLocalReference<jclass>(env, f);
}
}
for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
Field* f = klass->GetStaticField(i);
if (f->GetName()->Equals(name)) {
+ f->InitJavaFields();
return AddLocalReference<jclass>(env, f);
}
}
@@ -319,10 +423,10 @@
NATIVE_METHOD(Class, getClassLoader, "(Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
- //NATIVE_METHOD(Class, getDeclaredConstructors, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;"),
+ NATIVE_METHOD(Class, getDeclaredConstructors, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;"),
NATIVE_METHOD(Class, getDeclaredField, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"),
- //NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
- //NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
+ NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
+ NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
NATIVE_METHOD(Class, getDeclaringClass, "()Ljava/lang/Class;"),
//NATIVE_METHOD(Class, getEnclosingClass, "()Ljava/lang/Class;"),
NATIVE_METHOD(Class, getEnclosingConstructor, "()Ljava/lang/reflect/Constructor;"),