Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jaxb2RootElementHttpMessageConverter doesn't work well with class with @XmlAnyElement [SPR-10262] #14895

Closed
spring-projects-issues opened this issue Feb 5, 2013 · 6 comments
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

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 oxm:jaxb2-marshaller can be passed in as the marshaller and unmarshaller. JaxbMarshaller is already thread safe.
Option 2: Or better, looking for oxm:jaxb2-marshaller in the application context, if it is configured, just use that jaxbMarshaller as the default. It seems many people already assumed that if they config 'oxm:jaxb2-marshaller, that would be what used by Jaxb2RootElementHttpMessageConverter .

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

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Have you considered using MarshallingHttpMessageConverter? It seems to match the behavior you want.

@spring-projects-issues
Copy link
Collaborator Author

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>

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

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.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 12, 2013

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.

@spring-projects-issues spring-projects-issues added type: enhancement A general enhancement in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jan 11, 2019
@jhoeller jhoeller removed this from the General Backlog milestone Dec 23, 2023
@jhoeller jhoeller closed this as not planned Won't fix, can't repro, duplicate, stale Dec 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants