Spring MVC combined XML and annotation Controller configuration - java

I'm porting a large Spring 3.0 application to Spring 3.2 (yes, I know). The application combines XML and annotation configuration to define routes, for example:
servlet.xml:
<context:annotation-config/>
<context:component-scan base-package="foo.bar" />
...
<mvc:annotation-driven />
...
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
...
<property name="mappings">
<props>
<prop key="/booking/default.htm">booking.default</prop>
...
</props>
</property>
...
</bean>
<bean id="booking.default" class="foo.bar.BookingController">
...
</bean>
BookingController.java
#Controller
public class BookingController {
...
#RequestMapping(method = RequestMethod.GET)
public String handleRequest(...)
...
}
In Spring 3.0, the effect is to map GET /booking/default.htm to the handleRequest method of BookingController, however I have been unable to recreate this behaviour in Spring 3.2.
Spring 3.2, it seems, ignores the XML and views every method annotated with #RequestMapping(method = RequestMethod.GET) as the same, aborting on startup with java.lang.IllegalStateException: Ambiguous mapping found.
There are a large number of methods configured this way. Some of them have the #RequestMapping in a base library class that I can't change.
I can work around it by moving the url path from the XML configuration to the annotation, but I'd like to avoid that (for various reasons) and replicate the Spring 3.0 behaviour.
Is that possible? Searching for an answer has not been successful.

UPDATE:
TL;DR: This is not possible from Spring 3.1 onwards
Reading a SO "related questions" link:
SpringMVC 3.0 to 3.1 migration of ControllerClassNameHandlerMapping
Led me to:
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html
Which contains the excerpt:
New Support Classes for #RequestMapping methods in Spring MVC 3.1
...
There are also several things no longer possible:
Select a controller first with a SimpleUrlHandlerMapping or
BeanNameUrlHandlerMapping and then narrow the method based on
#RequestMapping annotations.
Which explains my problem.

Related

How to map URL to specific controller's method in Spring MVC using XML?

I know it's possible to do it with #RequestMapping annotation but is there way to do it in my XML dispatcher servlet settings file? I tried using SimpleUrlHandlerMapping:
mvc-dispathcer-servlet.xml
...
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/users">userController</prop>
</props>
</property>
</bean>
...
But as far as I understand there is no way to map URL to certain controller's method with SimpleUrlHandlerMapping. Is there way to do it in XML settings file at all?
As far as I know, this is not possible.
Using SimpleUrlHandlerMapping, you can only map URLs to a single controller. This makes sense: before Java-5 and annotations, the only way to make a URL mapping was to use HandlerMapping, and the only way to make a controller was to create a class that extented AbstractController. Such controllers could only handle the URL they were configured with. At the time, URL mapping was class oriented and not method oriented.
Since Java 5, Spring MVC added a lot of annotations like #RequestMapping allowing for method-oriented URL mapping but they didn't backport this to the XML configuration.
There is actually a JIRA ticket for exactly this feature, that remains unresolved at time of this writing (with a fix version of 4.3 Backlog).

Set attributes of ServletContext in Spring 3.2 MVC configuration

I'm stuck on a pretty simple task: how to set ServletContext attributes in Spring MVC 3.2 configuration?
I found that something similar can be done with ServletContextPropertyPlaceholderConfigurer, but from Spring 3.1 this is considered as deprecated:
"Deprecated. in Spring 3.1 in favor of PropertySourcesPlaceholderConfigurer in conjunction with StandardServletEnvironment."
This doesn't tell me much, since I don't know how to do it with StandardServletEnvironment.
Any suggestion?
You can use ServletContextAttributeExporter for this. Define a ServletContextAttributeExporter bean as below in your configuration file and set its attributes property to a map of key and value pairs that you want to put into ServletContext:
<bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="myKey" value="1" />
</map>
</property>
</bean>
Create a *.properties file somewhere in your class path, e.g. /myprops.properties.
Add a property-placeholder to your context-config:
<context:property-placeholder location="myprops.properties"/>
or, if you are using java config:
#Configuration
#PropertySource("classpath:myprops.properties")
public class ApplicationConfiguration {
...
}

Spring mvc with hibernate, how can I add a restful service endpoint?

