8007072: Update Core Reflection for Type Annotations to match latest spec
authorjfranck
Mon, 30 Sep 2013 11:18:18 +0200
changeset 20481 2735b307d256
parent 20480 e515a2633774
child 20482 6dc1f81f522c
8007072: Update Core Reflection for Type Annotations to match latest spec 8022324: j.l.Class.getAnnotatedInterfaces() for array type returns wrong value 8024915: j.l.r.Executable.getAnnotatedReceiverType() should return null for static methods Summary: Update javadoc and implementation of reflection for type annotations to match latest spec Reviewed-by: darcy
jdk/src/share/classes/java/lang/Class.java
jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java
jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
jdk/src/share/classes/java/lang/reflect/AnnotatedType.java
jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java
jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java
jdk/src/share/classes/java/lang/reflect/Executable.java
jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java
jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedInterfaces.java
jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedReceiverType.java
jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java
--- a/jdk/src/share/classes/java/lang/Class.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/Class.java	Mon Sep 30 11:18:18 2013 +0200
@@ -3414,16 +3414,20 @@
     transient ClassValue.ClassValueMap classValueMap;
 
     /**
-     * Returns an AnnotatedType object that represents the use of a type to specify
-     * the superclass of the entity represented by this Class. (The <em>use</em> of type
-     * Foo to specify the superclass in '... extends Foo' is distinct from the
-     * <em>declaration</em> of type Foo.)
+     * Returns an {@code AnnotatedType} object that represents the use of a
+     * type to specify the superclass of the entity represented by this {@code
+     * Class} object. (The <em>use</em> of type Foo to specify the superclass
+     * in '...  extends Foo' is distinct from the <em>declaration</em> of type
+     * Foo.)
      *
-     * If this Class represents a class type whose declaration does not explicitly
-     * indicate an annotated superclass, the return value is null.
+     * <p> If this {@code Class} object represents a type whose declaration
+     * does not explicitly indicate an annotated superclass, then the return
+     * value is an {@code AnnotatedType} object representing an element with no
+     * annotations.
      *
-     * If this Class represents either the Object class, an interface type, an
-     * array type, a primitive type, or void, the return value is null.
+     * <p> If this {@code Class} represents either the {@code Object} class, an
+     * interface type, an array type, a primitive type, or void, the return
+     * value is {@code null}.
      *
      * @return an object representing the superclass
      * @since 1.8
@@ -3441,30 +3445,33 @@
     }
 
     /**
-     * Returns an array of AnnotatedType objects that represent the use of types to
-     * specify superinterfaces of the entity represented by this Class. (The <em>use</em>
-     * of type Foo to specify a superinterface in '... implements Foo' is
-     * distinct from the <em>declaration</em> of type Foo.)
+     * Returns an array of {@code AnnotatedType} objects that represent the use
+     * of types to specify superinterfaces of the entity represented by this
+     * {@code Class} object. (The <em>use</em> of type Foo to specify a
+     * superinterface in '... implements Foo' is distinct from the
+     * <em>declaration</em> of type Foo.)
      *
-     * If this Class represents a class, the return value is an array
-     * containing objects representing the uses of interface types to specify
-     * interfaces implemented by the class. The order of the objects in the
-     * array corresponds to the order of the interface types used in the
-     * 'implements' clause of the declaration of this Class.
+     * <p> If this {@code Class} object represents a class, the return value is
+     * an array containing objects representing the uses of interface types to
+     * specify interfaces implemented by the class. The order of the objects in
+     * the array corresponds to the order of the interface types used in the
+     * 'implements' clause of the declaration of this {@code Class} object.
      *
-     * If this Class represents an interface, the return value is an array
-     * containing objects representing the uses of interface types to specify
-     * interfaces directly extended by the interface. The order of the objects in
-     * the array corresponds to the order of the interface types used in the
-     * 'extends' clause of the declaration of this Class.
+     * <p> If this {@code Class} object represents an interface, the return
+     * value is an array containing objects representing the uses of interface
+     * types to specify interfaces directly extended by the interface. The
+     * order of the objects in the array corresponds to the order of the
+     * interface types used in the 'extends' clause of the declaration of this
+     * {@code Class} object.
      *
-     * If this Class represents a class or interface whose declaration does not
-     * explicitly indicate any annotated superinterfaces, the return value is an
+     * <p> If this {@code Class} object represents a class or interface whose
+     * declaration does not explicitly indicate any annotated superinterfaces,
+     * the return value is an array of length 0.
+     *
+     * <p> If this {@code Class} object represents either the {@code Object}
+     * class, an array type, a primitive type, or void, the return value is an
      * array of length 0.
      *
-     * If this Class represents either the Object class, an array type, a
-     * primitive type, or void, the return value is an array of length 0.
-     *
      * @return an array representing the superinterfaces
      * @since 1.8
      */
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java	Mon Sep 30 11:18:18 2013 +0200
@@ -27,17 +27,18 @@
 
 
 /**
- * AnnotatedArrayType represents the use of an array type, whose component
- * type may itself represent the annotated use of a type.
+ * {@code AnnotatedArrayType} represents the potentially annotated use of an
+ * array type, whose component type may itself represent the annotated use of a
+ * type.
  *
  * @since 1.8
  */
 public interface AnnotatedArrayType extends AnnotatedType {
 
     /**
-     * Returns the annotated generic component type of this array type.
+     * Returns the potentially annotated generic component type of this array type.
      *
-     * @return the annotated generic component type of this array type
+     * @return the potentially annotated generic component type of this array type
      */
     AnnotatedType  getAnnotatedGenericComponentType();
 }
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java	Mon Sep 30 11:18:18 2013 +0200
@@ -26,17 +26,18 @@
 package java.lang.reflect;
 
 /**
- * AnnotatedParameterizedType represents the use of a parameterized type,
- * whose type arguments may themselves represent annotated uses of types.
+ * {@code AnnotatedParameterizedType} represents the potentially annotated use
+ * of a parameterized type, whose type arguments may themselves represent
+ * annotated uses of types.
  *
  * @since 1.8
  */
 public interface AnnotatedParameterizedType extends AnnotatedType {
 
     /**
-     * Returns the annotated actual type arguments of this parameterized type.
+     * Returns the potentially annotated actual type arguments of this parameterized type.
      *
-     * @return the annotated actual type arguments of this parameterized type
+     * @return the potentially annotated actual type arguments of this parameterized type
      */
     AnnotatedType[] getAnnotatedActualTypeArguments();
 }
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java	Mon Sep 30 11:18:18 2013 +0200
@@ -26,10 +26,10 @@
 package java.lang.reflect;
 
 /**
- * AnnotatedType represents the annotated use of a type in the program
- * currently running in this VM. The use may be of any type in the Java
- * programming language, including an array type, a parameterized type, a type
- * variable, or a wildcard type.
+ * {@code AnnotatedType} represents the potentially annotated use of a type in
+ * the program currently running in this VM. The use may be of any type in the
+ * Java programming language, including an array type, a parameterized type, a
+ * type variable, or a wildcard type.
  *
  * @since 1.8
  */
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java	Mon Sep 30 11:18:18 2013 +0200
@@ -26,18 +26,18 @@
 package java.lang.reflect;
 
 /**
- * AnnotatedTypeVariable represents the use of a type variable, whose
- * declaration may have bounds which themselves represent annotated uses of
- * types.
+ * {@code AnnotatedTypeVariable} represents the potentially annotated use of a
+ * type variable, whose declaration may have bounds which themselves represent
+ * annotated uses of types.
  *
  * @since 1.8
  */
 public interface AnnotatedTypeVariable extends AnnotatedType {
 
     /**
-     * Returns the annotated bounds of this type variable.
+     * Returns the potentially annotated bounds of this type variable.
      *
-     * @return the annotated bounds of this type variable
+     * @return the potentially annotated bounds of this type variable
      */
     AnnotatedType[] getAnnotatedBounds();
 }
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java	Mon Sep 30 11:18:18 2013 +0200
@@ -26,24 +26,25 @@
 package java.lang.reflect;
 
 /**
- * AnnotatedWildcardType represents the use of a wildcard type argument, whose
- * upper or lower bounds may themselves represent annotated uses of types.
+ * {@code AnnotatedWildcardType} represents the potentially annotated use of a
+ * wildcard type argument, whose upper or lower bounds may themselves represent
+ * annotated uses of types.
  *
  * @since 1.8
  */
 public interface AnnotatedWildcardType extends AnnotatedType {
 
     /**
-     * Returns the annotated lower bounds of this wildcard type.
+     * Returns the potentially annotated lower bounds of this wildcard type.
      *
-     * @return the annotated lower bounds of this wildcard type
+     * @return the potentially annotated lower bounds of this wildcard type
      */
     AnnotatedType[] getAnnotatedLowerBounds();
 
     /**
-     * Returns the annotated upper bounds of this wildcard type.
+     * Returns the potentially annotated upper bounds of this wildcard type.
      *
-     * @return the annotated upper bounds of this wildcard type
+     * @return the potentially annotated upper bounds of this wildcard type
      */
     AnnotatedType[] getAnnotatedUpperBounds();
 }
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java	Mon Sep 30 11:18:18 2013 +0200
@@ -514,18 +514,20 @@
     }
 
     /**
-     * Returns an AnnotatedType object that represents the use of a type to
+     * Returns an {@code AnnotatedType} object that represents the use of a type to
      * specify the return type of the method/constructor represented by this
      * Executable.
      *
-     * If this Executable represents a constructor, the AnnotatedType object
-     * represents the type of the constructed object.
+     * If this {@code Executable} object represents a constructor, the {@code
+     * AnnotatedType} object represents the type of the constructed object.
      *
-     * If this Executable represents a method, the AnnotatedType object
-     * represents the use of a type to specify the return type of the method.
+     * If this {@code Executable} object represents a method, the {@code
+     * AnnotatedType} object represents the use of a type to specify the return
+     * type of the method.
      *
-     * @return an object representing the return type of this method
-     * or constructor
+     * @return an object representing the return type of the method
+     * or constructor represented by this {@code Executable}
+     *
      * @since 1.8
      */
     public abstract AnnotatedType getAnnotatedReturnType();
