I was also skeptical of annotations, but seeing them in use can be great. They can also be used.
The main thing to remember about annotations is that they are static. They cannot change at runtime. Any other way of customization (xml, self-description in code, regardless) does not suffer from this. I have seen that people here at SO have problems with Spring in terms of having a test environment when injecting test configurations and having to dump it to XML in order to do this.
XML is not polymorphic, inherited, or anything else, so this is not a step backward in that sense.
The advantage of annotations is that it can give you a more static check of your configuration and can avoid a lot of detail and difficulties with coordination in XML configurations (basically saving DRY stuff).
As with XML, annotations can be used. The main thing is to balance the needs and benefits of each of them. Annotations, to the extent that they give you less verbose and DRY code, are a tool that you can use.
EDIT: Regarding the comment on annotation replacing an interface or an abstract class, I think this might be reasonable at the border of the frame. Within the framework intended for use by hundreds, if not thousands of projects, having an interface or base class can really distort things (especially the base class, although if you can do this with annotations there is no reason why you could not do it with normal interface.
Consider JUnit4. Previously, you had to extend the base class, which had a tuning and disruption method. In my opinion, it really doesn't matter if they were on the interface or in the base class. Now I have a completely separate project with my own inheritance hierarchy, and they all must follow this method. First of all, they cannot have their own conflicting method names (not a big deal in testing, but you understand my point). Secondly, you have a chain of calling super everything down, because all methods must be connected.
Now with JUnit4 you can have different @Before methods in different hierarchy classes, and they can be independent of each other. There is no less DRY way to do this without annotations.
From the point of view of developers, JUnit is a disaster. It is much better to have a specific type, which you can call setUp and teardown. But the framework does not exist for the convenience of the developer of the framework, it exists for the convenience of the user of the framework.
All this applies if your code does not need to care about the type (that is, in your example, nothing will still use the controller type). Then you can even say that the implementation of the framework interface is more impenetrable than overlaying the annotation.
If, however, you intend to write code to read this annotation in your own project, run far.