Spring MVC 3.0.7 in Liferay - ActionMapping without annotations - spring

I would like to make the same mapping as :
#Controller
#RequestMapping ("VIEW")
public class MyController extends AbstractController {
#RenderMapping (params = "action=changePage")
public String changePage (#ModelAttribute () final MyFormulaire form, final RenderRequest renderRequest, final RenderResponse renderResponse, final Model model) {
return "test";
}
}
but without using annotations and by configuring all the beans and mapping using xml.
Is it possible to do such a thing ? I didn't find documentation about mapping params in spring xml files.
Thanks

There is a question asked before similar to yours, here is the link; https://stackoverflow.com/a/4497616/1241311
An example of how to do it pre-spring 2.5;
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/doSomething/**" value-ref="controllerA"/>
<entry key="/otherThing/**" value-ref="controllerB"/>
</map>
</property>
</bean>
It seems this is a known issue and there is an improvment ticket, you can find more info in here; SPR-5757

Related

spring custom converter from basic type other than string not found

I am using Spring 3.1 and i wrote a custom converter
public class CategoryConverter implements Converter<Long, Category> {
#Override
public Category convert(String id) {
return BeanProvider.getCategoryDAO().get(id);
}
}
and wired it with mvc in the application context
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="converter.CategoryConverter"/>
</set>
</property>
</property>
Whenever i send the form (that sends a number, namely, the id) then I get a no matching editors or conversion strategy found exception.
If i declare the Converter as Converter<String, Category> then it miraculously works.
Can anybody point out, why it works only with string and not with long. Is there a way to define the converter in a way, so it works with type Long too?

Upgrading to spring-3.1 seems to break my CustomWebArgumentResolver

I'm trying to upgrade a spring MVC app from 3.0.6 to 3.1.2 and some controllers that used to work don't seem to work anymore. I've read the spring docs, but I'm confused about what's compatible with what.
We've got a CustomWebArgumentResolver that looks for any request parameter named "asOf" and coverts its value to a date. We call it, unimaginatively, the "AsOfDateConverter." When upgrading to spring-3.1.2, I took advantage of the new namespace functionality and added this to my applicationContext:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:argument-resolvers>
<bean id="customWebArgumentResolver" class="my.converters.CustomWebArgumentResolver">
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
The CustomWebArgumentResolver is straightforward:
public class CustomWebArgumentResolver implements WebArgumentResolver {
private AsOfDateConverter asOfDateConverter;
#Override
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {
if (isAsOfDateParameter(methodParameter)) {
return asOfDateConverter.convert(webRequest.getParameter("asOf"));
}
return UNRESOLVED;
}
Then an example controller might look something like this:
#Controller
#Secured({BaseController.ROLE_LOGGED_IN})
#org.springframework.transaction.annotation.Transactional
public class DashboardController extends BaseController {
public static final String URL = "/dashboard";
#RequestMapping(value=URL, method=RequestMethod.GET)
public ModelAndView get(#RequestParam(required=false) String requestedMeterType, #AsOf Date asOf) {
debug(log, "Rendering dashboard asOf %s", asOf);
etc etc
The "asOf" parameter is coming in null, and I'm sure I'm missing something obvious. If anyone out there neck deep in the latest MVC 3.1 stuff could point me in the right direction I'd be grateful.
Thanks!
Tom
EDIT:
The AsOf annotation:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
public #interface AsOf {
}
More of my applicationContext:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:argument-resolvers>
<bean class="[blah].AsOfDateHandlerMethodArgumentResolver">
<property name="asOfDateConverter">
<bean class="[blah].AsOfDateConverter"/>
</property>
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
<!-- Added to re-support #Controller annotation scanning after upgrading to spring-3.1. -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="[blah].converters.CustomerConverter"/>
<bean class="[blah].converters.AccountConverter"/>
<bean class="[blah].converters.DateConverter"/>
<bean class="[blah].converters.CustomerCommunicationInstanceConverter"/>
<bean class="[blah].converters.MeterTypeConverter"/>
<bean class="[blah].converters.AreaAmountConverter" p:precision="0"/>
<bean class="[blah].converters.LengthAmountConverter" p:precision="1"/>
</set>
</property>
</bean>
The API has changed with Spring 3.1 - the interface to implement to resolve a controller argument is HandlerMethodArgumentResolver. You can continue to use CustomWebArgumentResolver, by adapting it to a HandlerMethodArgumentResolver
However changing the code to use HandlerMethodArgumentResolver also will be easy:
public class CustomWebArgumentResolver implements HandlerMethodArgumentResolver {
private AsOfDateConverter asOfDateConverter;
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
if (isAsOfDateParameter(methodParameter)) {
return asOfDateConverter.convert(webRequest.getParameter("asOf"));
}
return UNRESOLVED;
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (methodParameter.getParameterAnnotation(AsOf.class)!=null)
}
Edit
After looking through your comments, I think I have an idea about what could be going wrong. Can you please check your #AsOf annotation, you probably have not declared the retention of Runtime, which could be the reason why the the WebArgumentResolver is not taking effect:
#Retention(RetentionPolicy.RUNTIME)
public #interface AsOf {
}
Anyway here is a gist with a full working test along the same lines:
https://gist.github.com/3703430

Spring MVC 3.1 without annotations?

I'm starting a new project with Spring 3.1, and have been eyeball deep in all the documentation and forum opinions about how to use the #Controller annotation.
I personally dislike using annotations for MVC; I much prefer having all the URLs of a webapp available in one place, using SimpleUrlHandlerMapping.
Also, from much previous work using Spring 2.x, I'm very used to the BaseCommandController heirarchy.
I've always loved Spring because it's empowering without being restricting. Now I find Spring MVC is forcing me to put URLs into the java source, meaning (a) I can't map a controller to several URLs, and (b) to discover what URLs are in use in a webapp, I have to scan through different java source files, which I find impractical.
What is the recommended way of combining #Controller with SimpleUrlHandlerMapping, please ?
Update:
Hi Dave, are you saying you can map multiple URLs like this (altered from petclini.web.ClinicController)?
#RequestMapping({"/vets", "/another"})
public ModelMap vetsHandler() {
If this works then good.
My question still stands though:
If I don't want URLs in my java source, how best to map them with #Controller classes?
Regards,
Here is a simple set up to support annotation and non-annotated controllers.
Dispatcher servlet configuration xml
<mvc:annotation-driven/>
<bean id="testController" class="com.test.web.TestController"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/test=testController
</value>
</property>
<property name="order" value="0"/>
</bean>
A simple URL mapped controller
public class TestController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
PrintWriter responseWriter = response.getWriter();
responseWriter.write("test");
responseWriter.flush();
responseWriter.close();
return null;
}
}
The controller for mvc annotation-config
#Controller
#RequestMapping("/home")
public class HomeController {
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String dashboard(Model model, HttpServletRequest request) {
return "home";
}
}
If you want to use your own handlers for #Controller annotation. you can probably look into ClassPathBeanDefinitionScanner and DefaultAnnotationHandlerMapping.determineUrlsForHandlerMethods.

How to access Spring RequestContext from a Freemarker TemplateDirectiveModel

I'm using Spring MVC with Freemarker as view technologie. I have a TemplateDirectiveModel object which needs to access Spring's RequestContext within the execute method. Currently I do it like this:
public class MyDirective implements TemplateDirectiveModel
{
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException
{
StringModel model = (StringModel) env.getGlobalVariable("springMacroRequestContext");
RequestContext requestContext = (RequestContext) model.getWrappedObject();
}
}
But I can't believe that this is the right way to do it. I have the feeling I missed something important. Maybe there are special classes and annotations for handling Freemarker direcives in Spring? Maybe I can let Spring inject something into the directive class with which I can access Springs request scope?
You could subclass FreeMarkerConfigurer, overriding its postProcessConfiguration(Configuration config)method.
Your implementation would just put a request-aware dependency in the configuration, as a shared variable for example (as preconised by the FM documentation).
Should do the trick, Spring-style...
There is an easier way to do this. If you are already using spring's FreeMarkerConfigurer, you can hand it a map of variables:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
p:templateLoaderPath="/some_path_here">
<property name="freemarkerVariables">
<map>
<entry key='macroName' value-ref="templateModelRef" />
</map>
</property>
</bean>
<bean id="templateModelRef" class="...class..extends TemplateModel">
<property name="someResource" value-ref="resourceRef"/>
</bean>
Now at least in a class that extends TemplateDirectiveModel's execute method you have access to that injected property.
public class MyDirective extends TemplateDirectiveModel {
private MyResource someResource;
#Override
public void execute(Environment env, Map params, TemplateModel[] loopVars,TemplateDirectiveBody body) throws TemplateException, IOException {
StringModel sharedVariable = (StringModel)env.getConfiguration().getSharedVariable("beanName");
MyClass sweetness = (MyClass)sharedVariable.getWrappedObject();
}
}
Now in your .ftl you can use:
<#macroName />
and it will have spring dependencies auto injected.

Spring #Transactional - JPA context in transaction problem

I'm using Spring + JSF + JPA configuration hosted on Glassfish v3.1.
I'm experiencing some strange (at least for me) behavior of #Transactional annotation. Here is my simplified example:
#Transactional
public void associateGroupToRole(String role, String group) throws MyServiceException {
GroupEntity groupEntity = userDao.getGroupByName(group);
RoleEntity roleEntity = userDao.getRoleByName(role);
//some stuff
if(!roleEntity.getGroups().contains(groupEntity)) {
roleEntity.getGroups().add(groupEntity);
}
}
#Transactional
public void associateGroupToRole(RoleEntity roleEntity, GroupEntity groupEntity) throws MyServiceException {
//some stuff
if(!roleEntity.getGroups().contains(groupEntity)) {
roleEntity.getGroups().add(groupEntity);
}
}
It turns out that "associateGroupToRole" with Entities as arguments works correctly and the one with String - does not. After small modification and coping code from one method to another:
#Transactional
public void associateGroupToRole(String role, String group) throws MyServiceException {
GroupEntity groupEntity = userDao.getGroupByName(group);
RoleEntity roleEntity = userDao.getRoleByName(role);
if(!roleEntity.getGroups().contains(groupEntity)) {
roleEntity.getGroups().add(groupEntity);
}
}
The code runs without any problems and everything is committed to database. My question is: What might be wrong in above example, what is happening to transaction context (when accessing from one annotated method to another), and why my entities are no longer in managed state?
Here is my Spring configuration:
<context:annotation-config />
<context:component-scan base-package="com.mypackage"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<tx:jta-transaction-manager/>
<tx:annotation-driven/>
As you can see I'm using persistence.xml file and my EntityManager uses JNDI to connect to DB.
Unfortunately there was a bug in some other piece of DAO code. Please vote for close this question.

Resources