Are annotations applicable to subclasses? - java

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 #RestController annotation necessary for UserController 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 of annotationType on the supplied Class,
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.

Related

Spring Boot | Using a separate file for logic

I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure

Interfaces are annotated with #Component annotation in spring IoC/DI. What could be the reason?

Some times interfaces are annotated with #Component annotation. Then my obvious reasoning was that classes that implement such interface will be treated as components as well. But if I am right that is not the case.
So what is the purpose of #Component annotation on interfaces.
Annotating an interface with #Component is common for Spring classes, particularly for some Spring stereotype annotations :
package org.springframework.stereotype;
...
#Component
public #interface Service {...}
or :
package org.springframework.boot.test.context;
...
#Component
public #interface TestComponent {...}
#Component is not declared as an inherited annotation :
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Component {...}
But whatever, during loading of the context, Spring discovers beans by considering the hierarchy of the annotation declared in the candidate class.
In the org.springframework.boot.BeanDefinitionLoader class (included in the Spring Boot dependency) that loads bean definitions from underlying sources, you can see an example of
org.springframework.core.annotation.AnnotationUtils.findAnnotation() that Spring uses to retrieve annotations in the whole hierarchy of the annotation:
class BeanDefinitionLoader {
...
private boolean isComponent(Class<?> type) {
// This has to be a bit of a guess. The only way to be sure that this type is
// eligible is to make a bean definition out of it and try to instantiate it.
if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
return true;
}
// Nested anonymous classes are not eligible for registration, nor are groovy
// closures
if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass()
|| type.getConstructors() == null || type.getConstructors().length == 0) {
return false;
}
return true;
}
...
}
Concretely, it means as the #Service annotation is itself annotated with #Component, Spring will consider a candidate class annotated with #Service as a bean to instantiate.
So, your guesswork is right :
Classes that implement such interface will be treated as components as
well.
But this works only for interfaces (such as #Service) that are Java annotations and not for plain interfaces.
For Spring classes, this way of doing makes sense (enriching actual stereotype for example) but for your own beans, using #Component for the interface rather than the implementation will not work and would bring more drawbacks than advantages :
it defeats in a same way the purpose of an interface that is above all a contract. It couples it to Spring and it supposes that you will always have a single implementation of the class. In this case, why using an interface ?
it scatters the reading of the class at two places while the interface doesn't need to have any Spring stereotype.
That is not the case there is no need to adding #component on an interface because it is not a bean as we can't create reference for it.
The main part is actually #autowired where you injection the dependecy.
For example
public interface SortAlog();
public class BubbleSortAlgo();
No we are following the dynamic binding and creating the object of interface but implementation is on the run time.
So #autowired is the one that will create the object internally and we have #component for bubbleSortAlgo and the only candidate for the injection, so it will get reference from there.
I hope I was able to make a point here.

#Controller annotation and Controller Classes in Spring MVC

When I am using Spring 3.x
While using annotations its difficult for me to know Which type of Controller class we are going to fetch using this #Controller
With reference to
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/Controller.html
These are implementing Controller class
AbstractController
AbstractUrlViewController
MultiActionController
ParameterizableViewController
ServletForwardingController
ServletWrappingController
UrlFilenameViewController
AbstractWizardFormController
SimpleFormController
However when we are using #Controller annotation in our Spring MVC
program how to know that Our #Controller annotation is implementing
any of these controllers, Kindly anyone explain me
I think you are missing the point here. In the old times to register a controller, your class must have implemented controller interface and choose request mapping type. Sometimes you had to implement lots of code to achieve single request mapping.
Nowadays, when we have annotations, the model has changed. We can handle multiple request types per controller class. Because in single #Controller annotated class we can handle many request mappings.
Controller annotation is a specialized #Component, that tells Spring that inside it will find #RequestMapping handlers. Those handlers can be used either for returning Json, HTML or for uploading files.
Now logic connected with same module can be placed under single controller class, you are more flexible in what you want to achieve. Secondly #Controller enables us to reduce code anount significantly.
You aren't using any of those classes. You confuse the Controller interface with the annotation.
The annotation is just a marker that states that your bean is a Spring Controller and can send an receive HTTP requests.
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Controller.html
The Controller interface was introduced when there were no annotations in the Java language.
Which type of Controller class we are going to fetch using this
#Controller ?
The #Controller annotation is to tell the web container that this is the controller class for requests with urls specified with #RequestMapping(URI). you are going to fetch no class if you are annotating your class with #Controller , you just need to provide a request handler method within the class and annotate it with #RequestMapping , though the controller class can also be annotated with #RequestMapping and in that case , only method inside the class will work as request handler method.
how to know that Our #Controller annotation is implementing any of
these controllers ?
The names of the classes you have mentioned are implementing Controller interface , not that #Controller annotation is implementing anything .Those controller classes are for specific purposes ,as their names suggest .

Can we extend the controller in Spring MVC?

Can we extend the controller in Spring MVC? How should we handle the #RequestMapping in the extended controller class? If anyone has any example please share. Thanks.
If BaseController's annotation cannot be removed, then you can use Adapter Pattern to obtain the inheritance.
#Controller
public class NewController {
// Autowired fields
BaseController base;
protected x toExtend() {
base.toExtend();
//new stuff
}
}
In usual cases, either BaseController does not have #Controller annotation, hence common controller methods can be put inside BaseController to be extended by actual controllers

Spring-MVC Problem using #Controller on controller implementing an interface

I'm using spring 2.5 and annotations to configure my spring-mvc web context. Unfortunately, I am unable to get the following to work. I'm not sure if this is a bug (seems like it) or if there is a basic misunderstanding on how the annotations and interface implementation subclassing works.
For example,
#Controller
#RequestMapping("url-mapping-here")
public class Foo {
#RequestMapping(method=RequestMethod.GET)
public void showForm() {
...
}
#RequestMapping(method=RequestMethod.POST)
public String processForm() {
...
}
}
works fine. When the context starts up, the urls this handler deals with are discovered, and everything works great.
This however does not:
#Controller
#RequestMapping("url-mapping-here")
public class Foo implements Bar {
#RequestMapping(method=RequestMethod.GET)
public void showForm() {
...
}
#RequestMapping(method=RequestMethod.POST)
public String processForm() {
...
}
}
When I try to pull up the url, I get the following nasty stack trace:
javax.servlet.ServletException: No adapter for handler [com.shaneleopard.web.controller.RegistrationController#e973e3]: Does your handler implement a supported interface like Controller?
org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1091)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
javax.servlet.http.HttpServlet.service(HttpServlet.java:627)
However, if I change Bar to be an abstract superclass and have Foo extend it, then it works again.
#Controller
#RequestMapping("url-mapping-here")
public class Foo extends Bar {
#RequestMapping(method=RequestMethod.GET)
public void showForm() {
...
}
#RequestMapping(method=RequestMethod.POST)
public String processForm() {
...
}
}
This seems like a bug. The #Controller annotation should be sufficient to mark this as a controller, and I should be able to implement one or more interfaces in my controller without having to do anything else. Any ideas?
What I needed to do was replace
<tx:annotation-driven/>
with
<tx:annotation-driven proxy-target-class="true"/>
This forces aspectj to use CGLIB for doing aspects instead of dynamic proxies - CGLIB doesn't lose the annotation since it extends the class, whereas dynamic proxies just expose the implemented interface.
Ed is right, adding
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
works fine
If you wish to use interfaces for your Spring MVC controllers then you need to move the annotations around a bit, as mentioned in the Spring docs: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping
Using #RequestMapping On Interface Methods A common pitfall when
working with annotated controller classes happens when applying
functionality that requires creating a proxy for the controller object
(e.g. #Transactional methods). Usually you will introduce an interface
for the controller in order to use JDK dynamic proxies. To make this
work you must move the #RequestMapping annotations to the interface as
well as the mapping mechanism can only "see" the interface exposed by
the proxy. Alternatively, you could activate proxy-target-class="true"
in the configuration for the functionality applied to the controller
(in our transaction scenario in ). Doing so
indicates that CGLIB-based subclass proxies should be used instead of
interface-based JDK proxies. For more information on various proxying
mechanisms see Section 8.6, “Proxying mechanisms”.
Unfortunately it doesn't give a concrete example of this. I have found a setup like this works:
#Controller
#RequestMapping(value = "/secure/exhibitor")
public interface ExhibitorController {
#RequestMapping(value = "/{id}")
void exhibitor(#PathVariable("id") Long id);
}
#Controller
public class ExhibitorControllerImpl implements ExhibitorController {
#Secured({"ROLE_EXHIBITOR"})
#Transactional(readOnly = true)
#Override
public void exhibitor(final Long id) {
}
}
So what you have here is an interface that declares the #Controller, #PathVariable and #RequestMapping annotations (the Spring MVC annotations) and then you can either put your #Transactional or #Secured annotations for instance on the concrete class. It is only the #Controller type annotations that you need to put on the interface because of the way Spring does its mappings.
Note that you only need to do this if you use an interface. You don't necessarily need to do it if you are happy with CGLib proxies, but if for some reason you want to use JDK dynamic proxies, this might be the way to go.
There's no doubt that annotations and inheritance can get a little tricky, but I think that should work. Try explicitly adding the AnnotationMethodHandlerAdapter to your servlet context.
http://static.springframework.org/spring/docs/2.5.x/reference/mvc.html#mvc-ann-setup
If that doesn't work, a little more information would be helpful. Specifically, are the two annotated controller methods from the interface? Is Foo supposed to be RegistrationController?
I know it is too late but i'm writing this for anyone have this problem
if you are using annotation based configuration... the solution might be like this:
#Configuration
#ComponentScan("org.foo.controller.*")
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig { ...}
The true reason you need to use 'proxy-target-class="true"' is in DefaultAnnotationHandlerMapping#determineUrlsForHandler() method: though it uses ListableBeanFactory#findAnnotationOnBean for looking up a #RequestMapping annotation (and this takes care about any proxy issues), the additional lookup for #Controller annotation is done using AnnotationUtils#findAnnotation (which does not handles proxy issues)

Categories

Resources