Javanna
A Java library to create and introspect annotations at runtime.
The whole library is just one class: com.athaydes.javanna.Javanna
.
To map between Java annotations and JSON, see Javanna-Gson.
Getting started
Javanna is on JCenter and Maven Central.
Gradle
dependencies {
compile "com.athaydes.javanna:javanna:1.1"
}
Maven
<dependency>
<groupId>com.athaydes.javanna</groupId>
<artifactId>javanna</artifactId>
<version>1.1</version>
</dependency>
Parse an annotation class
Given the following example definitions:
@Retention( RetentionPolicy.RUNTIME )
@interface Simple {
String value();
}
enum Example {SMALL, MEDIUM, LARGE, XXX}
@Retention( RetentionPolicy.RUNTIME )
@interface Complex {
String name() default "default-name";
int count() default 2;
Simple simple();
Example example();
}
You can parse the annotations like this:
JavaAnnotation<Complex> annotation = Javanna.parseAnnotation( Complex.class );
And then, inspect its members types and defaults (from the unit tests):
// check the annotation actual type
assertEquals( Complex.class, annotation.getAnnotationType() );
// check the default values Map
assertEquals( new HashMap<String, Object>() {{
put( "name", "default-name" );
put( "count", 2 );
}}, annotation.getDefaultValueByMember() );
// check the annotation member types
assertEquals( new HashMap<String, Class<?>>() {{
put( "name", String.class );
put( "count", int.class );
put( "simple", Simple.class );
put( "example", Example.class );
}}, annotation.getTypeByMember() );
// check the annotation members
assertEquals( new HashSet<>( Arrays.asList( "name", "count", "simple", "example" ) ), annotation.getMembers() );
Create an annotation instance
An annotation instance can be created from a Class
or JavaAnnotation
:
final Simple simple = Javanna.createAnnotation( Simple.class, new HashMap<String, Object>() {{
put( "value", "the-simple-one" );
}} );
Complex complex = Javanna.createAnnotation( Complex.class, new HashMap<String, Object>() {{
put( "name", "hello" );
put( "count", 6 );
put( "simple", simple );
put( "example", Example.LARGE );
}} );
// use the annotation as if it were a normal annotation instance
assertEquals( "hello", complex.name() );
assertEquals( 6, complex.count() );
assertEquals( "the-simple-one", complex.simple().value() );
assertEquals( Example.LARGE, complex.example() );
It is an error to not provide mandatory values, or to give invalid members or values of the wrong type. All errors cause an
IllegalArgumentException
to be thrown by thecreateAnnotation
method.
Read the values of an annotation instance as a Map
To read all values of an annotation as a Map, use the getAnnotationValues
method:
Map<String, Object> values = Javanna.getAnnotationValues( annotation );
Full example (from the unit tests):
@Simple( "hi" )
@Complex( name = "hello", count = 6, simple = @Simple( "hi" ), example = Example.SMALL )
public void canReadComplexAnnotationValues() throws Exception {
// get the annotations on this method
final Annotation simple = getClass().getMethod( "canReadComplexAnnotationValues" ).getAnnotation( Simple.class );
final Annotation complex = getClass().getMethod( "canReadComplexAnnotationValues" ).getAnnotation( Complex.class );
// expected values of the @Complex annotation
Map<String, Object> expectedValues = new LinkedHashMap<String, Object>() {{
put( "name", "hello" );
put( "count", 6 );
put( "simple", simple );
put( "example", Example.SMALL );
}};
// read the annotation values as a Map
Map<String, Object> actualValues = Javanna.getAnnotationValues( complex );
assertEquals( expectedValues, actualValues );
}
To extract annotation values recursively (eg. get the value of the @Simple
annotation as a Map in the example above), just use the getAnnotationValues(Annotation a, boolean recursive)
method:
Map<String, Object> actualValues = Javanna.getAnnotationValues( complex, true );
In this case, the resulting Map would be:
Map<String, Object> expectedValues = new LinkedHashMap<String, Object>() {{
put( "name", "hello" );
put( "count", 6 );
put( "simple", new LinkedHashMap<String, Object>() {{
put( "value", "hi" );
}} );
put( "example", Example.SMALL );
}};