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

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)

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

Better practice with Spring MVC: Service with non-fixed dependency

I have a requirement of compatibility with a new architecture based in Spring 3.2. The requirement is: a http request will come to a controller with an attribute that defines which kind of object is required. For example ...mycontroller/load?objType='obj1'.
My controller will have this structure:
#Controller
public class myController{
private ObjectService objectService;
#Autowired
public setObjectService(ObjectService objectService){
this.objectService = objectService;
}
}
So after that, I need to check this attribute to decide which service will I use. For example, this case is Obj1Service (method: "load"). All this services are extended from ObjectService, so: It is a good idea to swap objectService dependency to Obj1Service / Obj2Service in each incoming call? For example:
if(objType.equals("obj1")) this.setObjectService(context.getBean("obj1Service"..))
if(objType.equals("obj2")) this.setObjectService(context.getBean("obj2Service"..))
I know that is not a great design, but we need to integrate this new modules with other system that produces this kind of http requests.
It is necessary the inheritance because we have very similar behavior in many service's code, but with modifications in internal methods, so part of the behavior will be placed in ObjectService (it is not abstract) and other portion of the code will be placed in it children. Is there another way, more appropriate, to do this? Or you consider that is an acceptable solution?
Thanks!
You can use a map for all of your services, and get the appropriate service inside each controller method.
Let's say you have two services:
#Service("obj1")
public class ObjectServiceImpl1 implements ObjectService {
...
}
#Service("obj2")
public class ObjectServiceImpl2 implements ObjectService {
...
}
In your controller:
private Map<String, ObjectService> objectServices;
#Autowired
public setObjectServices(Map<String, ObjectService> objectServices){
this.objectServices= objectServices;
}
Spring will inject the map with all the ObjectService beans mapped by their names.
In load?objType=obj1 handler, you would have something like:
objectServices.get("obj1").doSomething(); // will use ObjectServiceImpl1
The same with load?objType=obj2 handler:
objectServices.get("obj2").doSomething(); // will use ObjectServiceImpl2
And so on.

Rest + Spring AOP + interface doesn't inject

I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.

Migration to Spring Annotated Controllers and traditional onSubmit method

I am trying to migrate from Spring 2.0 to Spring 3.0.
Previously I defined a controller MyController inheriting from SimpleFormController and have some logic written in the onSubmit method. All my controllers having the handler methods are inherited from MyController. Thus, the logic written in onSubmit of MyController used to get executed for all requests.
Now as I migrate to annotated controller wherein my controller is a simple pojo, how do I ensure the execution of onSubmit everytime? One way is to call onSubmit from all handler methods of all the controllers. This is cumbersome.
Can anyone suggest any feasible solution. As annotating formBackingObject with #ModelAttribute ensures the invocation for all requests, isn't there an analogy for onSubmit method?
If you want to perform the same action before each invokation of any annotated controller, you could use an interceptor. You can write your own interceptor by just implementing the preHandle method.
You will then need to register this interceptor in the DefaultAnnotationHandlerMapping or whatever Handler mapping you use to dispatch to your controllers.
Registering interceptors is explained in this article:
http://www.scottmurphy.info/spring_framework_annotation_based_controller_interceptors
Annotate the method you wish to invoke. The method signature is very flexible. Take a look at the docs for #RequestMapping
#RequestMapping(value={"/foo"}, method=RequestMethod.POST)
public String myMethod(many options for parameters) {...
Ok so if i understand correctly you want inheritance to continue to play a role in the stack when a request is handled by a controller. You can extend any class in an #RequestMapping annotated POJO but you will have to define an #override method to annotate it. All you do basically is call super with the arguments in the overriding method. If you extend an annotated class and both are declared as Controller then you will get an exception since the route will be defined more then once.
it would look like this
public class Pojo{
public String someBaseMethod(){
return "";
}
}
#Controller
public class ChildController extends Pojo {
#Override
#RequestMapping("/do_it")
public String someBaseMethod() {
return super.someBaseMethod();
}
}
A good case could be made to use composition over inheritance. I even suggest that you use the filtering mechanism instead if it can apply to perform common operations. AOP could also be a good tool.

Whats the best way to inject same instance of service in service for Spring AOP

I'va a ServiceImpl with is annotated with #Service stereotype of Spring and have two methods in it each one is annotated with custom annotations which are intercepted by Spring.
#Service
public class ServiceImpl implements Service{
#CustomAnnotation
public void method1(){
...
}
#AnotherCustomAnnotation
public void method2(){
this.method1();
...
}
}
}
Now Spring uses proxy based AOP approach and hence as I'm using this.method1() interceptor for #CustomAnnotation will not able to intercept this call, We used to inject this service in another FactoryClass and in that way we were able to get the proxy instance like -
#AnotherCustomAnnotation
public void method2(){
someFactory.getService().method1();
...
}
I'm now using Spring 3.0.x, which is the best way to get the proxy instance?
The other alternative is to use AspectJ and #Configurable.
Spring seems to be going towards these days (favoring).
I would look into it if you are using Spring 3 as it is faster (performance) and more flexible than proxy based aop.
Both methods are inside the same proxy, whereas the AOP functionality just enriches calls from the outside (see Understanding AOP Proxies). There are three ways for you to deal with that restriction:
Change your design (that's what I would recommend)
Change proxy type from JDK-proxy to proxy-target-class (CGLib-based subclassing) Nope, that doesn't help, see #axtavt's comment, it would have to be static AspectJ compilation.
Use ((Service)AopContext.currentProxy()).method1() (Works, but is an awful violation of AOP, see the end of Understanding AOP Proxies)
You could make your ServiceImpl class implement the BeanFactoryAware interface, and lookup itself thanks to the provided bean factory. But this is not dependency injection anymore.
The best solution is to put method1 in another service bean, which would be injected in your existing service bean and to which your existing service bean would delegate.

Categories

Resources