Yang opened SPR-10262 and commented
I have a Controller class returns a list wrapper because Jaxb won't work if just returning a List. So I built a wrapper class to use for the case where a list is returned.
@RequestMapping(produces= { "application/xml"} )
@ResponseBody
public JaxbListWrapper<Contact> listXML() {
List<Contact> result = subnetService.findAllSubnets();
return new JaxbListWrapper<>( result );
}
Here is the JaxbListWrapper:
@XmlRootElement(name="list")
public class JaxbListWrapper<T> {
private List<T> items;
public JaxbListWrapper() {
items = new ArrayList<T>();
}
public JaxbListWrapper(List<T> items) {
this.items = items;
}
@XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
}
(the above wrapper idea is from http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html)
But it wouldn't work in Spring MVC. And I will get this error of 'JAXBException: Contact nor any of its super class is known to this context'.
I looked into the code of Jaxb2RootElementHttpMessageConverter and realized that it is only creating a JaxbContext based on one class each. The JaxbContext doesn't contains Contact.class and thus the error.
One work around is to add @XmlSeeAlso
({Contact.class}) in the JaxbListWrapper(). But that kind of defeated the purpose of a generic list wrapper.
I wonder:
Option 1: if the Jaxb2RootElementHttpMessageConverter can be customized in a way so that
This issue is similar to: http://forum.springsource.org/showthread.php?129342-Spring-Roo-and-JAXBException-X-nor-any-of-its-super-class-is-known-to-this-context
Affects: 3.2 GA, 3.2.1
Reference URL: http://forum.springsource.org/showthread.php?129342-Spring-Roo-and-JAXBException-X-nor-any-of-its-super-class-is-known-to-this-context
3 votes, 8 watchers
Comment From: spring-projects-issues
Rossen Stoyanchev commented
Have you considered using MarshallingHttpMessageConverter? It seems to match the behavior you want.
Comment From: spring-projects-issues
Yang commented
Thanks. Rossen. MarshallingHttpMessageConverter does work in this case. I tried the following and it solved the problem. I guess Jaxb2RootElementHttpMessageConverter is not designed for my use case. I wonder if Jaxb2RootElementHttpMessageConverter can be extended to cover more cases like mine. After all, it is the default converter and when it is not working, people spend a lot of time trying to figure it out.
<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound
name="xxxxx.JaxbListWrapper" />
<oxm:class-to-be-bound
name="xxxxx.Contact" />
</oxm:jaxb2-marshaller>
<mvc:annotation-driven conversion-service="applicationConversionService">
<mvc:message-converters>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Comment From: spring-projects-issues
Rossen Stoyanchev commented
Okay, good point. I'll take a look at making AbstractJaxb2HttpMessageConverter configurable with a Marshaller/Unmarshaller. In the very least the Javadoc for Jaxb2RootElementHttpMessageConverter can be updated to point to MarshallingHttpMessageConverter.
Comment From: spring-projects-issues
Dmitry Katsubo commented
I have hit similar problem when trying to customize JAXB marshaller. I my case I would like to tune marshaller before using it:
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
However AbstractJaxb2HttpMessageConverter
has protected *final* Marshaller createMarshaller(...)
which makes it impossible to extend this class and add this behaviour.
So the only way out is MarshallingHttpMessageConverter
+ spring-oxm module.
P.S. There is also inconsistency between Jaxb2RootElementHttpMessageConverter.canRead()
that supports reading classes annotated with @XmlType
and Jaxb2Marshaller.supportsInternal()
that checks only for @XmlRootElement
.
Comment From: spring-projects-issues
Eric Bottard commented
+1 for adding a hook to customize the JaxbContext (if not removing the final modifier entirely).
This issue also pops up for example with Spring HATEOAS' PagedResources that end-user can't modify to add @XmlSeeAlso
to her element class.
Comment From: spring-projects-issues
Dmitry Katsubo commented
Eric, if you like the approach I have suggested in #15096, vote for that issue. However it targets the MarshallingHttpMessageConverter
+Jaxb2Marshaller
couple rather than Jaxb2RootElementHttpMessageConverter
. <oxm:jaxb2-marshaller>
is alright for majority of use cases, but I personally miss JAXB property support via it.