Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8: Class to AnnotatedType

Tags:

java

java-8

In Java 8, Class appears to have gained methods to get an AnnotatedType view of its superclasses and its superinterfaces.

How can you convert a Class to its own AnnotatedType? Does that question even make sense?

From what I can tell, an AnnotatedType has-a Type, not is-a Type. It's an AnnotatedElement, though; it's all very messy.

I have searched through the Javadocs to no avail, so far.

like image 616
Louis Wasserman Avatar asked Dec 03 '13 23:12

Louis Wasserman


2 Answers

So I finally got an acceptable understanding of the AnnotatedType interface. Here's a working Java 8 example to illustrate one of its uses

public static void main(String[] args) {
    Class<?> fooClass = Foo.class;
    AnnotatedType type = fooClass.getAnnotatedSuperclass();
    System.out.println(type);
    System.out.println(Bar.class == type.getType());
    System.out.println(Arrays.toString(type.getAnnotations()));
    System.out.println(Arrays.toString(type.getDeclaredAnnotations()));
}

public static class Bar {
}

public static class Foo extends @Custom Bar {
}

// So that annotation metadata is available at run time
@Retention(RetentionPolicy.RUNTIME)
// TYPE_USE being the important one
@Target(value = {ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE,
        METHOD, PACKAGE, PARAMETER, TYPE, TYPE_PARAMETER, TYPE_USE}) 
public @interface Custom {
}

This prints

sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@1d44bcfa
true
[@com.testing.Test$Custom()]
[@com.testing.Test$Custom()]

The AnnotatedType interface states

AnnotatedType represents the potentially annotated use of a type in the program currently running in this VM.

and Class#getAnnotatedSuperclass() javadoc states

Returns an AnnotatedType object that represents the use of a type to specify the superclass of the entity represented by this Class object.

I've made potentially bold in the AnnotatedType javadoc because it makes it clear that the type usage doesn't have to be annotated. If you had

public static class Bar {}
...
Bar.class.getAnnotatedSuperclass(); // returns Class instance for java.lang.Object

This is a use case that wasn't possible in Java 7 and lower because you could not annotate type usages (see some examples here). In Java 8, however, you can do

public static class Foo extends @Custom Bar {

where the type Bar is used as a super class and its usage is annotated with @Custom. It is therefore an AnnotatedType. Therefore, Foo.class.getAnnotatedSuperClass() will return an AnnotatedType instance for that usage.

How can you convert a Class to its own AnnotatedType? Does that question even make sense?

The question doesn't make sense. This is because a Class object holds self-contained metadata about a class. By self-contained, I mean everything that can be deduced from the class' .class file (or actual declaration). You cannot deduce any usages of the type anywhere else and therefore it cannot be converted to any AnnotatedType for itself.

You can have

public static class Foo extends @Custom Bar {}

public static class Zoom extends @Custom Bar {}

public static class Doing extends @Custom Bar {}

There is an AnnotatedType instance for each of the above uses of Bar, but which one would you chose to convert a [Bar] Class to its own AnnotatedType?

like image 173
Sotirios Delimanolis Avatar answered Nov 06 '22 03:11

Sotirios Delimanolis


Here's a simple example showing the usage of getAnnotatedSuperclass():

import java.lang.annotation.*;

public class AnnotationTest {

    @Target(ElementType.TYPE_USE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface First { }

    @Target(ElementType.TYPE_USE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Second { }

    class A { }

    class B extends @First @Second A { }

    public static void main(String[] args) {
        Annotation[] anns = B.class.getAnnotatedSuperclass().getAnnotations();
        System.out.printf("There are %d annotations on B's use of its superclass.%n", anns.length);
        for (Annotation a : anns)
            System.out.println(a.annotationType().getName());
    }
}

The output from this program is:

There are 2 annotations on B's use of its superclass.
AnnotationTest$First
AnnotationTest$Second

Note the distinction of annotations occurring at the use of B's superclass (namely A) as opposed to the declaration of A itself.

like image 2
Stuart Marks Avatar answered Nov 06 '22 01:11

Stuart Marks