So I have spring mvc up and running with hibernate.
I'm reading how I can add Restful endpoints using the #ResponseBody: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
So if I have an endpoint like:
http://localhost:8080/services/user/get/1
I will fetch a user with userId=1, how will I return and how will it convert my user object to an XML representation?
Do I have to do something special in my User.java class for this to work?
The way I've done this in the past is as follows:
Annotate your User class with JAXB annotations (for example #XmlRootElement)
Hook up a suitable Spring HttpMessageConverter as in this documentation
When sending a request, make sure to include an Accept header: Accept: application/xml
By doing this, you'll have total control of how your User gets "flattened" to XML, but you're leaving all the hard work (determining the correct endpoint, data conversion) to Spring.
The conversion of method return types annotated with #ResponseBody into actual HTTP Responses is accomplished by implementations of the HttpMessageConverter interface. Spring comes with an implementation for JAXB. So if you can annotate your User class with JAXB annotations, that may work for you. If User is a Hibernate annotated Entity, adding JAXB to it also can get hairy. You may want to create an intermediate object for the JAXB.
Alternately you can use any arbitrary Marshaller by using the Marshalling Message Converter. There are quite a few implementations of Marshaller built in to choose from, or you can always write your own.
You turn on converters by registering them on the AnnotationMethodHandlerAdapter (in the dispatcher servlet xml:
<bean id="xmlMessageConverter" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
<property name="supportedMediaTypes" value="text/xml" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="xmlMessageConverter"/>
</list>
</property>
</bean>
Spring MVC have integration with XStream (convert objects to XML)
This is an interesting approach: http://www.stupidjavatricks.com/?p=54
You have to set the XStreamAlias annotation in your class and configure Spring to use XStream.
I also indicate Spring that the output is xml. In your url example that should be:
http://localhost:8080/services/user/get/1.xml

Spring 3 MVC #Controller with AOP interceptors?

Anyone knows why apparently it is not possible to use AOP with annotated MVC Controllers? (see Post).
I have a #Controller that stops working as soon as I add a pointcut to it.
The problem is not that the interceptor is not being called, but rather the #Controller simply stops working (in the log you can see that instead of "Mapped URL path [/xx] onto handler 'Yyy'" you get a "no URL paths identified").
I know there is a mechanism for adding interceptors to controllers via the handlerMapping but my question is specific to AOP interceptors. Aren't annotated controllers just pojos in the Spring container as any other pojo? What is the difference? Why?
#Controller
#RequestMapping("/user")
public class RestTestImpl implements RestTest {
#RequestMapping(value="/", method={RequestMethod.GET})
public #ResponseBody String deleteUsers(String arg) {
return "Xxxxx";
}
}
In my servlet-Context I have:
<context:component-scan base-package="org.xxx.yyy"></context:component-scan>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
. . .
</bean>
And everything works just great.
But when I add:
<aop:config>
<aop:pointcut expression="execution(* org.xxx.*(..))" id="pc1"/>
<aop:advisor advice-ref="hibernateInterceptor" pointcut-ref="pc1" order="2" />
</aop:config>
The controller stops being a controller (no errors, simply it stops binding to the specified URL)!
From the Spring MVC Reference:
Note
When using controller interfaces (e.g. for AOP proxying),
make sure to consistently put all your
mapping annotations - such as
#RequestMapping and #SessionAttributes
- on the controller interface rather than on the implementation class.
Granted, this note is well hidden :-)
I ran into the same issue and found out the solution.
Indeed your controller (annotated by #Controller) and your aspects (annotated by #Aspect) should be in the same Spring context.
Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.
When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.
The above ssertion does not depend
on the way your declare your controllers/aspects (by manual XML declaration or annotation style)
on the proxying style you choose (JDK proxy or CGLIB)
I've tested all the combinations and they all work as long as the controller & aspects are in the same Spring context
My best guess without doing some serious digging is because Spring's AOP mechanism that you are using is wrapping the target classes in proxy classes which end up loosing their annotation or the original annotation gets dropped after weaving.
I am sure there is a better answer and I'll expand on mine as I think of a better more clear way to present it.

How do I inject a single property value into a string using spring 2.5.x?

I would really like to annotate a method with a reference to a single property in a property file for injection.
#Resource("${my.service.url}")
private String myServiceUrl;
Of course, this syntax does not work ;) Thats why I'm asking here.
I am aware that I can inject the full properties file, but that just seems excessive, I dont want the property file - I want the configured value.
Edit: I can only see PropertyPlaceholderConfigurer examples where XML is used to wire the property to the given field. I still cannot figure out how this can be achieved with an annotation ?
I know it has been a while since the original post but I have managed to stumble across a solution to this for spring 2.5.x
You can create instances of "String" beans in the spring xml configuration which can then be injected into the Annotated components
#Component
public class SomeCompent{
#Autowired(required=true
#Resource("someStringBeanId")
private String aProperty;
...
}
<beans ....>
<context:component-scan base-package="..."/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
...
</bean>
<bean id="someStringId" class="java.lang.String" factory-method="valueOf">
<constructor-arg value="${place-holder}"/>
</bean>
</beans>
I've created a project which addresses this problem for Spring 2.5.*:
http://code.google.com/p/spring-property-annotations/
For Spring 3 you can use the #Value("${propery.key}") annotation.
There's a thread about this on the Spring forum. The short answer is that there's really no way to inject a single property using annotations.
I've heard that the support for using annotations will be improved in Spring 3.0, so it's likely this will be addressed soon.
you can do this if you use XML configuration. Just configure PropertyPlaceholderConfigurer and specify property value in configuration
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:com/foo/jdbc.properties</value>
</property>
</bean>
<bean ...>
<property name="myServiceUrl" value="${my.service.url}"/>
</bean>
You could try injecting value of property "my.service.url" to a filed in your bean.
Take a look at: http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-factory-placeholderconfigurer
HTH.

Categories

Resources