I've wondered this for a while, but haven't been able to find anything on the topic.
Let's say I'm using Spring MVC and defining a series of Controllers.
@RestController
public abstract class AbstractController {
@Resource
private Environment env;
...
...
}
For the following, is a @RestController annotation necessary for UserController to register?
@RequestMapping(value = "/user")
public class UserController extends AbstractController {
@RequestMapping("value = "", method = RequestMethod.GET)
public ResponseEntity<User> getUser() {
...
return new ResponseEntity<>(user, HttpStatus.OK);
}
}
If you decide the annotation to be @Inherited, yes. In this example, @RestController is not defined with the @Inherited meta-annotation, so it is not applied to subclasess of AbstractController.
There are two questions here. SJuan76 has answered the first, concerning inheritance of type annotations.
The second question
is a
@RestControllerannotation necessary forUserControllerto register?
is a little more involved.
Spring has a concept of meta-annotations:
Many of the annotations provided by Spring can be used as meta-annotations in your own code. A meta-annotation is simply an annotation that can be applied to another annotation.
[...]
Meta-annotations can also be combined to create composed annotations. For example, the
@RestControllerannotation from Spring MVC is composed of@Controllerand@ResponseBody.
However, the component scanning process will not generate a bean definition for abstract classes. What's more, it won't discover these meta-annotations on subtypes that aren't themselves annotated. In other words, Spring will skip over your UserController type and won't register a bean definition for it. (I'm sure it could, it just doesn't as of 4.1.7.RELEASE.)
Now, if you did annotate your type UserController with @Component to force Spring to generate a bean definition, the Spring MVC process that handles @ResponseBody would detect the @RestController annotations on the AbstractController supertype.
This is done in RequestResponseBodyMethodProcessor which uses AnnotationUtils.findAnnotation to find an annotation on the type that contains your handler method. Its javadoc states
Find a single
AnnotationofannotationTypeon the suppliedClass, traversing its interfaces, annotations, and superclasses if the annotation is not present on the given class itself.This method explicitly handles class-level annotations which are not declared as inherited as well as meta-annotations and annotations on interfaces.
Therefore, if you had
@Component
@RequestMapping(value = "/user")
public class UserController extends AbstractController {
Spring would detect and generate a bean for UserController. When handling a request to /user with your getUser handler method, Spring MVC would operate as if your class was actually annotated with @RestController (or @ResponseBody).
However, again in your case, your handler method is returning a ResponseEntity. That's not handled by the HandlerMethodReturnValueHandler for @ResponseBody, it's handled by HttpEntityMethodProcessor.
A word of caution with abstract classes meant to be supertypes of @Controller types: if you have many subtypes also meant to be beans and the abstract supertype contains @RequestMapping annotated methods, Spring MVC will fail to register your handler methods because it will consider that supertype method to be duplicated across them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With