Reputation: 11363
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 Controller
s.
@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);
}
}
Upvotes: 3
Views: 2132
Reputation: 279970
There are two questions here. SJuan76 has answered the first, concerning inheritance of type annotations.
The second question
is a
@RestController
annotation necessary forUserController
to 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
@RestController
annotation from Spring MVC is composed of@Controller
and@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
Annotation
ofannotationType
on 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.
Upvotes: 3
Reputation: 24885
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
.
Upvotes: 6