@@ -549,24 +551,29 @@
     }
 
     /**
-     * Returns an AnnotatedType object that represents the use of a type to
-     * specify the receiver type of the method/constructor represented by this
-     * Executable. The receiver type of a method/constructor is available only
-     * if the method/constructor declares a formal parameter called 'this'.
+     * Returns an {@code AnnotatedType} object that represents the use of a
+     * type to specify the receiver type of the method/constructor represented
+     * by this Executable object. The receiver type of a method/constructor is
+     * available only if the method/constructor has a <em>receiver
+     * parameter</em> (JLS 8.4.1).
      *
-     * Returns null if this Executable represents a constructor or instance
-     * method that either declares no formal parameter called 'this', or
-     * declares a formal parameter called 'this' with no annotations on its
-     * type.
+     * If this {@code Executable} object represents a constructor or instance
+     * method that does not have a receiver parameter, or has a receiver
+     * parameter with no annotations on its type, then the return value is an
+     * {@code AnnotatedType} object representing an element with no
+     * annotations.
      *
-     * Returns null if this Executable represents a static method.
+     * If this {@code Executable} object represents a static method, then the
+     * return value is null.
      *
-     * @return an object representing the receiver type of the
-     * method or constructor represented by this Executable
+     * @return an object representing the receiver type of the method or
+     * constructor represented by this {@code Executable}
      *
      * @since 1.8
      */
     public AnnotatedType getAnnotatedReceiverType() {
+        if (Modifier.isStatic(this.getModifiers()))
+            return null;
         return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
                 sun.misc.SharedSecrets.getJavaLangAccess().
                         getConstantPool(getDeclaringClass()),
@@ -577,8 +584,8 @@
     }
 
     /**
-     * Returns an array of AnnotatedType objects that represent the use of
-     * types to specify formal parameter types of the method/constructor
+     * Returns an array of {@code AnnotatedType} objects that represent the use
+     * of types to specify formal parameter types of the method/constructor
      * represented by this Executable. The order of the objects in the array
      * corresponds to the order of the formal parameter types in the
      * declaration of the method/constructor.
@@ -587,7 +594,8 @@
      * parameters.
      *
      * @return an array of objects representing the types of the
-     * formal parameters of this method or constructor
+     * formal parameters of the method or constructor represented by this
+     * {@code Executable}
      *
      * @since 1.8
      */
