Reputation: 15769
I am trying out the @XmlIDREF
reference approach. The annotation is:
/**
* getter for Attribute/List<Attribute> attributes
* @return attributes
*/
@XmlElementWrapper(name="attributes")
@XmlElements({
@XmlElement(name="Attribute", type=AttributeJaxbDao.class)
})
@XmlIDREF
public List<Attribute> getAttributes() {
which leads to the error message:
javax.xml.bind.JAXBException:
Exception Description: Since the property or field [attributes] is set as XmlIDREF, the target type of each XmlElement declared within the XmlElements list must have an XmlID property. Please ensure the target type of XmlElement [Attribute] contains an XmlID property.
- with linked exception:
[Exception [EclipseLink-50035] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.JAXBException
Exception Description: Since the property or field [attributes] is set as XmlIDREF, the target type of each XmlElement declared within the XmlElements list must have an XmlID property. Please ensure the target type of XmlElement [Attribute] contains an XmlID property.]
at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:832)
at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:143)
although AttributeJaxbDao
has the annotation:
/**
* getter for xsd:string/String id
* @return id
*/
@XmlAttribute(name="id")
@XmlID
public String getId() {
There are two differences to the "standard use" @XmlIDREF
/@XmlID
:
@XmlElement
annotationHow come the error shows up in this situation? Would there be a work around for this. I'd like to avoid to be forced to not use the interface and the generalization.
Upvotes: 1
Views: 367
Reputation: 148977
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
There were unfortunately 2 bugs that we preventing this use case from working correctly.
These bugs have been fixed in the EclipseLink 2.4.2 and 2.5.0 streams. These streams are currently in development, a nightly build can be downloaded from the following link (starting Feb 22, 2013):
FULL EXAMPLE
Below is a slightly more complicated model than the one given in your question that I'm going to use to demonstrate that everything now works correctly.
Foo
The Foo
class has two properties of type List<Attribute>
, Attribute
is an interface. Both are annotated with @XmlElements
which contain @XmlElement
annotations that specify the concrete types. The attributeRefs
property is also annotated with @XmlIDREF
.
import java.util.*;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class Foo {
@XmlElementWrapper(name="Attributes")
@XmlElements({
@XmlElement(name="AttributeFoo", type=AttributeJaxbDao.class),
@XmlElement(name="AttributeBar", type=AttributeJaxbDao2.class)
})
List<Attribute> attributes = new ArrayList<Attribute>();;
@XmlElementWrapper(name="AttributeRefs")
@XmlElements({
@XmlElement(name="AttributeRefFoo", type=AttributeJaxbDao.class),
@XmlElement(name="AttributeRefBar", type=AttributeJaxbDao2.class)
})
@XmlIDREF
List<Attribute> attributeRefs = new ArrayList<Attribute>();
}
Attribute
Attribute
is just a very simple interface.
public interface Attribute {
}
AttributeJaxbDao
This is an implementation of Attribute
that contains a field annotated with @XmlID
that will be leveraged by the @XmlIDREF
annotation.
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class AttributeJaxbDao implements Attribute {
@XmlAttribute(name="id")
@XmlID
String id;
String name;
}
AttributeJaxbDao2
This is also an implementation of Attribute
that has a field annotated with @XmlID
.
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class AttributeJaxbDao2 implements Attribute {
@XmlAttribute(name="id")
@XmlID
String id;
String name;
}
Demo
Below is some demo code that you can run to prove that everything works:
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14921547/input.xml");
Foo foo = (Foo) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(foo, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo>
<Attributes>
<AttributeFoo id="a">
<name>A</name>
</AttributeFoo>
<AttributeBar id="b">
<name>B</name>
</AttributeBar>
<AttributeFoo id="c">
<name>C</name>
</AttributeFoo>
</Attributes>
<AttributeRefs>
<AttributeRefFoo>a</AttributeRefFoo>
<AttributeRefBar>b</AttributeRefBar>
<AttributeRefFoo>c</AttributeRefFoo>
</AttributeRefs>
</foo>
Upvotes: 2