Is it possible to read the value of a annotation in java?

this is my code:

@Column(columnName="firstname")




private String firstName;


@Column(columnName="lastname")
private String lastName;


public String getFirstName() {
return firstName;
}


public void setFirstName(String firstName) {
this.firstName = firstName;
}


public String getLastName() {
return lastName;
}


public void setLastName(String lastName) {
this.lastName = lastName;
}

is it possible to read the value of my annotation @Column(columnName="xyz123") in another class?

195613 次浏览

I've never done it, but it looks like Reflection provides this. Field is an AnnotatedElement and so it has getAnnotation. This page has an example (copied below); quite straightforward if you know the class of the annotation and if the annotation policy retains the annotation at runtime. Naturally if the retention policy doesn't keep the annotation at runtime, you won't be able to query it at runtime.

An answer that's since been deleted (?) provided a useful link to an annotations tutorial that you may find helpful; I've copied the link here so people can use it.

Example from this page:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;


@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
String str();


int val();
}


class Meta {
@MyAnno(str = "Two Parameters", val = 19)
public static void myMeth(String str, int i) {
Meta ob = new Meta();


try {
Class c = ob.getClass();


Method m = c.getMethod("myMeth", String.class, int.class);


MyAnno anno = m.getAnnotation(MyAnno.class);


System.out.println(anno.str() + " " + anno.val());
} catch (NoSuchMethodException exc) {
System.out.println("Method Not Found.");
}
}


public static void main(String args[]) {
myMeth("test", 10);
}
}

Yes, if your Column annotation has the runtime retention

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
....
}

you can do something like this

for (Field f: MyClass.class.getFields()) {
Column column = f.getAnnotation(Column.class);
if (column != null)
System.out.println(column.columnName());
}

UPDATE : To get private fields use

Myclass.class.getDeclaredFields()

Of course it is. Here is a sample annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {


String testText();
}

And a sample annotated method:

class TestClass {


@TestAnnotation(testText="zyx")
public void doSomething() {}
}

And a sample method in another class that prints the value of the testText:

Method[] methods = TestClass.class.getMethods();
for (Method m : methods) {
if (m.isAnnotationPresent(TestAnnotation.class)) {
TestAnnotation ta = m.getAnnotation(TestAnnotation.class);
System.out.println(ta.testText());
}
}

Not much different for field annotations like yours.

Cheerz!

While all the answers given so far are perfectly valid, one should also keep in mind the google reflections library for a more generic and easy approach to annotation scanning, e.g.

 Reflections reflections = new Reflections("my.project.prefix");


Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

You can also use generic types, in my case, taking into account everything said before you can do something like:

public class SomeTypeManager<T> {


public SomeTypeManager(T someGeneric) {


//That's how you can achieve all previously said, with generic types.
Annotation[] an = someGeneric.getClass().getAnnotations();


}


}

Remember, that this will not equival at 100% to SomeClass.class.get(...)();

But can do the trick...

Elaborating to the answer of @Cephalopod, if you wanted all column names in a list you could use this oneliner:

List<String> columns =
Arrays.asList(MyClass.class.getFields())
.stream()
.filter(f -> f.getAnnotation(Column.class)!=null)
.map(f -> f.getAnnotation(Column.class).columnName())
.collect(Collectors.toList());

In common case you have private access for fields, so you CAN'T use getFields in reflection. Instead of this you should use getDeclaredFields

So, firstly, you should be aware if your Column annotation has the runtime retention:

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
}

After that you can do something like this:

for (Field f: MyClass.class.getDeclaredFields()) {
Column column = f.getAnnotation(Column.class);
// ...
}

Obviously, you would like to do something with field - set new value using annotation value:

Column annotation = f.getAnnotation(Column.class);
if (annotation != null) {
new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
object,
myCoolProcessing(
annotation.value()
)
);
}

So, full code can be looked like this:

for (Field f : MyClass.class.getDeclaredFields()) {
Column annotation = f.getAnnotation(Column.class);
if (annotation != null)
new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
object,
myCoolProcessing(
annotation.value()
)
);
}

For the few people asking for a generic method, this should help you (5 years later :p).

For my below example, I'm pulling the RequestMapping URL value from methods that have the RequestMapping annotation. To adapt this for fields, just change the

for (Method method: clazz.getMethods())

to

for (Field field: clazz.getFields())

And swap usage of RequestMapping for whatever annotation you are looking to read. But make sure that the annotation has @Retention(RetentionPolicy.RUNTIME).

public static String getRequestMappingUrl(final Class<?> clazz, final String methodName)
{
// Only continue if the method name is not empty.
if ((methodName != null) && (methodName.trim().length() > 0))
{
RequestMapping tmpRequestMapping;
String[] tmpValues;


// Loop over all methods in the class.
for (Method method: clazz.getMethods())
{
// If the current method name matches the expected method name, then keep going.
if (methodName.equalsIgnoreCase(method.getName()))
{
// Try to extract the RequestMapping annotation from the current method.
tmpRequestMapping = method.getAnnotation(RequestMapping.class);


// Only continue if the current method has the RequestMapping annotation.
if (tmpRequestMapping != null)
{
// Extract the values from the RequestMapping annotation.
tmpValues = tmpRequestMapping.value();


// Only continue if there are values.
if ((tmpValues != null) && (tmpValues.length > 0))
{
// Return the 1st value.
return tmpValues[0];
}
}
}
}
}


// Since no value was returned, log it and return an empty string.
logger.error("Failed to find RequestMapping annotation value for method: " + methodName);


return "";
}

one of the ways I used it :

protected List<Field> getFieldsWithJsonView(Class sourceClass, Class jsonViewName){
List<Field> fields = new ArrayList<>();
for (Field field : sourceClass.getDeclaredFields()) {
JsonView jsonViewAnnotation = field.getDeclaredAnnotation(JsonView.class);
if(jsonViewAnnotation!=null){
boolean jsonViewPresent = false;
Class[] viewNames = jsonViewAnnotation.value();
if(jsonViewName!=null && Arrays.asList(viewNames).contains(jsonViewName) ){
fields.add(field);
}
}
}
return fields;
}

To read the value of annotation in java try to follow the following steps:

  1. Create an annotation.
  2. Follow the logic in the target class below.
  3. Access the value as in Output.

Annotation

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.TYPE}) // make annotation usable only for classes
@Retention(RetentionPolicy.RUNTIME) // make annotation available at the runTime
public @interface EntryPoint {
String url();
}

Target

// just remember to import your annotation in this case "EntryPoint"


import java.lang.annotation.Annotation;


@EntryPoint(url = "api/v1/demo")
public class Demo {
// get class of this.
private final Class<? extends Demo> demo = this.getClass();
// get specific annotation (EntryPoint.class)
private final Annotation annotation = demo.getAnnotation(EntryPoint.class);
// instantiate annotation and assign it value from the class annotation.
final EntryPoint entryPoint = (EntryPoint) annotation;
}

Output

public class Main {
public static void main(String[] args) {
// create an object of the class with the annotation.
Demo demo = new Demo();
System.out.println(demo.entryPoint.url());
}
}

The result is "api/v1/demo"