5

Although every page on internet says that @RestController is a specification of @Component.I dont know whether it has to be related with DispatcherServlet. But when I try below code by switching between @RestController & @Component, I don't see same behaviour :

First I tried with @RestController:

@RestComponent
public class TestController {
    @RequestMapping(value="/testController", method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
    public void testController() {
        System.out.println("Hello");
    }

}

I got below output in Console:

Hello

Second I tried with @Component + @ResponseBody:

@Component
@ResponseBody
public class TestController {
    @RequestMapping(value="/testController", method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
    public void testController() {
        System.out.println("Hello");
    }
}

I got an error on postman:

{
    "timestamp": 1570998345860,
    "status": 405,
    "error": "Method Not Allowed",
    "message": "Request method 'POST' not supported",
    "path": "/testController"
}

If both annotations are same, then why is there a difference in output ??

Below is the Source code for @RestController & @Controller , which shows that both @RestController & @Controller are specification of @Component:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

}


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
}

Maybe it has to be related with DispatcherServlet. It might be possible that Dispatcher Servlet only check for URL in @RestController annotated classes.

ASharma7
  • 726
  • 3
  • 8
  • 27
  • I don't know how you missed this from doc `Indicates that an annotated class is a "Controller" (e.g. a web controller).` https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Controller.html – Ryuzaki L Oct 13 '19 at 20:51

4 Answers4

3

@Controller is user in traditional controller and @RestController annotation was introduced to simplify the creation of RESTful web services. It's a convenience annotation that combines @Controller and @ResponseBody

@Controller annotation is simply a specialized of the @Component class and allows implementation classes to be autodetect through the classpath scanning.

@Controller is typically used in combination with a @RequestMapping annotation used on request handling methods.

The request handling method is annotated with @ResponseBody. This annotation enables automatic serialization of the return object into the HttpResponse.

@RestController is a specialized version of the controller. It includes the @Controller and @ResponseBody annotations and as a result, simplifies the controller implementation.

The controller is annotated with the @RestController annotation, therefore the @ResponseBody isn't required.

Every request handling method of the controller class automatically serializes return objects into HttpResponse.
see here in detail : https://www.baeldung.com/spring-controller-vs-restcontroller

Amit Kumar
  • 31
  • 4
2

Just because @RestController is a @Component does not mean you can achieve the same functionality by switching to the broader one @Component. Even with the addition of @ResponseBody, you don't achieve equivalent functionality (as expressed through the Request Method POST not being supported).

Replace @Component with @Controller, because a @RestController has the exact same functionality as a @Controller + @ResponseBody. You can also see this in the meta-annotations of @RestController, you see it is meta-annotated with @Controller instead of just @Component. In turn, @Controller is meta-annotated with @Component.

Mario Ishac
  • 5,060
  • 3
  • 21
  • 52
  • RestController = Controller (=Component) + ResponseBody, So effectively RestController = Component + ResponseBody – ASharma7 Oct 13 '19 at 20:55
  • @ASharma7 Your logic is faulty because while a `@RestController` IS a `@Component` plus `@ResponseBody`, it has extended functionality that a `@Component` + `@ResponseBody` does not offer. It's like saying a Tesla is a car, and while that is true, a Tesla has more functionality than a normal car that you might need. In order to get that extended functionality here (namely supporting HTTP request methods like `POST`, you need to have the `@Controller` + `@ResponseBody`, not `@Component` + `@ResponseBody`. – Mario Ishac Oct 13 '19 at 21:00
  • 1
    @ASharma7 you seem to assume that `@Controller` is equivalent to `@Component`. That is false. – Boris the Spider Oct 13 '19 at 21:15
  • @BoristheSpider I am NOT ASSUMING. I am showing the source code of Controller. Its nothing more than Component in source code. – ASharma7 Oct 13 '19 at 21:31
  • @ASharma7 again, you seem to assume that just because the annotation is only meta annotated there is nothing else going on. This is false. `@Controller` specifically demarcates a controller in the MVC framework. – Boris the Spider Oct 13 '19 at 21:33
1

The @Controller , @RestController , @Service etc are all annotations that are meta-annotated with the @Component annotation. All these annotations are essentially specializations of the @Component annotation for specific use cases. The @Component annotation is generally used to register a Spring bean.

The @Controller annotation even though it is annotated with @Component internally , it provides a different functionality altogether.By annotating a class with this annotation we are essentially telling spring to scan this class for @RequestMapping annotation to register beans for request mapping. This does not happen when you just use the @Component annotation.

When the spring application starts up, the DispatcherServlet will enable the RequestMappingHandlerMapping RequestMappingHandlerAdapter (which is a handler mapping which looks for @RequestMapping annotations on @Controllers). So when a request reaches the dispatcher servlet it gives it to the RequestMappingHandlerMapping which resolves the uri to a controller method bean.For more information read : DispatcherServlet, Updated Doc Spring 5.x HandlerMapping

Note : In older versions of spring DefaultAnnotationHandlerMapping is enabled for this by spring.

So in summary :

  • @Component is a generic stereotype for any Spring-managed component or bean.
  • @Repository is a stereotype for the persistence layer.
  • @Service is a stereotype for the service layer.
  • @Controller is a stereotype for the presentation layer (spring-MVC).

Spring [Doc][4].

The @Controller annotation indicates that a particular class serves the role of a controller.

The basic purpose of the @Controller annotation is to act as a stereotype for the annotated class, indicating its role. The dispatcher will scan such annotated classes for mapped methods, detecting @RequestMapping annotations (see the next section).

Annotated controller beans may be defined explicitly, using a standard Spring bean definition in the dispatcher's context. However, the @Controller stereotype also allows for autodetection, aligned with Spring 2.5's general support for detecting component classes in the classpath and auto-registering bean definitions for them.

Similar post : What's the difference between @Component, @Repository & @Service annotations in Spring?

Ananthapadmanabhan
  • 5,706
  • 6
  • 22
  • 39
  • I understand that. This is why i am getting status = 405. I also understand that official documentation says @Controller provides something special that it starts behaving like webcontroller. But if some functionality comes into picture, there must be source code behind that. My ask is the source code, which gives that Controller that special behaviour. I am asking this because I had been asked in one of interview – ASharma7 Oct 14 '19 at 05:21
  • @ASharma7Please read: https://docs.spring.io/spring/docs/3.0.0.RC2/spring-framework-reference/html/ch15s02.html and also on how handler mapping maps a request uri to a controller https://docs.spring.io/spring/docs/3.0.0.RC2/spring-framework-reference/html/ch15s04.html – Ananthapadmanabhan Oct 14 '19 at 05:27
  • @ASharma7I have updated the answer hope this clears things up for you. – Ananthapadmanabhan Oct 14 '19 at 05:33
  • The `DefaultAnnotationHandlerMapping` doesn't exists anymore its successor `RequestMappingHandlerMapping` and `RequestMappingHandlerAdapter` should be used instead. You are also linking to old (read ancient) documentation, you want to use the current one (Spring 5.2 not 3.0). – M. Deinum Oct 14 '19 at 08:19
0

You should not get the same behaviour because @Component is more generic. It only registers your class as a Spring Managed Bean. However, @RestController not only registers your class as a managed bean, it further registers it as an entry point for HTTP calls to the specified URL path. Same goes for other Layer specific annotations like @Repository, @Configuration e.t.c