Commit 0618281a by Andrew Haley Committed by Andrew Haley

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
parent debac9f4
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:
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>
* sun/reflect/annotation/AnnotationInvocationHandler.java:
Whitespace only changes. Whitespace only changes.
2007-03-02 Andrew Haley <aph@redhat.com> 2007-03-02 Andrew Haley <aph@redhat.com>
......
...@@ -7194,7 +7194,7 @@ sun/reflect/Reflection.java ...@@ -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 \
......
...@@ -8373,7 +8373,7 @@ sun/reflect.list: $(sun_reflect_source_files) ...@@ -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 \
......
...@@ -29,19 +29,19 @@ class sun::reflect::annotation::AnnotationInvocationHandler : public ::java::lan ...@@ -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:
......
/* 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.
...@@ -8,7 +8,7 @@ GNU Classpath is free software; you can redistribute it and/or modify ...@@ -8,7 +8,7 @@ GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU Classpath is distributed in the hope that it will be useful, but GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
...@@ -43,9 +43,9 @@ import java.lang.annotation.Annotation; ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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
h += deepHashCode(val) ^ 127 * key.hashCode(); {
Object val
= invoke(null,
type.getDeclaredMethod((String)key, (Class[])null),
(Object[])null);
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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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, if (val.getClass().isArray())
val.getClass().getName()); val = coerce((Object[])val, method.getReturnType());
} }
if (val.getClass().isArray()) catch (ArrayStoreException _)
{ {
val = arrayClone(val); 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 ...@@ -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");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment