/* sun.reflect.annotation.AnnotationInvocationHandler
- Copyright (C) 2006
+ Copyright (C) 2006, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
import java.lang.annotation.AnnotationTypeMismatchException;
import java.lang.annotation.IncompleteAnnotationException;
import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
implements InvocationHandler, Serializable
{
private static final long serialVersionUID = 6182022883658399397L;
- private final Class type;
- private final Map memberValues;
+ private final Class<? extends Annotation> type;
+ private final Map<String, ?> memberValues;
/**
* Construct a new invocation handler for an annotation proxy.
* Note that the VM is responsible for filling the memberValues map
* 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.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())
{
* (can) use different representations of annotations that reuse this
* method.
*/
- public static boolean equals(Class type, Map memberValues, Object other)
+ public boolean equals(Object proxy, Object other)
{
if (type.isInstance(other))
{
for (int i = 0; i < methods.length; i++)
{
String key = methods[i].getName();
- Object val = methods[i].invoke(other, new Object[0]);
- if (! deepEquals(memberValues.get(key), val))
+ Object val = methods[i].invoke(other, (Object[])null);
+ Object thisVal
+ = invoke(proxy,
+ methods[i],
+ (Object[])null);
+ if (! deepEquals(thisVal, val))
{
return false;
}
return true;
}
}
- catch (IllegalAccessException _)
- {
- // Ignore exception, like the JDK
- }
- catch (InvocationTargetException _)
+ catch (Throwable _)
{
// Ignore exception, like the JDK
}
* (can) use different representations of annotations that reuse this
* method.
*/
- public static int hashCode(Class type, Map memberValues)
+ public int hashCode()
{
int h = 0;
Iterator iter = memberValues.keySet().iterator();
while (iter.hasNext())
{
Object key = iter.next();
- Object val = memberValues.get(key);
- h += deepHashCode(val) ^ 127 * key.hashCode();
+ try
+ {
+ Object val
+ = invoke(null,
+ type.getDeclaredMethod((String)key, (Class[])null),
+ (Object[])null);
+ h += deepHashCode(val) ^ 127 * key.hashCode();
+ }
+ catch (Throwable _)
+ {
+ }
}
return h;
}
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[])
return Arrays.toString((Object[]) obj);
* (can) use different representations of annotations that reuse this
* method.
*/
- public static String toString(Class type, Map memberValues)
+ public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append('@').append(type.getName()).append('(');
return sb.toString();
}
+
private static Class getBoxedReturnType(Method method)
{
Class returnType = method.getReturnType();
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[])
- return ((boolean[]) obj).clone();
+ if (! val.getClass().isArray())
+ return val;
- if (obj instanceof byte[])
- return ((byte[]) obj).clone();
+ Object[] srcArray = (Object[])val;
+ final int len = srcArray.length;
- if (obj instanceof char[])
- return ((char[]) obj).clone();
+ if (dstType.getComponentType().isPrimitive())
+ {
+ 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[])
- return ((short[]) obj).clone();
+ if (dstType == byte[].class)
+ {
+ byte[] dst = new byte[len];
+ for (int i = 0; i < len; i++)
+ dst[i] = (Byte)srcArray[i];
+ return dst;
+ }
- if (obj instanceof int[])
- return ((int[]) obj).clone();
+ if (dstType == char[].class)
+ {
+ char[] dst = new char[len];
+ for (int i = 0; i < len; i++)
+ dst[i] = (Character)srcArray[i];
+ return dst;
+ }
- if (obj instanceof float[])
- return ((float[]) obj).clone();
+ if (dstType == short[].class)
+ {
+ short[] dst = new short[len];
+ for (int i = 0; i < len; i++)
+ dst[i] = (Short)srcArray[i];
+ return dst;
+ }
- if (obj instanceof long[])
- return ((long[]) obj).clone();
+ if (dstType == int[].class)
+ {
+ int[] dst = new int[len];
+ for (int i = 0; i < len; i++)
+ dst[i] = (Integer)srcArray[i];
+ return dst;
+ }
- if (obj instanceof double[])
- return ((double[]) obj).clone();
+ if (dstType == long[].class)
+ {
+ long[] dst = new long[len];
+ for (int i = 0; i < len; i++)
+ dst[i] = (Long)srcArray[i];
+ return dst;
+ }
- if (obj instanceof Object[])
- return ((Object[]) obj).clone();
+ if (dstType == float[].class)
+ {
+ 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)
throws Throwable
{
String methodName = method.getName().intern();
+
if (args == null || args.length == 0)
{
if (methodName == "toString")
{
- return toString(type, memberValues);
+ return toString();
}
else if (methodName == "hashCode")
{
- return Integer.valueOf(hashCode(type, memberValues));
+ return Integer.valueOf(hashCode());
}
else if (methodName == "annotationType")
{
{
throw new IncompleteAnnotationException(type, methodName);
}
- if (! getBoxedReturnType(method).isInstance(val))
+ try
{
- throw new AnnotationTypeMismatchException(method,
- val.getClass().getName());
+ if (val.getClass().isArray())
+ 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;
}
}
{
if (methodName == "equals")
{
- return Boolean.valueOf(equals(type, memberValues, args[0]));
+ return Boolean.valueOf(equals(proxy, args[0]));
}
}
throw new InternalError("Invalid annotation proxy");