Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting the present annotations within the given object passed into a constructor

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:

  1. is this possible to detect the annotations in this object/class at runtime, and only for THIS passed object (I don't want to scan for annotations on the classpath!)?
  2. is it possible to detect the datatype of the @Cell tagged members? This is needed because the Cell class doesn't accept all datatypes.
  3. is it possible to retrieve the actual member name (specified in the java file) so that the user doesn't have to specify the members Cell name. I want the user to be able to write @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.
  4. How to detect if the annotations are in the right place?If code is tagged like this, then the object should be ignored (or maybe an exception is thrown)?
    @Cell // oh oh, that's no good :(
    public class WrongClass {
    // some members
    }
  5. Could you provide some startup code, so I know a little to get going with this problem. I am really new to annotations and reflection. BTW: I am using the latest jvm 1.6+

Thank you for your kind help!

like image 641
user504342 Avatar asked Dec 06 '10 09:12

user504342


People also ask

How do you check annotations?

The isAnnotation() method is used to check whether a class object is an annotation. The isAnnotation() method has no parameters and returns a boolean value. If the return value is true , then the class object is an annotation. If the return value is false , then the class object is not an annotation.

Which of the following are built in annotations in Java?

Java popularly defines seven built-in annotations as we have seen up in the hierarchy diagram. Four are imported from java. lang. annotation: @Retention, @Documented, @Target, and @Inherited.

How do you make annotations on Kotlin?

Just like in Java, Kotlin has repeatable annotations, which can be applied to a single code element multiple times. To make your annotation repeatable, mark its declaration with the @kotlin. annotation.


2 Answers

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

like image 93
Liviu T. Avatar answered Oct 12 '22 10:10

Liviu T.


Q.1 :is this possible to detect the annotations in this object/class at runtime, and only for THIS passed object (I don't want to scan for annotations on the classpath!)?

Yes it is very well possible using isAnnotationPresent

@Deprecated
public class AnnotationDetection {

    public static void main(String[] args) {
        AnnotationDetection annotationDetection = new AnnotationDetection();
        System.out.println(annotationDetection.getClass().isAnnotationPresent(Deprecated.class));
    }
}

Note that annotation which are scoped to retain at Runtime will be available only,

like image 42
jmj Avatar answered Oct 12 '22 08:10

jmj