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

58,610

Solution 1

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

Solution 2

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,

Share:
58,610
user504342
Author by

user504342

If you read this, then you might be interested in my hobby: writing about-me pages ;)

Updated on February 17, 2020

Comments

  • user504342
    user504342 about 4 years

    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!

  • user504342
    user504342 over 13 years
    Answering some of my own questions: 1. see above; 2. Use the java.lang.reflect.Field methods: getName() and getType() to find out the datatype of the field; 4. see above; 5. See Thinking in Java 4th, and Java reflection in Action (good resources for answers). 3. still unanswered.
  • Liviu T.
    Liviu T. over 13 years
    @user504343 so you want the @Cell.name to default to the property name that it's put on?
  • user504342
    user504342 over 13 years
    yes, that's true. If field has @Cell then pick the fieldname for the Cell.name. If field has @Cell(name="hello") then pick that as the Cell.name. If @Cell(name="") pick the fieldname too.
  • Don Srinath
    Don Srinath almost 10 years
    Can you please explain how ?
  • jmj
    jmj almost 10 years
    @Don this.getClass().isAnnotationPresent(SomeAnnotation.class)
  • Don Srinath
    Don Srinath almost 10 years
    ,it will always be false. Since getClass gives instance of Class object and it doesn't contain the intended annotation.
  • jmj
    jmj almost 10 years
    well you need to retrieve class instance of the class you want to check if that class has specific annotation present, check javadoc
  • Don Srinath
    Don Srinath almost 10 years
    yah check that, seems that it is not possible to do this at run-time.
  • jmj
    jmj almost 10 years
    It is possible to do at runtime, let me add verbose answer
  • Don Srinath
    Don Srinath almost 10 years
    Yah, thanks for the update. Anyway there you have AnnotationDetection defined. So you know it is that class even at the compile time. What if you get a Object, which can be an instance of any class, and you want to get annotations defined for that particular passed object?
  • jmj
    jmj almost 10 years
    I am sorry I am not understanding your comment, what is your requirement, it could be a compiled class as well in my example
  • Don Srinath
    Don Srinath almost 10 years
    My case is that say there is a method public void soutannotations(Object object), where at the compile time you don't know what the actual object that will be passed at the run time.Anyway it works too if we get declared methods and then check annotations of each of those methods. Thanks
  • Arià
    Arià about 6 years
    In Kotlin: yourStringResVariable.javaClass.isAnnotationPresent(StringRe‌​s::class.java)
  • Nemo
    Nemo over 2 years
    @DonSrinath it would be much better if you first test what you appeals for and post it after check yourself