mirror of
https://github.com/corda/corda.git
synced 2025-03-17 17:45:17 +00:00
match Java's schizophrenic concept of inner class access modifiers
An inner class has two sets of modifier flags: one is declared in the usual place in the class file and the other is part of the InnerClasses attribute. Not only is that redundant, but they can contradict, and the VM can't just pick one and roll with it. Instead, Class.getModifiers must return the InnerClasses version, whereas reflection must check the top-level version. So even if Class.getModifiers says the class is protected, it might still be public for the purpose of reflection depending on what the InnerClasses attribute says. Crazy? Yes.
This commit is contained in:
parent
6ed98b85f8
commit
25d69f38ee
@ -30,6 +30,7 @@ import java.lang.annotation.Annotation;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
@ -439,6 +440,19 @@ public final class Class <T> implements Type, AnnotatedElement {
|
||||
}
|
||||
|
||||
public int getModifiers() {
|
||||
ClassAddendum addendum = vmClass.addendum;
|
||||
if (addendum != null) {
|
||||
InnerClassReference[] table = addendum.innerClassTable;
|
||||
if (table != null) {
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
InnerClassReference reference = table[i];
|
||||
if (Arrays.equals(vmClass.name, reference.inner)) {
|
||||
return reference.flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vmClass.flags;
|
||||
}
|
||||
|
||||
|
@ -746,6 +746,28 @@ getDeclaringClass(Thread* t, object c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned
|
||||
classModifiers(Thread* t, object c)
|
||||
{
|
||||
object addendum = classAddendum(t, c);
|
||||
if (addendum) {
|
||||
object table = classAddendumInnerClassTable(t, addendum);
|
||||
if (table) {
|
||||
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
|
||||
object reference = arrayBody(t, table, i);
|
||||
if (0 == strcmp
|
||||
(&byteArrayBody(t, className(t, c), 0),
|
||||
&byteArrayBody(t, innerClassReferenceInner(t, reference), 0)))
|
||||
{
|
||||
return innerClassReferenceFlags(t, reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return classFlags(t, c);
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#endif//CLASSPATH_COMMON_H
|
||||
|
@ -1634,7 +1634,7 @@ extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||
Avian_java_lang_Class_getModifiers
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
return classFlags
|
||||
return classModifiers
|
||||
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[0])));
|
||||
}
|
||||
|
||||
|
@ -4123,12 +4123,19 @@ EXPORT(JVM_GetComponentType)(Thread* t, jclass c)
|
||||
return reinterpret_cast<jclass>(run(t, jvmGetComponentType, arguments));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
jvmGetClassModifiers(Thread* t, uintptr_t* arguments)
|
||||
{
|
||||
return classModifiers
|
||||
(t, jclassVmClass(t, *reinterpret_cast<jobject>(arguments[0])));
|
||||
}
|
||||
|
||||
extern "C" AVIAN_EXPORT jint JNICALL
|
||||
EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c) };
|
||||
|
||||
return classFlags(t, jclassVmClass(t, *c));
|
||||
return run(t, jvmGetClassModifiers, arguments);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -4349,7 +4356,9 @@ EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c,
|
||||
extern "C" AVIAN_EXPORT jint JNICALL
|
||||
EXPORT(JVM_GetClassAccessFlags)(Thread* t, jclass c)
|
||||
{
|
||||
return EXPORT(JVM_GetClassModifiers)(t, c);
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
return classFlags(t, jclassVmClass(t, *c));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -2314,13 +2314,6 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
|
||||
flags);
|
||||
|
||||
set(t, table, ArrayBody + (i * BytesPerWord), reference);
|
||||
|
||||
if (0 == strcmp
|
||||
(&byteArrayBody(t, className(t, class_), 0),
|
||||
&byteArrayBody(t, innerClassReferenceInner(t, reference), 0)))
|
||||
{
|
||||
classFlags(t, class_) = flags;
|
||||
}
|
||||
}
|
||||
|
||||
object addendum = getClassAddendum(t, class_, pool);
|
||||
|
@ -49,8 +49,9 @@ public class Reflection {
|
||||
private static void innerClasses() throws Exception {
|
||||
Class c = Reflection.class;
|
||||
Class[] inner = c.getDeclaredClasses();
|
||||
expect(1 == inner.length);
|
||||
expect(Hello.class == inner[0]);
|
||||
expect(2 == inner.length);
|
||||
expect(Hello.class == inner[0]
|
||||
|| Hello.class == inner[1]);
|
||||
}
|
||||
|
||||
private int egads;
|
||||
@ -236,6 +237,14 @@ public class Reflection {
|
||||
|
||||
expect((Foo.class.getMethod("toString").getModifiers()
|
||||
& Modifier.PUBLIC) != 0);
|
||||
|
||||
expect(avian.TestReflection.get(Baz.class.getField("foo"), new Baz())
|
||||
.equals(42));
|
||||
expect((Baz.class.getModifiers() & Modifier.PUBLIC) == 0);
|
||||
}
|
||||
|
||||
protected static class Baz {
|
||||
public int foo = 42;
|
||||
}
|
||||
}
|
||||
|
||||
|
9
test/avian/TestReflection.java
Normal file
9
test/avian/TestReflection.java
Normal file
@ -0,0 +1,9 @@
|
||||
package avian;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class TestReflection {
|
||||
public static Object get(Field field, Object target) throws Exception {
|
||||
return field.get(target);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user