how to marshal object and return as a view (and not as JSP page) in spring + xstream
I'm trying to follow this tutorial and build a RESTful service that can un/marshal an object to/from XML. http://www.stupidjavatricks.com/?p=54
The marshaller of choice in the article is xStream (I found it to be very easy to use and configure).
The point is, using STS -- Spring's own flavor of Eclipse bundled with tcServer -- I built a project based on the STS template of MVC. This is a legacy project started from Spring version 2.4, and I migrated it to version 3.0. So, the template created all the necessary XML markup, and I added my configuration to point the view to the correct object conversion (to the xstream marshaler).
Here is part of my bean that sends the object to a new view (copied out from the link):
<bean id="bookXmlView" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
</bean>
</constructor-arg>
</bean>
It all worked nicely until I installed the latest STS version 2.5.2.RELEASE and created a new MVC project from a template. (The new template does not use urlrewrite.xml anymore, among some other changes).
I set the correct configuration 1 by 1 as the tutorial suggests, but now no matter what, the view is always directed to a JSP, so if my controller looks like this:
@RequestMapping(value = "/authors/{authorId}")
public ModelAndView getAuthorById(@PathVariable String authorId) {
Author author = bookService.getAuthorById(authorId);
ModelAndView mav =new ModelAndView("bookXmlView", BindingResult.MODEL_KEY_PREFIX+"author", author);
return mav;
}
It would always try to return to a author.jsp view and not the object as XML. I tried many things with no 开发者_如何学JAVAsuccess. Any ideas why this happens and how to fix it?
UPDATE ------------------- As noted I added logs:
I set it as DEBUG level and discovered something:
DEBUG: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Rejected bean name 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor': no URL paths identified
DEBUG: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Rejected bean name 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor': no URL paths identified DEBUG: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Rejected bean name 'org.springframework.context.annotation.internalRequiredAnnotationProcessor': no URL paths identified DEBUG: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Rejected bean name 'org.springframework.context.annotation.internalCommonAnnotationProcessor': no URL paths identified DEBUG: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Rejected bean name 'bookXmlView': no URL paths identified
Notice this line: Rejected bean name 'bookXmlView': no URL paths identified.
Searching this indicated maybe a clash between <mvc:annotation-driven />
and my autodetectAnnotations in the xstream settings?
Any case, after invoking the link, I got the following log entry. Notice it forwards the view to /WEB-INF/views/bookXmlView.jsp:
DEBUG: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/test/page_init]
DEBUG: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapping [/page_init] to HandlerExecutionChain with handler [test.test.test.HomeController@a087de] and 2 interceptors DEBUG: org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/test/page_init] is: -1 DEBUG: org.springframework.web.bind.annotation.support.HandlerMethodInvoker - Invoking request handler method: public org.springframework.web.servlet.ModelAndView test.test.test.HomeController.getObject() DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'bookXmlView' DEBUG: org.springframework.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'bookXmlView'; URL [/WEB-INF/views/xmlView.jsp]] in DispatcherServlet with name 'appServlet' DEBUG: org.springframework.web.servlet.view.JstlView - Added model object 'org.springframework.validation.BindingResult.books' of type [test.test.test.ObjectTest] to request in view with name 'bookXmlView' DEBUG: org.springframework.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/views/xmlView.jsp] in InternalResourceView 'bookXmlView' DEBUG: org.springframework.web.servlet.DispatcherServlet - Successfully completed request
Got it at last! First I tried a different marshaller - JAXB2 but xstream should work as well.
Next thing is the definition - turns out for some reason the configuration uses this (wrong):
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
using only InternalResourceViewResolver
while definition for org.springframework.web.servlet.view.BeanNameViewResolver is ignored. The solution for that is to define them both in one bean called ContentNegotiatingViewResolver as follows:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
</bean>
<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="com.mycompany.dashboard.Person" />
</oxm:jaxb2-marshaller>
<bean name="person" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="marshaller" />
</bean>
That configuration solved my problems and person object I played with was not directed to a JSP view but marshaller turn is to an XML:
@RequestMapping(value = "/person", method = RequestMethod.GET)
public ModelAndView addPerson() {
Person person = new Person();
person.setAddress("address 123");
person.setAge(50);
person.setName("Andrew");
System.out.println("new person: " + person);
ModelAndView mav = new ModelAndView("person",BindingResult.MODEL_KEY_PREFIX + "person",person);
return mav;
Hope it would help others in the future too.
精彩评论