Je me demande s'il est possible d'annoter mes classes de sorte que la première fois que le marshaller rencontre un objet, il génère un élément XML du type approprié, mais toute référence ultérieure à cet objet aura une entrée XML IDREF créé?Can JAXB marshal par confinement d'abord puis marshal par @XmlIDREF pour les références suivantes?
Can JAXB marshal par confinement d'abord puis marshal par @XmlIDREF pour les références suivantes?
Répondre
Vous pouvez exploiter le concept de JAXB de XmlAdapter
faire quelque chose comme ce qui suit:
input.xml
Ce qui suit est le document XML que je vais utiliser pour cet exemple. La 3ème entrée phone-number
est une référence à la 1ère entrée phone-number
et la 5ème entrée phone-number
est une référence au 4 .:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A"/>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
<number>555-WORK</number>
<extension>1234</extension>
</phone-number>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
</customer>
client
La classe client conserve une collection de PhoneNumber
objets. La même instance de PhoneNumber peut apparaître plusieurs fois dans la collection.
package forum7587095;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
private List<PhoneNumber> phoneNumbers;
@XmlElement(name="phone-number")
public List<PhoneNumber> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
PhoneNumber
C'est une classe qui peut apparaître soit dans le document lui-même ou comme référence. Cela sera géré en utilisant un XmlAdapter
. Un XmlAdapter est configuré à l'aide de l'annotation @XmlJavaTypeAdapter
. Étant donné que nous avons spécifié cet adaptateur au niveau de type/classe qu'il appliquera à toutes les propriétés faisant référence à la classe PhoneNumber
:
package forum7587095;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(PhoneNumberAdapter.class)
public class PhoneNumber {
private String id;
private String number;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public boolean equals(Object arg0) {
if(null == arg0 || arg0.getClass() != this.getClass()) {
return false;
}
PhoneNumber test = (PhoneNumber) arg0;
if(!equals(id, test.getId())) {
return false;
}
return equals(number, test.getNumber());
}
protected boolean equals(String control, String test) {
if(null == control) {
return null == test;
} else {
return control.equals(test);
}
}
@Override
public int hashCode() {
return id.hashCode();
}
}
WorkPhoneNumber
Sur la base de votre commentaire que j'ai ajouté une sous-classe de PhoneNumber
.
package forum7587095;
public class WorkPhoneNumber extends PhoneNumber {
private String extension;
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
@Override
public boolean equals(Object arg0) {
if(!super.equals(arg0)) {
return false;
}
return equals(extension, ((WorkPhoneNumber) arg0).getExtension());
}
}
PhoneNumberAdapter
est inférieure à la mise en œuvre du XmlAdapter
. Notez que nous devons maintenir si l'objet PhoneNumber a déjà été vu. Si c'est le cas, nous remplissons seulement la partie id
de l'objet AdaptedPhoneNumber
.
package forum7587095;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{
private List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>();
private Map<String, PhoneNumber> phoneNumberMap = new HashMap<String, PhoneNumber>();
@XmlSeeAlso(AdaptedWorkPhoneNumber.class)
@XmlType(name="phone-number")
public static class AdaptedPhoneNumber {
@XmlAttribute public String id;
public String number;
public AdaptedPhoneNumber() {
}
public AdaptedPhoneNumber(PhoneNumber phoneNumber) {
id = phoneNumber.getId();
number = phoneNumber.getNumber();
}
public PhoneNumber getPhoneNumber() {
PhoneNumber phoneNumber = new PhoneNumber();
phoneNumber.setId(id);
phoneNumber.setNumber(number);
return phoneNumber;
}
}
@XmlType(name="work-phone-number")
public static class AdaptedWorkPhoneNumber extends AdaptedPhoneNumber {
public String extension;
public AdaptedWorkPhoneNumber() {
}
public AdaptedWorkPhoneNumber(WorkPhoneNumber workPhoneNumber) {
super(workPhoneNumber);
extension = workPhoneNumber.getExtension();
}
@Override
public WorkPhoneNumber getPhoneNumber() {
WorkPhoneNumber phoneNumber = new WorkPhoneNumber();
phoneNumber.setId(id);
phoneNumber.setNumber(number);
phoneNumber.setExtension(extension);
return phoneNumber;
}
}
@Override
public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception {
AdaptedPhoneNumber adaptedPhoneNumber;
if(phoneNumberList.contains(phoneNumber)) {
if(phoneNumber instanceof WorkPhoneNumber) {
adaptedPhoneNumber = new AdaptedWorkPhoneNumber();
} else {
adaptedPhoneNumber = new AdaptedPhoneNumber();
}
adaptedPhoneNumber.id = phoneNumber.getId();
} else {
if(phoneNumber instanceof WorkPhoneNumber) {
adaptedPhoneNumber = new AdaptedWorkPhoneNumber((WorkPhoneNumber)phoneNumber);
} else {
adaptedPhoneNumber = new AdaptedPhoneNumber(phoneNumber);
}
phoneNumberList.add(phoneNumber);
}
return adaptedPhoneNumber;
}
@Override
public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception {
PhoneNumber phoneNumber = phoneNumberMap.get(adaptedPhoneNumber.id);
if(null != phoneNumber) {
return phoneNumber;
}
phoneNumber = adaptedPhoneNumber.getPhoneNumber();
phoneNumberMap.put(phoneNumber.getId(), phoneNumber);
return phoneNumber;
}
}
Démo
Afin d'assurer la même instance du XmlAdapter
est utilisé pour l'ensemble marshal
et unmarshal
opérations que nous devons mettre spécifiquement une instance de la XMLAdapter tant sur le Marshaller
et Unmarshaller
:
package forum7587095;
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(Customer.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setAdapter(new PhoneNumberAdapter());
File xml = new File("src/forum7587095/input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
System.out.println(customer.getPhoneNumbers().get(0) == customer.getPhoneNumbers().get(2));
System.out.println(customer.getPhoneNumbers().get(3) == customer.getPhoneNumbers().get(4));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setAdapter(new PhoneNumberAdapter());
marshaller.marshal(customer, System.out);
}
}
Sortie
true
true
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A"/>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
<number>555-WORK</number>
<extension>1234</extension>
</phone-number>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
</customer>
Pour plus d'informations
- http://blog.bdoughan.com/2011/09/mixing-nesting-and-references-with.html
- http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html
- http://blog.bdoughan.com/search/label/XmlAdapter
- http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html
- http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
- 1. Can Jaxb marshal les éléments enfants sans l'élément racine?
- 2. Marshal paramètre dans JAXB
- 3. JAXB Marshal ne convertit pas le séparateur d'un tableau d'octets
- 4. comment pouvons-nous éviter l'allocation effectuée par Marshal :: StringToHGlobalAnsi?
- 5. Can XmlJavaTypeAdapter marshal objet à un autre objet?
- 6. Marshal :: copie avec CvMat
- 7. données Marshal trop court
- 8. golang: Marshal [] os.FileInfo dans JSON
- 9. KSOAP2 Marshal Tableau d'objets complexes
- 10. Ajouter StartElement à JAXBContext marshal
- 11. Comment marshal int * en C#?
- 12. Jackson marshal XMLAttribute obtient la valeur "null"
- 13. Comment marshal C# struct array?
- 14. Problème avec la classe Marshal
- 15. Comment puis-je marshal liste <int>?
- 16. Confusion avec Ruby `concept de Marshal`
- 17. Marshal une classe C++ à C#
- 18. XMLAdapter et XmlIDREF dans Moxy JAXB
- 19. Marshal ruby hash avec proc par défaut - supprimer le proc par défaut?
- 20. Utilisation de Marshal pour prendre l'objet à xml dans Camel
- 21. Problème étrange avec le module Ruby marshal
- 22. Pointeur de structure Marshal dans VS2010
- 23. Python: Incrémenter marshal/pickle un objet?
- 24. Marshal XMLAttribute dans la classe dérivée
- 25. Chaîne système à chaîne std sans marshal
- 26. Marshal :: GetFunctionPointerForDelegate: devrais-je publier son résultat?
- 27. C# classe Marshal disponible sur Xbox?
- 28. Type de retour générique de marshal pour com interop
- 29. Impossible d'utiliser la valeur Marshal sur les données sérialisables
- 30. MarshalException: CORBA MARSHAL 1398079745/Pourrait trouver les classes
Merci Blaise pour la réponse très détaillée! Ce concept est-il le même si 'PhoneNumber' avait des sous-classes? Par exemple, 'Customer' ayant plusieurs références à la même instance de sous-classe' PhoneNumber'? – holic87
@ holic87 - J'ai mis à jour ma réponse afin que 'PhoneNumber' ait des sous-classes. –
Merci pour la clarification! – holic87