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
Related
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.
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).
I've got a MyAppConversionServiceFactoryBean which I'm registering like:
<bean id="conversionService" class="com.MyProject.MyAppConversionServiceFactoryBean">
<property name="messageSource" ref="messageSource"/>
<property name="converters">
<set>
<bean class="com.MyProject.XRepresentationConverter" />
<bean class="com.MyProject.YRepresentationConverter" />
<bean class="com.MyProject.ZRepresentationConverter" />
</set>
</property>
</bean>
I can continue to list every converter we write into this list, but I'd love to be able to configure it such that this isn't necessary and that converters will automatically register themselves somehow with my factory.
Sidebar 1: If that's not possible with a custom factory, is it possible with the default spring one?
Sidebar 2: If neither the first part nor Sidebar 1 is possible, is it possible to #Autowired the conversionService into the converters (so they can easily call one another)? Attempting to #Autowired ConversionService conversionService has previously given me issues due to not being able to wire the conversionService into an object while it's still busy creating the service.
Note: We're using Spring, but not Spring MVC. I have no control over that, so any solutions on that route will be unfortunately unusable. I can change pretty much anything else about the configuration and Java classes, just not the overarching tools.
#Vikdor's comment on the question pointed me in the right direction.
Spring is apparently capable (and no one I asked in person knew this) of gathering collections of beans through the scanning process with #Autowired annotations. Here's what I needed to achieve the same effect I got from the configuration in the post:
applicationContent.xml must have:
<context:component-scan base-package="com.MyProject"/>
<bean id="conversionService" class="com.MyProject.MyAppConversionServiceFactoryBean" />
MyAppConversionServiceFactoryBean.java:
public class MyAppConversionServiceFactoryBean implements
FactoryBean<ConversionService>, InitializingBean {
#Autowired
private Set<BaseConverter> converters;
}
And then all of my converters now have the #Component annotation.
Relevant Docs on #Autowired do briefly mention that it can be used to collect all beans of a type, but I wouldn't have known that it could be done into any collection type without this thread by Grzegorz Oledzki which addresses the generic form of my question, but takes it down a philosophical route.
I've followed the tutorial for spring remoting, in particular HttpInvokerServiceExporter and have no problems setting up both the client and the server (factorybean).
Question is, I've noticed using Spring MVC, each interface is mapped to a particular URL
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="hello.htm">test_service</prop>
</props>
</property>
</bean>
<!-- *********************exposed web services*************************-->
<bean name="test_service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="serviceInterface" value="foo.webservices.HelloServiceInterface" />
<property name="service">
<ref bean="helloService"></ref>
</property>
Question is, if I have more than 1 method in my service interface, is it possible to map each of these interface methods to a URL themselves?
The idea behind HTTPInvokerServiceExporter is to provide an endpoint to receive remove method invocation.
On the server side it would be easy as configure a RemoteExporter, declaring the interface you want to expose and associating it to the real bean that will handle the invocations.
On the client it would be necessary configure the RemoteAcessor that basically needs the interface that is going be access on the server side.
The implementation over HTTP can be done using HttpInvokerServiceExporter on the server side like the following example:
Service Interface:
package foo.bar.services;
public interface MyService {
public int sum(int num1, int num2);
}
For this service you would have an implementation (let's say foo.bar.services.DefaultMyService).
The exposition and configuration on spring context would look like:
<bean name="myService" class="foo.bar.DefaultMyService" />
<bean name="/myService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
With this configuration I just intended to have a instance of my implementation of MyService being exposed under foo.bar.MyService interface over the URL mapped by /myService (bean name) in the simpliest case using BeanNameUrlHandlerMapping that does nothing else than map a URL to a bean with the URL value (this case /myService).
On the client side (consumer), you will have a bean configured just declaring the interface you expect the remote side is exposing. For our service would be something like:
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://foo.bar.org/springSample/myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
At the moment spring instantiate the beans on client side, a proxy is instantiated and every method invocation would then be serialized and sent over HTTP to the endpoint (in this case http://foo.bar.org/springSample/myService. At the server side this request is deserialized and interpreted i.e. invoking the method on the real service being exposed (on our case DefaultMyService). The service will return something that will be serialized an gave as result to the HTTP request performed by the client. The client will receive it and deserialize it and return it to the original method invocator.
As you can see (and got from Spring documentation):
The server side will
Deserializes remote invocation objects and serializes remote
invocation result objects. Uses Java serialization just like RMI, but
provides the same ease of setup as Caucho's HTTP-based Hessian and
Burlap protocols.
The client side will
Serializes remote invocation objects and deserializes remote
invocation result objects. Uses Java serialization just like RMI, but
provides the same ease of setup as Caucho's HTTP-based Hessian and
Burlap protocols.
The serialization used with Spring Remoting on this case is Java serialization, meaning the HTTP request holds an entity body containing the serialized object (is good to keep in mind that in this case JVM version and class versions needs to be compatible).
The exposition is done as a whole, you could not separate it having one URL for each method of that interface. Therefore would be easier the use of Spring MVC and create a controller (#Controller) implement a method for each method you have on your interface annotating it as #RequestMapping (with the desired URL) and invoke the method on the service as follows the example:
Controller Sample
package foo.bar;
import foo.bar.service.MyService;
#Controller
public class MyService {
#Autowired
private MyService myService;
#RequestMapping("/sum/{num1}/{num2}")
public int sum(#PathVariable("num1") int num1, #PathVariable("num2") int num2) {
return myService.sum(num1, num2);
}
}
Using the context configuration
<context:component-scan base-package="foo.bar"/>
it would map the classes found on foo.bar and under packages automatically, meaning the Service implementation (DefaultMyService) could be mapped with #Service and #Autowired to the controller as done in the sample, without any bean configuration on the context xml.
But this will expose your service over REST interface, meaning it will handle HTTP plain requests that could be done by other consumers like a PHP consumer (this couldn't be done with Spring Remoting because it uses pure Java serialization).
If your client is Java you could definitively use Remoting and expose your service as a whole, if not the REST implementation using Spring MVC is a good solution.
Spring Documentation can be found here
I really recommend defining your controllers with the #Controller annotation. From the Spring documentation, start with adding a component scan to your Spring config.
<context:component-scan base-package="your.package.path"/>
Then, in a class, say, your.package.path.WhateverController, annotate the class:
#Controller
WhateverController
And annotate your methods with #RequestMapping:
#RequestMapping(value = "/helloWorld")
public ModelAndView helloWorld() {
...
}
#RequestMapping(value = "/project/{projectId}")
public ModelAndView helloWorld(#PathVariable String projectId) {
...
}
That's about it, multiple mappings per controller.
I think you need to tell us what you are trying to do first. If you are exposing your services to a universal web client, REST or SOAP would be a better option; if you are exposing your services to another Spring bean in another application, then Spring Remoting might suffice.
The comment "exposed web services" in your spring configuration file seems unclear of your purpose.
When you expose a service to remote clients, you always need to provide a contract to let the remote clients know what's possible. REST exposes that contract using URL's; SOAP exposes that contract using WSDL's; and Spring Remoting just directly gives the client that contract in a java interface, so the client can inject that interface into its own beans and use it like a locally defined bean.
In your question you mentioned mapping a method to an URL, Spring Remoting can't do that because it exposes intefaces; what you want to do sound very REST to me. And I agree with #stevebrown, exposing your services using a mapped controller is a good approach.
I have a static method I have no control over: MyUtils.getServiceURL() which returns a URL. I need to extract just the port from this URL to set a property on a bean:
<bean id="myBean>
<property name="defaultPort" value="?????"/>
</bean>
I can get the string value of the URL as a bean like this:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
I'm probably just going to write a method to parse the URL in myBean and extract the port. I was wondering if there was a way to avoid having to do this, and configure this directly in the spring context?
No need for custom classes, or parsers. Remember, a bean is just a class with get/is/set methods. A java.net.URL class qualifies as such.
Solution: Use a java.net.URL as a Spring-configurable bean and call it's getPort method.
Remember, in Spring, you can wire anything as a bean very easily so long as it sports methods using the get/is/set Bean convention. The java.net.URL class does such a thing.
** warning ** I'm just typing this out of my a$$, you'll have to check for any syntax shenanigans that I might be introducing in this Spring-config pseudo-code. One thing that is certain is that the concept will work with Spring 2.5 and that it relies on the util schema.
If you are using an older version of Spring, you'll have to use a PropertyPathFactoryBean. If you are using Spring 3.0, you'll want to use Spring expression language (EL), but I can't comment on the later since I'm not familiar with Spring 3.0.
In java:
int port = (new URL(MyUtils.getServiceURL()).getPort()
In Spring:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
<bean id="myURL" class="java.net.URL">
<constructor-arg>
<ref-bean="serviceURL"/>
</constructor-arg>
</bean>
<util:property-path id="defaultPort" path="myURL.port"/>
<bean id="myBean>
<property name="defaultPort" ref="defaultPort"/>
</bean>
There might be a way to consolidate all these four expressions into three or less, don't know if that will improve readability, though. The concept remains the same, though. Treat a java.net.URL instance as a bean, set its URL via its constructor, and get a hold (via Spring) of its getPort() method.
** edit **:
If you are using Spring 2.5 you can create an inline groovy bean that does all that for you. I've seen people doing that as integration glue to get rid of multitude of temp Spring bean place holders. That's the best choice IMO when you need to define a class (when it's simpler than just using Spring tags) and when you know such a class won't be used outside of Spring wiring of things.
Not I can think of. Either way, you probably have to write something to parse the port out. Since you have no control of that static method, perhaps you may want to utilize the adapter pattern to hide that static method. Doing so also makes your code easier to test because you can easily mock that external API out. For example:-
public interface URLServiceAdapter {
int getServiceURLPort();
}
public class URLServiceAdapterImpl implements URLServiceAdapter {
public int getServiceURLPort() {
return MyUtils.getServiceURL().getPort();
}
}
Your beans will then rely on your adapter class instead of MyUtils.getServiceURL() directly:-
<bean id="urlServiceAdapter" class="project.URLServiceAdapterImpl" />
That way, you can do something like this:-
#Autowired
private UrlServiceAdapter urlServiceAdapter;
...
bean.setDefaultPort(urlServiceAdapter.getServiceURLPort());
SpEL is your friend.
<bean id="myBean>
<property name="defaultPort"
value='#{ T(com.foo.MyUtils).getServiceURL().split(":")[2].split("/")[0] }'/>
</bean>
Enjoy,