My question in short: how do I detect if a java annotation is present (and in the right place) for a given user class/object.
Details of the "problem"
Lets say I have two java classes:
public class Line {
private List<Cell> cells;
public Line(Object... annotatedObjects) {
// check if annotations @Line and @Cell are present in annotatedObjects.
}
// getter/setter for cells.
}
public class Cell {
// some members
// some methods
}
A Line object holds Cells.
I also have two annotations, like:
public @interface Line {
// some stuff here
}
public @interface Cell {
// some stuff here
}
I also have a bunch of user classes (two will do for this example) that contain the @Line and @Cell annotations I specified, like:
@Line(name="pqr", schema="three")
public class AUserClass {
@Cell
private String aString;
}
@Line(name="xyz", schema="four")
public class AnotherUserClass {
@Cell(name="birthday")
private Date aDate;
}
The problem: When I instantiate a new Line object, I want to be able to pass the user classes/objects into the Line constructor. The Line constructor then finds out if the passed user classes/objects are valid classes that can be processed. Only user classes that have a @Line
annotation for the class, and at least one @Cell
annotation for its members are valid objects that can be passed into the constructor of the Line object.
All other passed objects are invalid. The moment a valid user object is passed, all the available members that are tagged as @Cell
in that object are transformed to Cell objects and added to the cells list.
My questions:
@Cell
tagged members? This is needed because the Cell class doesn't accept all datatypes.@Cell
(without a name) and @Cell(name="aName")
, and when only @Cell
is specified, the name of the member is used instead. I have no idea if this information is still available at runtime using reflection.@Cell // oh oh, that's no good :(
public class WrongClass {
// some members
}
First you need to have retention policy on your annotations so you can read them with reflection
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface Line {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public static @interface Cell {
}
Second you need to test if the class has the Line annotation with isAnnotationPresent(annotationClass)
. This method is accessible from java.lang.Class
and a java.lang.reflect.Field.
NOTE: that you need to retrieve the fields that are private with class.getDeclaredField(fieldName)
.
3.
I don't think you can make an annotation have a default value based on a propertyName but you can make name optional by providing a default String name() default DEFAULT
and check for that value when iterating through the fields and either use the value stored in name()
or the propertyName