AnnotationInvocationHandler.java: Generify in a few places.

2007-03-02  Andrew Haley  <aph@redhat.com>

        * sun/reflect/annotation/AnnotationInvocationHandler.java:
        Generify in a few places.
        (equals): Rewrite to use invoke on local proxy.
        (deepToString): Remove most of it.
        (toString): Make nonstatic.
        (arrayClone): Delete.
        (coerce): New method.
        (invoke): Rewrite to handle gcj's structures correctly.
        * java/lang/natClass.cc (getDeclaredAnnotations): Fix test for
        null loader.
        * sources.am: Regenerate.
        * Makefile.am: Likewise.

From-SVN: r122483
This commit is contained in:
Andrew Haley 2007-03-02 19:05:57 +00:00 committed by Andrew Haley
parent debac9f40d
commit 0618281a42
6 changed files with 141 additions and 81 deletions

View File

@ -1,3 +1,18 @@
2007-03-02 Andrew Haley <aph@redhat.com>
* sun/reflect/annotation/AnnotationInvocationHandler.java:
Generify in a few places.
(equals): Rewrite to use invoke on local proxy.
(deepToString): Remove most of it.
(toString): Make nonstatic.
(arrayClone): Delete.
(coerce): New method.
(invoke): Rewrite to handle gcj's structures correctly.
* java/lang/natClass.cc (getDeclaredAnnotations): Fix test for
null loader.
* sources.am: Regenerate.
* Makefile.am: Likewise.
2007-03-02 Andrew Haley <aph@redhat.com> 2007-03-02 Andrew Haley <aph@redhat.com>
* sun/reflect/annotation/AnnotationInvocationHandler.java: * sun/reflect/annotation/AnnotationInvocationHandler.java:

View File

@ -7194,7 +7194,7 @@ sun/reflect/Reflection.java
sun_reflect_header_files = $(patsubst %.java,%.h,$(sun_reflect_source_files)) sun_reflect_header_files = $(patsubst %.java,%.h,$(sun_reflect_source_files))
sun_reflect_annotation_source_files = \ sun_reflect_annotation_source_files = \
classpath/sun/reflect/annotation/AnnotationInvocationHandler.java \ sun/reflect/annotation/AnnotationInvocationHandler.java \
classpath/sun/reflect/annotation/AnnotationParser.java \ classpath/sun/reflect/annotation/AnnotationParser.java \
classpath/sun/reflect/annotation/AnnotationType.java \ classpath/sun/reflect/annotation/AnnotationType.java \
classpath/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java \ classpath/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java \

View File

@ -8373,7 +8373,7 @@ sun/reflect.list: $(sun_reflect_source_files)
sun_reflect_annotation_source_files = \ sun_reflect_annotation_source_files = \
classpath/sun/reflect/annotation/AnnotationInvocationHandler.java \ sun/reflect/annotation/AnnotationInvocationHandler.java \
classpath/sun/reflect/annotation/AnnotationParser.java \ classpath/sun/reflect/annotation/AnnotationParser.java \
classpath/sun/reflect/annotation/AnnotationType.java \ classpath/sun/reflect/annotation/AnnotationType.java \
classpath/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java \ classpath/sun/reflect/annotation/EnumConstantNotPresentExceptionProxy.java \

View File

@ -29,19 +29,19 @@ class sun::reflect::annotation::AnnotationInvocationHandler : public ::java::lan
public: public:
AnnotationInvocationHandler(::java::lang::Class *, ::java::util::Map *); AnnotationInvocationHandler(::java::lang::Class *, ::java::util::Map *);
static ::java::lang::annotation::Annotation * create(::java::lang::Class *, ::java::util::Map *); static ::java::lang::annotation::Annotation * create(::java::lang::Class *, ::java::util::Map *);
static jboolean equals(::java::lang::Class *, ::java::util::Map *, ::java::lang::Object *); jboolean equals(::java::lang::Object *, ::java::lang::Object *);
private: private:
static jboolean deepEquals(::java::lang::Object *, ::java::lang::Object *); static jboolean deepEquals(::java::lang::Object *, ::java::lang::Object *);
static jint deepHashCode(::java::lang::Object *); static jint deepHashCode(::java::lang::Object *);
public: public:
static jint hashCode(::java::lang::Class *, ::java::util::Map *); jint hashCode();
private: private:
static ::java::lang::String * deepToString(::java::lang::Object *); static ::java::lang::String * deepToString(::java::lang::Object *);
public: public:
static ::java::lang::String * toString(::java::lang::Class *, ::java::util::Map *); ::java::lang::String * toString();
private: private:
static ::java::lang::Class * getBoxedReturnType(::java::lang::reflect::Method *); static ::java::lang::Class * getBoxedReturnType(::java::lang::reflect::Method *);
::java::lang::Object * arrayClone(::java::lang::Object *); ::java::lang::Object * coerce(::java::lang::Object *, ::java::lang::Class *);
public: public:
::java::lang::Object * invoke(::java::lang::Object *, ::java::lang::reflect::Method *, JArray< ::java::lang::Object * > *); ::java::lang::Object * invoke(::java::lang::Object *, ::java::lang::reflect::Method *, JArray< ::java::lang::Object * > *);
private: private:

