How do I reuse annotations across complexTypes?
I'm trying to write my first xsd which will have JAXB mapped POJOs generated from it, to be used in a webservice. There will be three related classes which I would like to see expressed in xml as...
<stringKey systemName="string key 1" businessName="Customer">Glorious strings</stringKey>
<numberKey systemName="number key 1" businessName="Invoice number">1025.52</numberKey>
<dateKey systemName="date key 1" businessName="Invoice date">1970-01-01</dateKey>
I'm trying to reuse the declaration of th开发者_Go百科e annotations so the JAXB generated POJOs can belong to the same interface. So far I have the following xsd...
<xs:complexType name="dateKey">
<xs:simpleContent>
<xs:extension base="namedElement">
<xs:attribute type="xs:dateTime" name="keyValue" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="namedElement" abstract="true">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="businessName" />
<xs:attribute type="xs:string" name="systemName" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
This gets me part way there, it gives me xml like...
<dateKey systemName="date key 1" businessName="Invoice date"><keyValue>1970-01-01</keyValue></dateKey>
I am having difficulty reusing a type which declares the annotations, while overriding the base of that type. (Note I am trying to get rid of the 'keyValue' element in the above example). Any ideas?
EDIT: I've noticed the xsd snippet does not validate the following xml snippet - that seems to have been lost in the refactoring, but I hope you get the point...
I have found you can use 'attributeGroup' to extract common attributes to create a xsd like...
<xs:complexType name="dateKey">
<xs:simpleContent>
<xs:extension base="xs:dateTime">
<xs:attributeGroup ref="namedElement" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:attributeGroup name="namedElement">
<xs:attribute type="xs:string" name="businessName" />
<xs:attribute type="xs:string" name="systemName" />
</xs:attributeGroup>
This allows me to reuse the attributes across similar elements, but the generated POJOs do not share a common abstract superclass. I think I'm going to stop auto-generating the POJOs and go with hand built XSD and POJOs, although I'm a little worried that discrepancies between the two.
Why not start from Java classes and do the following. You will need to mark the parent class @XmlTransient to have things work correctly:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
@XmlTransient
public class NamedElement {
private String businessName;
private String systemName;
@XmlAttribute
public String getBusinessName() {
return businessName;
}
public void setBusinessName(String businessName) {
this.businessName = businessName;
}
@XmlAttribute
public String getSystemName() {
return systemName;
}
public void setSystemName(String systemName) {
this.systemName = systemName;
}
}
And the subclasses would look like the following:
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlValue;
@XmlRootElement
public class DateKey extends NamedElement {
private Date value;
@XmlValue
@XmlSchemaType(name="date")
public Date getValue() {
return value;
}
public void setValue(Date value) {
this.value = value;
}
}
Then the following code:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(DateKey.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
DateKey dateKey = (DateKey) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(dateKey, System.out);
}
}
Will handle your document:
<dateKey systemName="date key 1" businessName="Invoice date">1970-01-01</dateKey>
精彩评论