The typical use-case is for simple things like @Override, but clearly you can do a lot more with them. If you push the limits of them, you get things like Project Lombok, though my understanding is that that's a huge abuse of annotations. What exactly can you do? What sort of things can you do at compile-time and run-time with annotations? What can you not do?
We use runtime annotation together with reflection to customize our Domain Model Mapping to the database. Also our form validation is based on Annotations in the code used at runtime.
In addition you can use the Annotation Processor which comes with Java to preprocess your Source files
EDIT: And with lombak, as asked in the Question there was added a new more powerful way of using this Annotation processing than mostly everyone here thought to be possible. Let me describe this for you in a few words: They hook the Java Annotation Processing step in a) The Java-Compiler and b) the Eclipse IDE where the parse tree for your code is generated. This way eclipse shows you more code that you really wrote, and the javac believes the same. The generator technic uses old style Java Annoation Processing, but you can think of Lombak as the missing glue everyone needed to make it really useful.
Annotations are metadata, information about information - in this case your code.
With annotations, you can provide hints and clues to the consumer of the annotation, such as the compiler or the code itself at runtime. I have used them carefully on a few occasions, where their presence replaced the need for some other boolean comparison evaluating to true, and the attributes provided further information about what actually needed to be done because the annotation was present.
Regarding what you can't do with annotations .. I'm not sure how to answer that. Use them if they solve a real problem or make your code more elegant, but don't force it.
Pardon me possibly over-simplifying things.
Annotations belongs to reflection. Annotations alone don't provide anything, you need to use them either in your code, or use them jointly with things like dynamic proxy or byte-code rewritting, which also belong to the field of reflection.
Reflection is known as something extremely powerful but at the same time that can be dangerous.
I think the underlying question is: "what are the legitimate uses of annotations, or more generally reflection?".
Because there is tension between reflection and safety (breaks type system, access to final fields, etc.), there are then two camps: those who embrace meta-programming and those who embrace safety. What's legitimate is ultimately a matter of taste and opinion.
Related questions:
Based on your comment it seems like you are mostly interest about JSR-269 and hooking in the compilation process. I see two use cases for JSR-269: for custom error/semantics checks (e.g. Override), for DSL/language engineering. Whether it's widely used apart for hacking and experiment, I don't know. Here are nevertheless cool links from a colleague:
That said, I would say that byte-code transformation/compiler hooks still belongs to meta-programming. For instance you can generate getter/setter like in Lombok at compile-time, or use a dynamic proxy that do that at run-time. So to me, this duality means that we're still in the field of reflection.
I'm pretty sure you can't use annotations to do laundry.
But other than that, here are some of the real limitation of annotations in my experience:
- They are static. This means that you cannot have some dynamic runtime configuration replace them. So if you have database information retrieved from an annotation, that can be very limiting. Frameworks that do that tend to end up needing both configuration mechanisms, annotation and some XML or other dynamic mechanism. Not exactly wonderful.
- Related to number 1, they are difficult to test. Imagine a framework that has to process some annotation. Creating all of the variations to test is a lot of boiler plate.
- They are hard to consume. Both the reflection gotchas and just general difficulties make it so that they are appropriate for a framework to asks its users to write an annotation, but you would never want to have a user of the framework have to analyze the annotations on a parameter to determine anything.
This question is very (too?) broad so I will just give one example that I find interesting. JPA 2.0 relies on annotation processing to generate static metamodel classes for entities (used for type safe queries with the Criteria API).
See also
- Hibernate Static Metamodel Generator Annotation Processor
org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor
(Hibernate's implementation)
Lately I started using annotations with Guice(DI) and create cool annotation called @Login for tests. Guice has AOP support. So every test annotated with @Login with automatically log the user before running. It looks cooler than calling Login action before every test or in set-up method.
I every gave it param to log as chosen user.
You could also take a look at Seam annotations http://docs.jboss.org/seam/1.0.0.GA/reference/en/html/annotations.html or hibernate validator http://docs.jboss.org/hibernate/stable/validator/reference/en/html_single/#validator-usingvalidator