I'm not checking this in yet.

I wrote a patch for the annotation inheritance bug (PR 28203) for the
gcj-eclipse branch of gcj.  I also fixed a buglet (IMO) in
AnnotationInvocationHandler, and added a helper 'create' method to
that class.

This patch ports this work back to Classpath.

The only trouble is, I had to break Class.getAnnotations() to make
this compile against cvs head -- the Inherited class doesn't exist
there and is required for proper operation of the code.  So, the real
patch can only work on the generics branch.

What would you prefer?  The hacked patch on the trunk and the real
patch on the branch?  No change on the trunk and the real patch on the
branch?  Something else?

Note that the 1.4-ification is much uglier than the original, too, as
the original used foreach.

Finally, this adds a new native method, Method.getDefaultValue.  Not
sure if that is best either; but I have noticed that our Method and
Field implementations are missing a number of things related to
annotations.

Tom

2006-10-18  Tom Tromey  <[EMAIL PROTECTED]>

        PR classpath/28203:
        * java/lang/Class.java (getAnnotations): Rewrote.
        * sun/reflect/annotation/AnnotationInvocationHandler.java (create):
        New method.
        (arrayClone): New method.
        (invoke): Clone array return results.
        * vm/reference/java/lang/reflect/Method.java (getDefaultValue): New
        native method.

Index: java/lang/Class.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Class.java,v
retrieving revision 1.49
diff -u -r1.49 Class.java
--- java/lang/Class.java        28 Apr 2006 13:43:02 -0000      1.49
+++ java/lang/Class.java        19 Oct 2006 04:52:57 -0000
@@ -66,6 +66,7 @@
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 
@@ -1514,15 +1515,29 @@
    */
   public Annotation[] getAnnotations()
   {
-    HashSet set = new HashSet();
-    set.addAll(Arrays.asList(getDeclaredAnnotations()));
-    Class[] interfaces = getInterfaces();
-    for (int i = 0; i < interfaces.length; i++)
-      set.addAll(Arrays.asList(interfaces[i].getAnnotations()));
-    Class superClass = getSuperclass();
-    if (superClass != null)
-      set.addAll(Arrays.asList(superClass.getAnnotations()));
-    return (Annotation[]) set.toArray(new Annotation[set.size()]);
+    HashMap/*<Class, Annotation>*/ map = new HashMap/*<Class, Annotation>*/();
+    Annotation[] as = getDeclaredAnnotations();
+    for (int i = 0; i < as.length; ++i)
+      {
+        Annotation a = as[i];
+        map.put(a.annotationType(), a);
+      }
+    for (Class s = getSuperclass();
+         s != null;
+         s = s.getSuperclass())
+      {
+        as = s.getAnnotations();
+        for (int i = 0; i < as.length; ++i)
+          {
+            Annotation a = as[i];
+            Class k = a.annotationType();
+            // FIXME: only generics has Inherited.
+            if (! map.containsKey(k) /* && 
k.isAnnotationPresent(Inherited.class) */)
+              map.put(k, a);
+          }
+      }
+    Collection/*<Annotation>*/ v = map.values();
+    return (Annotation[]) v.toArray(new Annotation[v.size()]);
   }
 
   /**
Index: sun/reflect/annotation/AnnotationInvocationHandler.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/sun/reflect/annotation/AnnotationInvocationHandler.java,v
retrieving revision 1.1
diff -u -r1.1 AnnotationInvocationHandler.java
--- sun/reflect/annotation/AnnotationInvocationHandler.java     9 Jun 2006 
06:59:21 -0000       1.1
+++ sun/reflect/annotation/AnnotationInvocationHandler.java     19 Oct 2006 
04:53:00 -0000
@@ -39,11 +39,13 @@
 package sun.reflect.annotation;
 
 import java.io.Serializable;
+import java.lang.annotation.Annotation;
 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.util.Arrays;
 import java.util.Iterator;
 import java.util.Map;
@@ -74,6 +76,26 @@
         this.memberValues = memberValues;
     }
 
+    public static Annotation create(Class type, Map memberValues)
+    {
+      Method[] ms = type.getDeclaredMethods();
+      for (int i = 0; i < ms.length; ++i)
+        {
+          Method m = ms[i];
+          String name = m.getName();
+          if (! memberValues.containsKey(name))
+            {
+              // FIXME: what to do about exceptions here?
+              memberValues.put(name, m.getDefaultValue());
+            }
+        }
+      AnnotationInvocationHandler handler
+        = new AnnotationInvocationHandler(type, memberValues);
+      return (Annotation) Proxy.newProxyInstance(type.getClassLoader(),
+                                                 new Class[] { type },
+                                                 handler);
+    }
+
     /**
      * Compare an instance of AnnotationInvocationHandler with another object.
      * Note that the other object does not have to be an
@@ -295,6 +317,38 @@
         return returnType;
     }
 
+    private Object arrayClone(Object obj)
+    {
+        if (obj instanceof boolean[])
+            return ((boolean[]) obj).clone();
+
+        if (obj instanceof byte[])
+            return ((byte[]) obj).clone();
+
+        if (obj instanceof char[])
+            return ((char[]) obj).clone();
+
+        if (obj instanceof short[])
+            return ((short[]) obj).clone();
+
+        if (obj instanceof int[])
+            return ((int[]) obj).clone();
+
+        if (obj instanceof float[])
+            return ((float[]) obj).clone();
+
+        if (obj instanceof long[])
+            return ((long[]) obj).clone();
+
+        if (obj instanceof double[])
+            return ((double[]) obj).clone();
+
+        if (obj instanceof Object[])
+            return ((Object[]) obj).clone();
+
+        return obj;
+    }
+
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable
     {
@@ -325,6 +379,10 @@
                     throw new AnnotationTypeMismatchException(method,
                         val.getClass().getName());
                 }
+                if (val.getClass().isArray())
+                {
+                    val = arrayClone(val);
+                }
                 return val;
             }
         }
Index: vm/reference/java/lang/reflect/Method.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/reflect/Method.java,v
retrieving revision 1.19
diff -u -r1.19 Method.java
--- vm/reference/java/lang/reflect/Method.java  22 Apr 2006 21:52:18 -0000      
1.19
+++ vm/reference/java/lang/reflect/Method.java  19 Oct 2006 04:53:00 -0000
@@ -450,5 +450,18 @@
     MethodSignatureParser p = new MethodSignatureParser(this, sig);
     return p.getGenericReturnType();
   }
+
+  /**
+   * If this method is an annotation method, returns the default
+   * value for the method.  If there is no default value, or if the
+   * method is not a member of an annotation type, returns null.
+   * Primitive types are wrapped.
+   *
+   * @throws TypeNotPresentException if the method returns a Class,
+   * and the class cannot be found
+   *
+   * @since 1.5
+   */
+  public native Object getDefaultValue();
 }
 

Reply via email to