View File

@ -1,5 +1,5 @@
/* sun.reflect.annotation.AnnotationInvocationHandler /* sun.reflect.annotation.AnnotationInvocationHandler
Copyright (C) 2006 Copyright (C) 2006, 2007
Free Software Foundation, Inc. Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -43,9 +43,9 @@ import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.AnnotationTypeMismatchException;
import java.lang.annotation.IncompleteAnnotationException; import java.lang.annotation.IncompleteAnnotationException;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.lang.reflect.Array;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
@ -62,21 +62,21 @@ public final class AnnotationInvocationHandler
implements InvocationHandler, Serializable implements InvocationHandler, Serializable
{ {
private static final long serialVersionUID = 6182022883658399397L; private static final long serialVersionUID = 6182022883658399397L;
private final Class type; private final Class<? extends Annotation> type;
private final Map memberValues; private final Map<String, ?> memberValues;
/** /**
* Construct a new invocation handler for an annotation proxy. * Construct a new invocation handler for an annotation proxy.
* Note that the VM is responsible for filling the memberValues map * Note that the VM is responsible for filling the memberValues map
* with the default values of all the annotation members. * with the default values of all the annotation members.
*/ */
public AnnotationInvocationHandler(Class type, Map memberValues) public AnnotationInvocationHandler(Class<? extends Annotation> type, Map memberValues)
{ {
this.type = type; this.type = type;
this.memberValues = memberValues; this.memberValues = (Map<String, ?>)memberValues;
} }
public static Annotation create(Class type, Map memberValues) public static Annotation create(Class<? extends Annotation> type, Map memberValues)
{ {
for (Method m : type.getDeclaredMethods()) for (Method m : type.getDeclaredMethods())
{ {
@ -106,7 +106,7 @@ public final class AnnotationInvocationHandler
* (can) use different representations of annotations that reuse this * (can) use different representations of annotations that reuse this
* method. * method.
*/ */
public static boolean equals(Class type, Map memberValues, Object other) public boolean equals(Object proxy, Object other)
{ {
if (type.isInstance(other)) if (type.isInstance(other))
{ {
@ -118,8 +118,12 @@ public final class AnnotationInvocationHandler
for (int i = 0; i < methods.length; i++) for (int i = 0; i < methods.length; i++)
{ {
String key = methods[i].getName(); String key = methods[i].getName();
Object val = methods[i].invoke(other, new Object[0]); Object val = methods[i].invoke(other, (Object[])null);
if (! deepEquals(memberValues.get(key), val)) Object thisVal
= invoke(proxy,
methods[i],
(Object[])null);
if (! deepEquals(thisVal, val))
{ {
return false; return false;
} }
@ -127,11 +131,7 @@ public final class AnnotationInvocationHandler
return true; return true;
} }
} }
catch (IllegalAccessException _) catch (Throwable _)
{
// Ignore exception, like the JDK
}
catch (InvocationTargetException _)
{ {
// Ignore exception, like the JDK // Ignore exception, like the JDK
} }
@ -217,45 +217,30 @@ public final class AnnotationInvocationHandler
* (can) use different representations of annotations that reuse this * (can) use different representations of annotations that reuse this
* method. * method.
*/ */
public static int hashCode(Class type, Map memberValues) public int hashCode()
{ {
int h = 0; int h = 0;
Iterator iter = memberValues.keySet().iterator(); Iterator iter = memberValues.keySet().iterator();
while (iter.hasNext()) while (iter.hasNext())
{ {
Object key = iter.next(); Object key = iter.next();
Object val = memberValues.get(key); try
{
Object val
= invoke(null,
type.getDeclaredMethod((String)key, (Class[])null),
(Object[])null);
h += deepHashCode(val) ^ 127 * key.hashCode(); h += deepHashCode(val) ^ 127 * key.hashCode();
} }
catch (Throwable _)
{
}
}
return h; return h;
} }
private static String deepToString(Object obj) private static String deepToString(Object obj)
{ {
if (obj instanceof boolean[])
return Arrays.toString((boolean[]) obj);
if (obj instanceof byte[])
return Arrays.toString((byte[]) obj);
if (obj instanceof char[])
return Arrays.toString((char[]) obj);
if (obj instanceof short[])
return Arrays.toString((short[]) obj);
if (obj instanceof int[])
return Arrays.toString((int[]) obj);
if (obj instanceof float[])
return Arrays.toString((float[]) obj);
if (obj instanceof long[])
return Arrays.toString((long[]) obj);
if (obj instanceof double[])
return Arrays.toString((double[]) obj);
if (obj instanceof Object[]) if (obj instanceof Object[])
return Arrays.toString((Object[]) obj); return Arrays.toString((Object[]) obj);
@ -267,7 +252,7 @@ public final class AnnotationInvocationHandler
* (can) use different representations of annotations that reuse this * (can) use different representations of annotations that reuse this
* method. * method.
*/ */
public static String toString(Class type, Map memberValues) public String toString()
{ {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append('@').append(type.getName()).append('('); sb.append('@').append(type.getName()).append('(');
@ -284,6 +269,7 @@ public final class AnnotationInvocationHandler
return sb.toString(); return sb.toString();
} }
private static Class getBoxedReturnType(Method method) private static Class getBoxedReturnType(Method method)
{ {
Class returnType = method.getReturnType(); Class returnType = method.getReturnType();
@ -315,51 +301,106 @@ public final class AnnotationInvocationHandler
return returnType; return returnType;
} }
private Object arrayClone(Object obj) // This is slightly awkward. When the value of an annotation is an
// array, libgcj constructs an Object[], but the value() method
// returns an arrays of the appropriate primitive type. We should
// perhaps save the resulting array rather than the Object[].
private Object coerce(Object val, Class dstType)
throws ArrayStoreException
{ {
if (obj instanceof boolean[]) if (! val.getClass().isArray())
return ((boolean[]) obj).clone(); return val;
if (obj instanceof byte[]) Object[] srcArray = (Object[])val;
return ((byte[]) obj).clone(); final int len = srcArray.length;
if (obj instanceof char[]) if (dstType.getComponentType().isPrimitive())
return ((char[]) obj).clone(); {
if (dstType == boolean[].class)
{
boolean[] dst = new boolean[len];
for (int i = 0; i < len; i++)
dst[i] = (Boolean)srcArray[i];
return dst;
}
if (obj instanceof short[]) if (dstType == byte[].class)
return ((short[]) obj).clone(); {
byte[] dst = new byte[len];
for (int i = 0; i < len; i++)
dst[i] = (Byte)srcArray[i];
return dst;
}
if (obj instanceof int[]) if (dstType == char[].class)
return ((int[]) obj).clone(); {
char[] dst = new char[len];
for (int i = 0; i < len; i++)
dst[i] = (Character)srcArray[i];
return dst;
}
if (obj instanceof float[]) if (dstType == short[].class)
return ((float[]) obj).clone(); {
short[] dst = new short[len];
for (int i = 0; i < len; i++)
dst[i] = (Short)srcArray[i];
return dst;
}
if (obj instanceof long[]) if (dstType == int[].class)
return ((long[]) obj).clone(); {
int[] dst = new int[len];
for (int i = 0; i < len; i++)
dst[i] = (Integer)srcArray[i];
return dst;
}
if (obj instanceof double[]) if (dstType == long[].class)
return ((double[]) obj).clone(); {
long[] dst = new long[len];
for (int i = 0; i < len; i++)
dst[i] = (Long)srcArray[i];
return dst;
}
if (obj instanceof Object[]) if (dstType == float[].class)
return ((Object[]) obj).clone(); {
float[] dst = new float[len];
for (int i = 0; i < len; i++)
dst[i] = (Float)srcArray[i];
return dst;
}
return obj; if (dstType == double[].class)
{
double[] dst = new double[len];
for (int i = 0; i < len; i++)
dst[i] = (Double)srcArray[i];
return dst;
}
}
Object dst = Array.newInstance(dstType.getComponentType(), len);
System.arraycopy((Object)srcArray, 0, dst, 0, len);
return dst;
} }
public Object invoke(Object proxy, Method method, Object[] args) public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable throws Throwable
{ {
String methodName = method.getName().intern(); String methodName = method.getName().intern();
if (args == null || args.length == 0) if (args == null || args.length == 0)
{ {
if (methodName == "toString") if (methodName == "toString")
{ {
return toString(type, memberValues); return toString();
} }
else if (methodName == "hashCode") else if (methodName == "hashCode")
{ {
return Integer.valueOf(hashCode(type, memberValues)); return Integer.valueOf(hashCode());
} }
else if (methodName == "annotationType") else if (methodName == "annotationType")
{ {
@ -372,15 +413,19 @@ public final class AnnotationInvocationHandler
{ {
throw new IncompleteAnnotationException(type, methodName); throw new IncompleteAnnotationException(type, methodName);
} }
if (! getBoxedReturnType(method).isInstance(val)) try
{ {
throw new AnnotationTypeMismatchException(method,
val.getClass().getName());
}
if (val.getClass().isArray()) if (val.getClass().isArray())
{ val = coerce((Object[])val, method.getReturnType());
val = arrayClone(val);
} }
catch (ArrayStoreException _)
{
throw new AnnotationTypeMismatchException
(method, val.getClass().getName());
}
if (! getBoxedReturnType(method).isInstance(val))
throw (new AnnotationTypeMismatchException
(method, val.getClass().getName()));
return val; return val;
} }
} }
@ -388,7 +433,7 @@ public final class AnnotationInvocationHandler
{ {
if (methodName == "equals") if (methodName == "equals")
{ {
return Boolean.valueOf(equals(type, memberValues, args[0])); return Boolean.valueOf(equals(proxy, args[0]));
} }
} }
throw new InternalError("Invalid annotation proxy"); throw new InternalError("Invalid annotation proxy");