@@ -602,8 +610,8 @@
     }
 
     /**
-     * Returns an array of AnnotatedType objects that represent the use of
-     * types to specify the declared exceptions of the method/constructor
+     * Returns an array of {@code AnnotatedType} objects that represent the use
+     * of types to specify the declared exceptions of the method/constructor
      * represented by this Executable. The order of the objects in the array
      * corresponds to the order of the exception types in the declaration of
      * the method/constructor.
@@ -612,7 +620,8 @@
      * exceptions.
      *
      * @return an array of objects representing the declared
-     * exceptions of this method or constructor
+     * exceptions of the method or constructor represented by this {@code
+     * Executable}
      *
      * @since 1.8
      */
--- a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java	Mon Sep 30 11:18:18 2013 +0200
@@ -118,6 +118,7 @@
 
     static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
                                                             new TypeAnnotation[0], new TypeAnnotation[0], null);
+    static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
 
     private static class AnnotatedTypeBaseImpl implements AnnotatedType {
         private final Type type;
--- a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java	Mon Sep 30 11:18:18 2013 +0200
@@ -174,6 +174,11 @@
     public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations,
             ConstantPool cp,
             Class<?> decl) {
+        if (decl == Object.class ||
+                decl.isArray() ||
+                decl.isPrimitive() ||
+                decl == Void.TYPE)
+            return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE_ARRAY;
         return buildAnnotatedTypes(rawAnnotations,
                                    cp,
                                    decl,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedInterfaces.java	Mon Sep 30 11:18:18 2013 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8022324
+ * @summary Test Class.getAnnotatedInterfaces() returns 0-length array as
+ *          specified.
+ */
+
+import java.lang.reflect.AnnotatedType;
+import java.util.Arrays;
+
+public class GetAnnotatedInterfaces {
+    private static final Class<?>[] testData = {
+        GetAnnotatedInterfaces.class,
+        (new Clz() {}).getClass(),
+        (new Object() {}).getClass(),
+        Object[].class,
+        Object[][].class,
+        Object[][][].class,
+        Object.class,
+        void.class,
+        int.class,
+    };
+
+    private static int failed = 0;
+    private static int tests = 0;
+
+    public static void main(String[] args) throws Exception {
+        testReturnsZeroLengthArray();
+
+        if (failed != 0)
+            throw new RuntimeException("Test failed, check log for details");
+        if (tests != 9)
+            throw new RuntimeException("Not all cases ran, failing");
+    }
+
+    private static void testReturnsZeroLengthArray() {
+        for (Class<?> toTest : testData) {
+            tests++;
+
+            AnnotatedType[] res = toTest.getAnnotatedInterfaces();
+
+            if (res == null) {
+                failed++;
+                System.out.println(toTest + ".class.getAnnotatedInterface() returns" +
+                        "'null' should zero length array");
+            } else if (res.length != 0) {
+                failed++;
+                System.out.println(toTest + ".class.getAnnotatedInterfaces() returns: "
+                        + Arrays.asList(res) + ", should be a zero length array of AnnotatedType");
+            }
+        }
+    }
+
+    interface If {}
+
+    static abstract class Clz {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedReceiverType.java	Mon Sep 30 11:18:18 2013 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8024915
+ */
+
+import java.lang.reflect.AnnotatedType;
+import java.util.Arrays;
+
+public class GetAnnotatedReceiverType {
+    public void method() {}
+    public void method0(GetAnnotatedReceiverType this) {}
+    public static void method4() {}
+
+    class Inner0 {
+        public Inner0() {}
+    }
+
+    class Inner1 {
+        public Inner1(GetAnnotatedReceiverType GetAnnotatedReceiverType.this) {}
+    }
+
+    private static int failures = 0;
+    private static int tests = 0;
+
+    public static void main(String[] args) throws NoSuchMethodException {
+        checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method").getAnnotatedReceiverType(),
+                "getAnnotatedReceiverType for \"method\" should return an empty AnnotatedType");
+        checkEmptyAT(Inner0.class.getConstructor(GetAnnotatedReceiverType.class).getAnnotatedReceiverType(),
+                "getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType");
+
+        checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method0").getAnnotatedReceiverType(),
+                "getAnnotatedReceiverType for \"method0\" should return an empty AnnotatedType");
+        checkEmptyAT(Inner1.class.getConstructor(GetAnnotatedReceiverType.class).getAnnotatedReceiverType(),
+                "getAnnotatedReceiverType for a ctor with a \"this\" should return an empty AnnotatedType");
+
+        checkNull(GetAnnotatedReceiverType.class.getMethod("method4").getAnnotatedReceiverType(),
+                "getAnnotatedReceiverType() on a static method should return null");
+
+        if (failures != 0)
+            throw new RuntimeException("Test failed, see log for details");
+        else if (tests != 5)
+            throw new RuntimeException("Not all cases ran, failing");
+    }
+
+    private static void checkNull(Object o, String msg) {
+        if (o != null) {
+            failures++;
+            System.err.println(msg);
+        }
+        tests++;
+    }
+
+    private static void checkEmptyAT(AnnotatedType a, String msg) {
+        if (a.getAnnotations().length != 0) {
+            failures++;
+            System.err.print(msg);
+        }
+        tests++;
+    }
+}
--- a/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java	Fri Sep 27 18:38:00 2013 -0700
+++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java	Mon Sep 30 11:18:18 2013 +0200
@@ -23,12 +23,16 @@
 
 /*
  * @test
- * @bug 8022343
- * @summary make sure Class.getAnnotatedSuperclass() returns null when specified to do so
+ * @bug 8022343 8007072
+ * @summary Test Class.getAnnotatedSuperclass() returns null/non-null
+ *          AnnotatedType as specified
  */
 
+import java.lang.reflect.AnnotatedType;
+import java.util.Arrays;
+
 public class GetAnnotatedSuperclass {
-    private static final Class<?>[] testData = {
+    private static final Class<?>[] nullTestData = {
         Object.class,
         If.class,
         Object[].class,
@@ -36,9 +40,31 @@
         int.class,
     };
 
+    private static final Class<?>[] nonNullTestData = {
+        Class.class,
+        GetAnnotatedSuperclass.class,
+        (new If() {}).getClass(),
+        (new Clz() {}).getClass(),
+        (new Object() {}).getClass(),
+    };
+
+    private static int failed = 0;
+    private static int tests = 0;
+
     public static void main(String[] args) throws Exception {
-        int failed = 0;
-        for (Class<?> toTest : testData) {
+        testReturnsNull();
+        testReturnsEmptyAT();
+
+        if (failed != 0)
+            throw new RuntimeException("Test failed, check log for details");
+        if (tests != 10)
+            throw new RuntimeException("Not all cases ran, failing");
+    }
+
+    private static void testReturnsNull() {
+        for (Class<?> toTest : nullTestData) {
+            tests++;
+
             Object res = toTest.getAnnotatedSuperclass();
 
             if (res != null) {
@@ -47,10 +73,26 @@
                         + res + ", should be null");
             }
         }
+    }
 
-        if (failed != 0)
-            throw new RuntimeException("Test failed, check log for details");
+    private static void testReturnsEmptyAT() {
+        for (Class<?> toTest : nonNullTestData) {
+            tests++;
+
+            AnnotatedType res = toTest.getAnnotatedSuperclass();
+
+            if (res == null) {
+                failed++;
+                System.out.println(toTest + ".getAnnotatedSuperclass() returns 'null' should  be non-null");
+            } else if (res.getAnnotations().length != 0) {
+                failed++;
+                System.out.println(toTest + ".getAnnotatedSuperclass() returns: "
+                        + Arrays.asList(res.getAnnotations()) + ", should be an empty AnnotatedType");
+            }
+        }
     }
 
     interface If {}
+
+    static abstract class Clz {}
 }