How to implement Spring's 3.1 MvcAnnotationDriven? - java

This is the code example from Spring 3.1 Spring Source Blog: From XML to #Configuration I'm trying to implement in my application (which was done in Spring 2.0 not by me so it's lot of learning).
#FeatureConfiguration
class MvcFeatures {
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
// ...
}
However, I can't understand the point of .argumentResolvers(new CustomArgumentResolver()) and their CustomArgumentResolver looks like bellow. What's the point of it?
public class CustomArgumentResolver implements WebArgumentResolver {
#Override
public Object resolveArgument(MethodParameter param, NativeWebRequest request) throws Exception {
RequestAttribute attr = param.getParameterAnnotation(RequestAttribute.class);
if (attr != null) {
return request.getAttribute(attr.value(), WebRequest.SCOPE_REQUEST);
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}

To add to #GaryF's answer, and to clarify some points, Spring 2.5 introduced annotated controllers, which replaced the old interface-style controllers of Spring 2.0. These new controllers have methods with no fixed parameters - the method declares the parameters that it needs to do its job, and nothing more.
For example, say a controller method needed one thing to do its job - a request parameter that contains the ID of an object from the database. In Spring 2.0, you would need to implement something like AbstractController.handleRequestInternal(), e.g
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Spring 2.5 made that easier:
#RequestMapping
public ModelAndView handle(String id) {
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Here, we only declare parameters for the stuff we need.
So far so good, but this is where a custom WebArgumentResolver comes in. Say I want to remove the getObjById from my controller altogether, because maybe I think it clutters up the code, and maybe it's used across many other controller methods. Instead, I want to do this:
#RequestMapping
public ModelAndView handle(MyThing id) {
//... do stuff and return ModelAndView
}
It's even simpler, and has a bare minimum of boilerplate code. A custom WebArgumentResolver can be registered with the app-context which recognises parameters of type MyThing, and knows how to extract the information from the request. Spring invokes that resolver, and passes the result to the controller method.
Custom resolvers aren't commonly used, but can be very handy in the right situation.
The example in your question uses CustomArgumentResolver to resolve the example's custom RequestAttribute class. The resolver pulls out request attributes and binds them to RequestAttribute objects, so that they can be declared as controller method parameters.

WebArgumentResolvers are a way for you to specify how the parameters of MVC-mapped methods should be resolved. If you'd like to use a custom object as a parameter for an MVC-mapped method, Spring tries to figure out how make sense of it in it's own way. Typically this would happen through binding, where some http parameters you submit match up with the fields of the object and Spring matches them up and creates a new object for you.
If you ever have a situation where the submitted parameters don't match up quite so neatly with your method parameters, WebArgumentResolvers are there to fill in the gap: you provide custom logic so Spring doesn't have to figure it out.
In your example, param is one such parameter to be matched up. This piece of custom code first checks if the parameter has an #RequestAttribute annotation. If it does, then the custom code pulls the value from that object and looks it up as an attribute on the http request, returning it. It it does not have that annotation, then the method returns the UNRESOLVED value, which simply indicates that this WebArgumentResolver doesn't know anything about this particular parameter and Spring should try a different method (such as binding).

Related

How can I specify method with an parameterized annotation and its value with #Pointcut

Background:
I am developing an web application with Spring MVC.
I want to make an aspect that is executed on POST requests and not executed on GET requests, because I want to inject the logic that prevent POST requests which are sent before completion of HTML rendering.
#RequestMapping(value = "/aaa", method = RequestMethod.POST)
public String methodForPost(AnDto dto, Model model) {
// the aspect should be executed on this method
}
#RequestMapping(value = "/bbb", method = RequestMethod.GET)
public String methodForGET(AnDto dto, Model model) {
// the aspect shouldn't be executed on this method
}
Question:
How can I specify method with an parameterized annotation and its value with #Pointcut ?
How can I specify method with an parameterized annotation and its value in <aop:pointcut> in Spring applicationContext.xml?
#Around(value="#annotation(RequestMapping)")
public Object display(ProceedingJoinPoint joinPoint, RequestMapping requestMapping ) throws Throwable {
// You have access to requestMapping. From which you can get whether its get or post and decide to proceed or not.
}
More info http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj-advice-params-passing
You might have to extend this to intercept only for Requestmapping's in your package. Because this intercepts every RequestMappig you might have in your project including one used by the libraries which you might be using, which is a burden.

How is a #ModelAttribute injected without any explicit reference

I have a controller that works, but I do not understand why it works. Here it is:
#Controller
#RequestMapping("/someUrl")
public class MyController {
#Autowired
private SomeService someService;
#RequestMapping(method = RequestMethod.GET)
public String page() throws ApplicationException {
return "page";
}
#ModelAttribute("modelAttribute")
public PageModel loadPageModel() throws ApplicationException {
return someService.createPageModel();
}
}
Visiting "/someUrl" will get me to the view of the name "page", as it is expected. What is puzzling, is that despite the model attribute "modelAttribute", or an object of type "PageModel" is not referenced anywhere near the method page, the modelAttribute is still visible for the view. I am happy that this works, but I do not understand why. Any thoughts?
#ModelAttribute is somewhat overloaded, and serves two main functions depending on where it's declared.
With method parameter:
#RequestMapping(value="/create", method=POST)
public String createPage(#ModelAttribute("pageModel") PageModel pageModel) ...
For example, when #ModelAttribute is declared with a method parameter, and you submit parameters to that method, Spring will try to bind the submitted params to an object of type PageModel. Where does it get the PageModel: 1) if there's one currently in Spring managed model, use that 2) otherwise it will create a PageModel using the default constructor of PageModel object
At the method declaration (how you're using it):
#ModelAttribute("modelAttribute")
public PageModel loadPageModel() throws ApplicationException {
return someService.createPageModel();
}
In your case, when#ModelAttribute is declared at the method level, it tells Spring that the method will provide a PageModel before any RequestMapping is called for a particular request. The created PageModel instance is put into Springs managed model under a "modelAttribute" key. Then from your views, you should be able to reference that PageModel.
So the request goes something like this (i'm only showing relevant events):
request for /someUrl
Spring maps request to page() method
Spring see's that page() method is annotated with #RequestMapping so it calls all methods annotated with #ModelAttribute (at the method level) before executing page()
redirect to "page" view, where a PageModel under "modelAttribute" key is available for you to use
Note:
if your loadPageModel() method did not return a PageModel, it would still be called.
if you had multiple methods declared with #ModelAttribute at the method level, they would all be called each time a method with #RequestMapping is executed
As the contract for the ModelAttribute annotation puts it:
Annotation that binds a (..) method return value to a named model attribute, exposed to a web view.
Supported for controller classes with #RequestMapping methods.
In other words you are adding an attribute implicitely by returning it.
Why this works?
I don't know how internally Spring is doing it but what is enough for us to know is how we can make it eligible for Spring MVC to identify and make it available to the view which is well documented:
having #RequestMapping Controller methods (in your case implicitly defined at the class level)
having one of the supported return types that are combined with the ModelAttribute annotation.
of course being within the component-scan area
Have a good look at ModelAttributeMethodProcessor and lookup the handleReturnValue method. This method will be executed on controller methods annotated with #ModelAttribute.
/**
* Add non-null return values to the {#link ModelAndViewContainer}.
*/
#Override
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
if (returnValue != null) {
String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
mavContainer.addAttribute(name, returnValue);
}
}
You can see it simply adds it's return value to the model and is invoked with every request concerning that particular controller.
P.s. The starting point of most "magic" operations can be found in RequestMappingHandlerAdapter which is the default HandlerAdapter for modern Spring MVC applications.

Spring MVC Custom View

I am refactoring a legacy application to use Spring MVC. All of my controllers (legacy) return an object of type Model and my legacy dispatcher write the output of model.getContent(), the method getContent does internal processing and returns a json string. I have hundreds of controllers and do not want to rewrite them. Is it possible to write a custom view handler and include it in the spring servlet config?
Sample Controller:
public UserList extends BasicAction {
#Autowired
UserService userService;
#Autowired
UserCommand userCommand;
#Override
public Model getModel(Request req, Response resp)
throws ServletException, IOException {
Model model = new Model();
List<User> users;
try {
users = userService.getUsers((UserCriteria)userCommand.getResult());
model.addCollection(users);
model.setWrapper(new UserWrapper());
} catch (ValidationException e) {
e.printStackTrace();
} catch (WebCommandException e) {
e.printStackTrace();
}
return model;
}
}
I'm planning to annotate as #Controller. Specify the #RequestMapping or in the xml config, remove the base class BasicAction (legacy mvc). I've recently introduced spring to this project and refactored to use Dependency Injection and Request Scoped command objects (request wrappers)
The most straightforward is to implement View interface on your Model class. Then your legacy controllers can return this class directly (as they are now) and it will get rendered by DispatcherServlet via calling its render method.
Another possibility is to implement your own HandlerMethodReturnValueHandler, where the handler can actually render the response and mark the response as handled (mavContainer.setRequestHandled(true);) so that DispatcherServlet will not try to render any view.
I think what you want to do is create a custom ViewResolver that outputs your JSON response. This would be configured in Spring MVC to set the ViewResolver list, placing yours up top to have more precedence. The way it is supposed to work (from my recollection) is that Spring MVC will start at the top of the list, and try each ViewResolver until it finds one that returns the one that handles the return type. You will have to google how to make custom ViewResolvers, as I have only used them, never created one, but I know it's an interface so it should be do-able. I believe this would be the only way to do this that would not require any code changes in your controllers.
The more "preferred" method to do JSON, however, is to have Jackson in your classpath and simply return the object you want to serialize to JSON. Spring will auto-magically convert that to JSON, I believe using a ViewResolver they provide. But, I can surely relate to not wanting to refactor lots of working code.

How to pre-process the request body in Spring before passing it to the a Controller?

I am implementing a RESTful service and I would like to validate the XML against an XSD in an interceptor before passing it on the a CastorUnmarshaller.
Though, in the WebRequestInterceptor I have to read the request body which can only be read once so the unmarshaller cannot read it. Is there a way of doing it?
I know that I can do both the validation and the unmarshalling manually in the Controller, but I would like to use the #RequestBody <DomainObject> way to unmarhall it.
Alternatively, as another solution, is there a way to tell the CastorUnmarshaller to validate it against the xsd?
Quite a long time passed, but someone else might benefit from this:
You can define an #Around aspect and intercept the incoming requests and their respective bodies as follows:
#Aspect
#Component
public class RequestResponseLoggingAdvice {
private static final Logger logger = LoggerFactory.getLogger(RequestResponseLoggingAdvice.class);
#Pointcut("within(#org.springframework.web.bind.annotation.RestController*)")
public void restcontroller() {}
#Pointcut("#annotation(org.springframework.web.bind.annotation.PostMapping)")
public void postmapping() {}
#Around("restcontroller() && postmapping() && args(.., #RequestBody body, request)")
public Object logPostMethods(ProceedingJoinPoint joinPoint, Object body, HttpServletRequest request) throws Throwable {
logger.debug(request.toString()); // You may log request parameters here.
logger.debug(body.toString()); // You may do some reflection here
Object result;
try {
result = joinPoint.proceed();
logger.debug(result.toString());
} catch(Throwable t) {}
}
}
Please note that your REST controller methods have to have suitable signatures for the above aspect can hook in. A sample one could be as follows:
#PostMapping
public SampleDTO saveSample(#RequestBody Sample sample, HttpServletRequest request) {
//.....
}
You can probably attach a #Before aspect (spring AOP). There you can get the same request body parameter as passed to the controller method.
Another option is to wrap the request into one that supports reading the body multiple times (by caching it the first time)
A filter can also be used to validate the XML passed.
org.springframework.oxm.castor.CastorMarshaller has a validating property to enable validation on in- and out-going documents.
But enabling it in Spring-MVC's default marshaller must be solved.

cache controller response

I'd like to use memcached to cache the response produced by my controllers. The controllers themselves are Grails controllers, but there's nothing really Grails-specific about the problem. If I could figure out how to solve this problem in a Spring MVC, Struts (or similar) application, I should easily be able to migrate the solution to Grails.
Ideally, I'd like to identify the controller methods that are eligible for caching using Java annotations. Is anyone aware of an existing solution for this problem? I should emphasise that I'm not interested in using any caching technology other than memcached.
Thanks,
Don
The Simple Spring Memcached library the previous poster linked to would actually accomplish what you need to do. It doesn't limit itself to just DAO methods. You could annotate a controller method to cache it's response just as easily as annotating a DAO method.
So, if you have a Controller named SimpleController and you wanted to cache the response of that controller, you could do the following
public class SimpleController implements Controller {
#ReadThroughSingleCache(namespace = "SimpleController", keyIndex = 0, expiration = 3600)
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView("index")
}
This will cache the response of the controller in Memcached for an hour and any request that comes in that matches the same request will return the cached response.
Aaron, braveterry,
Thanks for suggesting my project: http://code.google.com/p/simple-spring-memcached/
Don, Aaron is correct that SSM is not limited to DAO methods, however there are a few caveats for his example:
I don't think HttpServletRequest's toString() method would produce a good key
You would need to make sure that ModelAndView is Serializable
That being said, there's no reason you can't delegate to another bean that has an appropriate signature
Here's some code as an example:
public class SimpleController implements Controller {
private BeanWithAnnotatedMethod bean; // Injected resource
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
Object keyObject = Helper.generateAppropriateKey(request);
String result = bean.annotatedMethod(keyObject);
return new ModelAndView(result)
}
Would something like this do the trick? http://code.google.com/p/simple-spring-memcached/

Categories

Resources