Spring MVC request / command objects - spring

Is there a convenient way to turn something like this..
#RequestMapping("/some/action/{q}/...")
public void doSomething(#PathVariable("q"), oh, my, god, a, billion, annotated parameters) { .. }
Into something like this..
#RequestMapping("/some/action/{q}/...")
public void doSomething(NiceEncapsulatingRequetObject request) { .. }
With Spring MVC?

After checking the docs, it doesn't seem like it is supported out of the box. You could try to create your own HandlerMethodArgumentResolver which gives you this feature. You might run into some issues since you'll need a circular reference between your implementation and the HandlerMethodArgumentResolverComposite instance. Nevertheless I think it should be possible.

Yes spring supports this out of the box, it is usualy refered to as bean binding.
Basicly you create an object with paramaters with the same name,
so if you have a paramater "q", your object should contain a private string q with both getter and setter present. It's also prefered not to use any constructors.
Spring will just fill in the paramaters it has in your object and pass it via the method's paramater.

You can create you own object like NiceEncapsulatingRequetObject and it's attributes should be String oh, Integer my etc. If you send the request with the exact names it will work

Related

Coding to an interface on a Spring Controller method with #RequestMapping

I have a Controller with the following method:
#RequestMapping(method = POST)
public ModelAndView emailRegister(EmailParameter parameters, ModelMap model) {}
Where EmailParameter is an interface. I understand Spring (magically?) maps the incoming HTTP parameters to my object fields by name, and it can't do this as I have declared an Interface.
Is it possible to declare an interface here, if so is there additional config I need somewhere?
I don't have extensive programming experience so I may be wrong in trying to use an Interface type here, but I believe this is what I should be doing?
Additionally if someone could explain how Spring maps the request parameters to my object fields, that would be much appreciated. Or a link to where this is explained, as I haven't been able to find one!
Thanks
You shouldn't use Interface because Spring needs to instantiate that object, otherwise you will be requiring the property editors OR converters.
Read the following post to know about How Spring MVC Binds Parameter?
Read section "Binding Domain Object" in following link.
https://web.archive.org/web/20160516151809/http://www.jpalace.org/document/92/binding-and-validation-of-handler-parameters-in-spring-mvc-controllers

ArgumentResolvers within single transaction?

I am wondering if there is a way to wrap all argument resolvers like for #PathVariables or #ModelAttributes into one single transaction? We are already using the OEMIV filter but spring/hibernate is spawning too many transactions (one per select if they are not wrapped within a service class which is be the case in pathvariable resolvers for example).
While the system is still pretty fast I think this is not necessary and neither consistent with the rest of the architecture.
Let me explain:
Let's assume that I have a request mapping including two entities and the conversion is based on a StringToEntityConverter
The actual URL would be like this if we support GET: http://localhost/app/link/User_231/Item_324
#RequestMapping("/link/{user}/{item}", method="POST")
public String linkUserAndItem(#PathVariable("user") User user, #PathVariable("item") Item item) {
userService.addItem(user, item);
return "linked";
}
#Converter
// simplified
public Object convert(String classAndId) {
return entityManager.find(getClass(classAndId), getId(classAndId));
}
The UserService.addItem() method is transactional so there is no issue here.
BUT:
The entity converter is resolving the User and the Item against the database before the call to the Controller, thus creating two selects, each running in it's own transaction. Then we have #ModelAttribute methods which might also issue some selects again and each will spawn a transaction.
And this is what I would like to change. I would like to create ONE readonly Transaction
I was not able to find any way to intercept/listen/etc... by the means of Spring.
First I wanted to override the RequestMappingHandlerAdapter but the resolver calls are well "hidden" inside the invokeHandleMethod method...
The ModelFactory is not a spring bean, so i cannot write an interceptor either.
So currently I only see a way by completely replacing the RequestMappingHandlerAdapter, but I would really like to avoid that.
And ideas?
This seems like a design failure to me. OEMIV is usually a sign that you're doing it wrong™.
Instead, do:
#RequestMapping("/link/User_{userId}/Item_{itemId}", method="POST")
public String linkUserAndItem(#PathVariable("userId") Long userId,
#PathVariable("itemId") Long itemId) {
userService.addItem(userId, itemId);
return "linked";
}
Where your service layer takes care of fetching and manipulating the entities. This logic doesn't belong in the controller.

Update field annotated with #Value in runtime

Let's imagine we have such a component in Spring:
#Component
public class MyComponent {
#Value("${someProperty}")
private String text;
}
If we define the property placeholder:
<context:property-placeholder location="classpath:myProps.properties"/>
And myPropos.properties contains the value for someProperty the value will be injected to the text field when the context is initialized. That's quite simple and easy.
But let's say that I have a service that enables user to change the value of the someProperty:
public void changeProp(String name, String newValue);
Is there a chance I can re-inject the newValue to text field. I mean it should be quite straight forward.. Basically it's nothing different than the after-initialization injection. I can not imagine that Spring does not have support for this? Can I fire some event or something?
I could do this on my own basically, but I wander is it maybe something there already? If not does anyone know what Spring class is in fact handling the injections at the first place? I could probably reuse the code there do perform this on my own if a solution does not exists.
I expect spring does not have a support for this, because the normal injection is done while creating the bean, but not will it is put in service.
Anyway: in this blog entry "Reloadable Application Properties with Spring 3.1, Java 7 and Google Guava", you can find the idea for an solution.
The key idea is to use a post processor to build a list of all fields with property fields. And if the properties are changed on can use this list to update the fields.

Spring 3.1.RC1 and PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE

Posted in spring forum with no response.
I have the following code snippet (from here), which is part of my pet project.
#Controller
#RequestMapping("/browse")
public class MediaBrowser {
...
#RequestMapping("/**")
public final ModelAndView listContents(final HttpServletRequest request) {
String folder = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
I access the following url:
http://localhost:8080/myapp/browse
In spring 3.0.6.RELEASE, I got the folder variable as null, which is the expected value.
In spring 3.1.RC1, the folder variable is /browse.
Is this a bug or has something changed in spring-3.1?
As skaffman said, you probably shouldn't use PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE. Take a look at How to match a Spring #RequestMapping having a #pathVariable containing "/"? for an example of using AntPathMatcher to accomplish what you are trying
This looks very much like an internal implementation detail of the framework, one that you should not be relying on.
The javadoc for PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE says:
Note: This attribute is not required to be supported by all HandlerMapping implementations. URL-based HandlerMappings will typically support it, but handlers should not necessarily expect this request attribute to be present in all scenarios.
I wouldn't be surprised if the behaviour changed slightly between 3.0 and 3.1.

MarshallingView in Spring to adjust output?

I have some POJOs which are the basis for this RESTful API I am working on. However, some of the responses I need to include some other information to make the API more complete. I really don't want to put these extra information in the POJO, but include it at the web service layer as if it were.
It deals with "People" who have "Appointments". Each appointment only has one person.
So, I have a RESTful call like /Patients/1 and it basically grabs the POJO for the Person and I am currently using XStream to serialize it and send it on its way. This works great, but I would like to do something like this:
<Person>
<firstName>James</firstName>
... other fields ...
<nextAppointment href="/Appointment/12345>2010-02-19</nextAppointment>
<prevAppointment href="/Appointment/12346>2010-01-01</prevAppointemnt>
</Person>
Where next and prev appointment are not actually included in the Person POJO. I am looking for a good "spring way" to accomplish this. The client could do something like this /Patients/1/PreviousAppointment and /Patients/1/NextAppointment, but I am looking to cut the amount of calls (maybe pre-optimization?) and give them a way to get more information if they need it by using he href.
It is very elegant using the XStreamMarshaller since all I do it hand the view the POJO or list of POJO and it handles it. But I need to doctors those up a bit before they are sent out.
Thanks!
This is the problem with handing your business objects directly to the marshaller - you have very little flexibility in how they turn that object into the response. There is something to be said for pre-transforming the objects yourself, you get more control that way.
So if you have a specific output structure that you want, then with XStream you need to build a class structure that looks like it. You then transform your business objects into that class structure, and pass that to XStream instead.
It may seem less elegant, but your system will be much less prone to being broken by small changes in your business object model, which you your current XStream-based system will be.
Solution to your problem : CREATE A CUSTOMIZEDCONVERTER...
public class CustomizedConverter implements Converter {
#Override
public void marshal(Object source, HierarchicalStreamWriter writer,MarshallingContext context) { ....}
#Override
public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {..}
#Override
public boolean canConvert(Class clazz) {..}
}
To know what to use the converter with the Marshaller refer this.
So basically the CONVERTER works on the POJO and ensures we get the XML response as given in the contract.

Resources