--- a/hotspot/test/runtime/jni/PrivateInterfaceMethods/PrivateInterfaceMethods.java Tue Oct 18 16:15:03 2016 -0700
+++ b/hotspot/test/runtime/jni/PrivateInterfaceMethods/PrivateInterfaceMethods.java Wed Oct 19 00:16:02 2016 +0000
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 8081800
+ * @bug 8081800 8165827
* @summary Add JNI invocation tests for private interface methods
* @run main/native PrivateInterfaceMethods
*/
@@ -34,19 +34,23 @@
}
static native int callIntVoid(Object target, String definingClassName, String methodName, boolean virtual);
+ static native void lookupIntVoid(String definingClassName, String methodName);
static interface A {
static final int AmResult = 1;
private int m() { return AmResult; }
+ private int onlyA() { return 0; }
}
static interface B extends A {
// No m() here
+ private int onlyB() { return 0; }
}
static interface C extends B {
static final int CmResult = 2;
private int m() { return CmResult; } // unrelated to A.m
+ private int onlyC() { return 0; }
}
public static class Impl implements C {
@@ -62,6 +66,29 @@
}
public static void main(String[] args) {
+
+ // JNI getMethodID only works for methods declared in or inherited by a type.
+ // Private interface methods are not inherited and so should only be found
+ // in the declaring interface.
+
+ lookup(A.class.getName(), "onlyA", null); // should succeed
+ lookup(B.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+ lookup(C.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+ lookup(Impl.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+ lookup(Impl2.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+
+ lookup(B.class.getName(), "onlyB", null); // should succeed
+ lookup(A.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+ lookup(C.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+ lookup(Impl.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+ lookup(Impl2.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+
+ lookup(C.class.getName(), "onlyC", null); // should succeed
+ lookup(A.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+ lookup(B.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+ lookup(Impl.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+ lookup(Impl2.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+
Impl impl = new Impl();
// Note: JNI doesn't enforce access control so we can make
@@ -106,6 +133,25 @@
test(impl2, Impl2.class.getName(), "m", -1, false, NoSuchMethodError.class);
}
+ static void lookup(String definingClass, String method, Class<?> expectedException) {
+
+ String desc = "Lookup of " + definingClass + "." + method;
+ try {
+ lookupIntVoid(definingClass, method);
+ if (expectedException != null)
+ throw new Error(desc + " succeeded - but expected exception "
+ + expectedException.getSimpleName());
+ System.out.println(desc + " - passed");
+ }
+ catch (Throwable t) {
+ if (t.getClass() != expectedException)
+ throw new Error(desc + " failed: got exception " + t + " but expected exception "
+ + expectedException.getSimpleName());
+ else
+ System.out.println(desc + " threw " + expectedException.getSimpleName() + " as expected");
+ }
+ }
+
static void test(Object target, String definingClass, String method,
int expected, boolean virtual, Class<?> expectedException) {
@@ -115,16 +161,19 @@
try {
int res = callIntVoid(target, definingClass, method, virtual);
if (expectedException != null)
- throw new Error(desc + " succeeded - but expected exception " + expectedException.getSimpleName());
+ throw new Error(desc + " succeeded - but expected exception "
+ + expectedException.getSimpleName());
if (res != expected)
throw new Error(desc + " got wrong result: " + res + " instead of " + expected);
System.out.println(desc + " - passed");
}
catch (Throwable t) {
if (t.getClass() != expectedException)
- throw new Error(desc + " failed", t);
+ throw new Error(desc + " failed: got exception " + t + " but expected exception "
+ + expectedException.getSimpleName());
else
System.out.println(desc + " threw " + expectedException.getSimpleName() + " as expected");
}
}
+
}
--- a/hotspot/test/runtime/jni/PrivateInterfaceMethods/libPrivateInterfaceMethods.c Tue Oct 18 16:15:03 2016 -0700
+++ b/hotspot/test/runtime/jni/PrivateInterfaceMethods/libPrivateInterfaceMethods.c Wed Oct 19 00:16:02 2016 +0000
@@ -52,3 +52,27 @@
else
return (*env)->CallIntMethod(env, impl, m_id);
}
+
+// Private interface methods lookup test
+JNIEXPORT void JNICALL
+Java_PrivateInterfaceMethods_lookupIntVoid(JNIEnv *env, jclass unused,
+ jstring defining_class_name, jstring method_name) {
+
+ // Lookup int method_name() in defining_class_name
+
+ jmethodID m_id = NULL;
+ jclass clazz = NULL;
+ const char* name = NULL;
+
+ name = (*env)->GetStringUTFChars(env, defining_class_name, NULL);
+ if (name == NULL) return;
+ clazz = (*env)->FindClass(env, name);
+ (*env)->ReleaseStringUTFChars(env, defining_class_name, name);
+ if ((*env)->ExceptionCheck(env)) return;
+
+ name = (*env)->GetStringUTFChars(env, method_name, NULL);
+ if (name == NULL) return;
+ m_id = (*env)->GetMethodID(env, clazz, name, "()I");
+ (*env)->ReleaseStringUTFChars(env, method_name, name);
+}
+