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

JAXB marshalling with 'any' elements [SWS-751] #839

Closed
gregturn opened this issue Jan 23, 2012 · 5 comments
Closed

JAXB marshalling with 'any' elements [SWS-751] #839

gregturn opened this issue Jan 23, 2012 · 5 comments
Assignees

Comments

@gregturn
Copy link
Member

@gregturn gregturn commented Jan 23, 2012

Dan Luputan opened SWS-751 and commented

This can also be an improvement, but different from what the user expects as Jaxb2Marshaller is correctly configured.
class A {
@XmlAnyElement(lax = true)
protected Object any;
}

// B is any
@XmlRootElement
class B {
}
Jaxb2Marshaller.classesToBeBound = {A, B}

If I create an object A with A.any=B, AbstractJaxb2PayloadMethodProcessor.getJaxbContext creates a JAXBContext which only sees A, and not B, so marshalling fails.

The solution
@XmlSeeAlso(B.class)
class A {
}
is not elegant. Is there a better way to set the local context to work with any elements?


Affects: 2.0.3

@gregturn
Copy link
Member Author

@gregturn gregturn commented Jan 24, 2012

Arjen Poutsma commented

I am not sure if there are better ways to configure the Jaxb2Marshaller for this scenario.

At any rate, I can't reproduce this issue with the following code:


@XmlRootElement
public class A {

    @XmlAnyElement(lax = true)
    public Object any;

}

@XmlRootElement
public class B {

}
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>jaxb.schema.A</value>
            <value>jaxb.schema.B</value>
        </list>
    </property>
</bean>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("jaxb.xml", Driver.class);
Jaxb2Marshaller marshaller = applicationContext.getBean("marshaller", Jaxb2Marshaller.class);

A a = new A();
a.any = new B();

marshaller.marshal(a, new StreamResult(System.out));

the above prints out:

<a><b/></a>

which I think is correct.

@gregturn
Copy link
Member Author

@gregturn gregturn commented Jan 25, 2012

Dan Luputan commented

As I said (maybe not that clear), the issue is with AbstractJaxb2PayloadMethodProcessor.getJaxbContext, not using Jaxb2Marshaller directly which obviously works.

The issue here is how to populate the JAXBContext. With 'any' elements, the possible candidates are lost since this is how JAXB works. But Jaxb2Marshaller already has all the candidates configured. getJaxbContext does JAXBContext.newInstance(clazz), where I would need the 'any' candidates included. So I asked for a solution to that.

@gregturn
Copy link
Member Author

@gregturn gregturn commented Jan 25, 2012

Dan Luputan commented

One more comment, it is not clear to me why jaxbContexts Map is needed in AbstractJaxb2PayloadMethodProcessor when the JAXBContext from the marshaller could be used.

@gregturn
Copy link
Member Author

@gregturn gregturn commented Jan 26, 2012

Arjen Poutsma commented

I see now; sorry for the misunderstanding earlier.

I don't think there is a better way of using the AbstractJaxb2PayloadMethodProcessor in this particular scenario. The underlying reason is that this processor detects the JAXBContext for a given class automatically, and since A does not have a reference to B (except with the @XmlSeeAlso annotation), it will not work.

You can, however, use the MarshallingPayloadMethodProcessor instead of the JAXB2 one. The way to make this work is to configure a Jaxb2Marshaller from the Spring OXM module with the classesToBeBound property (as shown in the snippet above), and plug that into the MarshallingPayloadMethodProcessor. This way, JAXB2 is explicitly configured for a particular set of classes (A & B) and will only work for those classes.

To answer your final question: we cache the JAXB2Contexts in a map because they are quite expensive to create. Check the getJaxbContext() method to see more.

Hope this helps.

@gregturn
Copy link
Member Author

@gregturn gregturn commented May 4, 2012

Arjen Poutsma commented

Closing old issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.