I've implemented a REST API based on JPA and JAXB.
I have a classes roughly like this (very simplified):
@Entity
@XmlRootElement
...
public class Thing {
@Id
@GeneratedValue
...
@XmlAttribute
@XmlID
@XmlJavaTypeAdapter(JAXBLongAdapter.class)
private Long id;
...
}
Hibernate (my current JPA provider) generates numbers as the id value, but they are naturally unique only for one one type, Thing in this example.
Now XSD says that xsd:id (@XmlID) is a NCString which cannot be a plain number so i prepended a '_' to numbers in the JAXBLongAdapter. - like '_1'
Now the schema validator complains:
[org.xml.sax.SAXParseException: cvc-id.2: There are multiple occurrences of ID value '_1'.]
If I understand this correctly a xsd:ID element must have a (string) value that is globally unique in the xml document. But this is very opposite of the common way of using IDs in databases.
What do I do now? I thought of three things:
It seems that I now have to change the Database schema to use different IDs. - But it would be nice if the IDs stayed short, because they appear in URLs.
My question: Is there a ID generator that is comparably fast and is globally unique? Or is there another way of tackling this?
EDIT:
This hack kinda works, leaving the JPA IDs intact.
@XmlID
@XmlAttribute(name="id")
private String getXmlID(){
return String.format("%s-%s", this.getClass().getSimpleName(), this.getId().toString());
}
private void setXmlID(String xmlid){
String prefix = String.format("%s-", this.getClass().getSimpleName());
if(xmlid.startsWith(prefix)){
this.id = Long.parseLong(xmlid.substring(prefix.length()));
}else{
throw new IllegalArgumentException(xmlid+" does not look like "+prefix+"###");
}
}
By moving the JAXB Annotation from the field to dedicated private getters/setters for the XmlID.
That's exactly what I had done with for some time.
You can ask yourself what is actually @XmlID
for this domain object when marshalled?
I once thought @XmlID
and @XmlIDREF
can solve the circular problem in JAXB.
Here comes what I'm doing with my JPA entities along with JAXB annotations.
Do not give the simple JPA @Id
up. That's the heart of JPA.
@XmlRootElement
public class Parent {
@Id
@XmlAttribute
private Long id;
@OneToMany
@XmlElement(name = "child")
@XmlElementWrapper
private Collection<Child> children;
}
@XmlRootElement
public class Child {
@XmlAttribute
private Long getParentId() {
return parent.getId();
}
@Id
@XmlAttribute
private Long id;
@ManyToOne
@XmlTransient // for preventing infinite circular problem
private Parent parent;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With