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

Checking for @XmlRootElement annotation should be made optional in Jaxb2Marshaller [SPR-7931] #12586

Closed
spring-projects-issues opened this issue Feb 2, 2011 · 5 comments
Assignees
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Feb 2, 2011

Oliver Drotbohm opened SPR-7931 and commented

The Jaxb2Marshaller is only supporting classes annotated with @XmlRootElement currently and there's no way to override that behaviour as supportsInternal(Class, boolean) is private. There are cases when you want to (un)marshal classes that are @XmlType annotated only. Especially when working with XJC, you get the @XmlRootElement annotation only for classes that have their xsd:simpleType or xsd:complexType nested inside the xsd:element declaration (see this blog entry for why that's the case). However, if you have a type that can be reused and used as a root element's type, XJC will not create the @XmlRootElement annotation but rather a factory method inside the ObjectFactory class. To get those classes (un)marshalled, you currently have to copy large parts of Jaxb2Marshaller as there's no way to disable the check for the annotation. So it would be cool if this was configurable through a bean property or at least changeable so that a subclass could potentially call supportsInternal(clazz, false).


Issue Links:

Referenced from: commits 01d2082

@spring-projects-issues
Copy link
Collaborator Author

Arjen Poutsma commented

The reason the Jaxb2Marshaller does not support classes that are annotated with @XmlType is quite simple: JAXB2 does not support them. Try running the following piece of code:

public static void main(String[] args) throws JAXBException {
	DummyType t = new DummyType();
	JAXBContext context = JAXBContext.newInstance(DummyType.class);
	javax.xml.bind.Marshaller m = context.createMarshaller();
	m.marshal(t, System.out);
}

@XmlType
public static class DummyType {

	private String s = "Hello";
}

This results in the following exception:

[com.sun.istack.internal.SAXException2: unable to marshal type "org.springframework.oxm.jaxb.Jaxb2MarshallerTests$DummyType" as an element because it is missing an @XmlRootElement annotation]

You can, however, marshal classes annotated with @XmlType if you put them in a JAXBElement, and this is also support in the Jaxb2Marshaller. See:

public static void main(String[] args) throws JAXBException {
	DummyType t = new DummyType();
	JAXBElement<DummyType> e = new JAXBElement<DummyType>(new QName("http://example.com", "dummyType"), DummyType.class, t);
	JAXBContext context = JAXBContext.newInstance(DummyType.class);
	javax.xml.bind.Marshaller m = context.createMarshaller();
	m.marshal(e, System.out);
	System.out.println();

This results in:

<dummyType xmlns="http://example.com"/>

@spring-projects-issues
Copy link
Collaborator Author

Arjen Poutsma commented

Resolving as invalid.

@spring-projects-issues
Copy link
Collaborator Author

Ignacio Cavero commented

As it is Jaxb2Marshaller is incompatible with spring MVC MarshallingView because it calls 'mashaller.supports(o.getClass)' and that will always return false, even if 'o' is of type 'JAXBElement<SomeSupportedTypeWithoutXMLRootElement>'. You can say that they should call 'supports(myJAXBElement.getDeclaredType())' instead but that class has no knowledge of JAXB. So basically the supports(Class) method as it is now is broken because marshaller.marshall(o, result) works but marshaller.supports(o.getClass()) fails. Why not add a check for 'JAXBElement.class.isAssignableFrom(clazz)', that has to be better than a broken method even if not all JAXBElement objects are supported.

@spring-projects-issues
Copy link
Collaborator Author

Arjen Poutsma commented

Resolved by introducing a 'supportJaxbElementClass' property, which defaults to false, but can be set to true to let supports(Class) return true for JAXBElement.class.

I did it this way because I didn't want this new functionality to interfere with support(Type), which is actually a better version than supports(Class). Problem is that it requires information that isn't available in MarshallingView, because of runtime type erasure.

Also, I think this new functionality shouldn't enabled by default, because a given Jaxb2Marshaller does not support all JAXBElements, only those who wrap a XmlType that is supported (which is in fact what supports(Type) does). But once again, we don't have access to that information because of type erasure.

@spring-projects-issues
Copy link
Collaborator Author

Ben Grommes commented

I have another scenario not covered by this fix. I'm using EclipseLink MOXy which allows one to specify the XmlRootElement information not with an annotation on the class but in an xml mapping file. I want to be able to use the Jaxb2Marshaller without putting an @XmlRootElement annotation on my class since I can put it in the MOXy mapping file (this would make my POJOs JAXB annotation free). In this case I'm not using JAXBElements. Would it be possible to enable supportsInternal to skip the XmlRootElement annotation check?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants