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.
Most of these regressions were simply due to testing a lot more stuff,
esp. annotations and reflection, revealing holes in the Android
compatibility code. There are still some holes, but at least the
suite is passing (except for a fragile test in Serialize.java which I
will open an issue for).
Sorry this is such a big commit; there was more to address than I
initially expected.
Method.invoke should initialize its class before invoking the method,
throwing an ExceptionInInitializerError if it fails, without wrapping
said error in an InvocationTargetException.
Also, we must initialize ExceptionInInitializerError.exception when
throwing instances from the VM, since OpenJDK's
ExceptionInInitializerError.getCause uses the exception field, not the
cause field.
Inner classes can have inner classes, but getDeclaredClasses() is
supposed to list *only* the immediate inner classes.
Example: if class Reflection contains a class Hello that contains
a class World, Reflection.class.getDeclaredClasses() must not
include World in its result.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
We should pass the method of the original interface to the
InvocationHandler, not the method of the interface.
That way, proxy instances of annotations will have easy access to
the default values.
This happens to be compatible with the way Oracle Java does it, too.
To accomplish our goal, we keep a global map between proxy classes and
Method references and assign the appropriate list to a field of the
Proxy subclass. This means that we now have to call the super-class
constructor in the generated constructor (which is the correct thing to
do anyway... ;-)).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Proxies implement interfaces whose methods *must* be public, as per the
specification of the Java language.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
When the class whose field is to be inspected has no annotations at all,
at least my javac here (1.6.0_51 on MacOSX) does not produce any class
addendum.
Therefore, let's verify that the addendum is not null before proceeding.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Previously, I used a shell script to extract modification date ranges
from the Git history, but that was complicated and unreliable, so now
every file just gets the same year range in its copyright header. If
someone needs to know when a specific file was modified and by whom,
they can look at the Git history themselves; no need to include it
redundantly in the header.
This mainly moves several sun.misc.Unsafe method implementations from
classpath-openjdk.cpp to builtin.cpp so that the Avian and Android
builds can use them.
It also replaces FinalizerReference.finalizeAllEnqueued with a no-op,
since the real implementations assumes too much about how the VM
handles (or delegates) finalization.
Java requires that NaNs be converted to zero and that numbers at or
beyond the limits of integer representation be clamped to the largest
or smallest value that can be represented, respectively.
Our implementation uses Object.wait(long) to implement Thread.sleep,
which had the side effect of interpreting zero as infinity. However,
for Thread.sleep, zero just means zero. I assume that doesn't mean
"don't sleep at all", though, or else the app wouldn't have called
Thread.sleep in the first place, so this patch sleeps for one
millisecond when zero is passed -- just enough to yield the processor
for a bit. Thread.yield might be a better choice in this case, but I
assume the app would have called that directly if that's what it
wanted.
We were not properly converting dots to slashes internally for package names
and we did not properly handle Method.getAnnotations and
Method.getAnnotation(Class<T>) on methods without any annotations.
Added some tests to cover these cases.