15

I've created simple annotation in Java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
    String columnName();
}

and class

public class Table {

    @Column(columnName = "id")
    private int colId;

    @Column(columnName = "name")
    private String colName;

    private int noAnnotationHere;

    public Table(int colId, String colName, int noAnnotationHere) {
       this.colId = colId;
       this.colName = colName;
       this.noAnnotationHere = noAnnotationHere;
    }  
}

I need to iterate over all fields, that are annotated with Column and get name and value of field and annotation. But I've got problem with getting value of each field, since all of them are of different data type.

Is there anything that would return collection of fields that have certain annotation? I managed to do it with this code, but I don't think that reflection is good way to solve it.

Table table = new Table(1, "test", 2);

for (Field field : table.getClass().getDeclaredFields()) {
    Column col;
    // check if field has annotation
    if ((col = field.getAnnotation(Column.class)) != null) {
        String log = "colname: " + col.columnName() + "\n";
        log += "field name: " + field.getName() + "\n\n";

        // here i don't know how to get value of field, since all get methods
        // are type specific

        System.out.println(log);
    }
}

Do I have to wrap every field in object, which would implement method like getValue(), or is there some better way around this? Basicly all I need is string representation of each field that is annotated.

edit: yep field.get(table) works, but only for public fields, is there any way how to do this even for private fields? Or do I have to make getter and somehow invoke it?

3
  • setAccessible. The array version will be faster if you have a security manager present. setAccessible is, of course, very dangerous in situations where you have security manager. Commented Apr 10, 2009 at 16:22
  • scary ... looks you're implementing your own version of JPA Commented Apr 10, 2009 at 16:29
  • @basszero: yep you're right, I have to make this for my college project because of my stupid teacher who lives in a cave and doesn't allow using of any libraries such as Toplink etc... Commented Apr 10, 2009 at 17:24

4 Answers 4

11

Every object should has toString() defined. (And you can override this for each class to get a more meaningful representation).

So you where your "// here I don't know" comment is, you could have:

Object value = field.get(table);
// gets the value of this field for the instance 'table'

log += "value: " + value + "\n";
// implicitly uses toString for you
// or will put 'null' if the object is null
Sign up to request clarification or add additional context in comments.

2 Comments

thx, this works, but only if fields are declared as public, when they're private i get Exception in thread "main" java.lang.IllegalAccessException: Class Main can not access a member of class Table with modifiers "private"
@Darth - have a look at Field.setAccessible - java.sun.com/javase/6/docs/api/java/lang/reflect/…
9

Reflection is exactly the way to solve it. Finding out things about types and their members at execution time is pretty much the definition of reflection! The way you've done it looks fine to me.

To find the value of the field, use field.get(table)

Comments

4

Reflection is exactly the way to look at annotations. They are a form of "metadata" attached to the class or method, and Java annotations were designed to be examined that way.

2 Comments

Wow, I share the same first 5 words with Jon's answer, I must be improving :)
If you look closely you will see Mr Skeet had placed his third word 'exactly' in italics while your entry is only in regular non-italic formatting. Well done for a step in the right direction but without this subtle but so descriptive emphasis which Jon has used your first five words still fall short of Mr Skeets.
2

Reflection is one way to process the object (probably the only way if the fields are private and don't have any kind of accessor method). You'll need to look at Field.setAccessible and perhaps Field.getType.

Another approach is to generate another class for enumerating the annotated fields using a compile-time annotation processor. This requires a com.sun API in Java 5, but support is better in the Java 6 JDK (IDEs like Eclipse may require special project configuration).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.