2011-09-28 7 views

Répondre

11

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

+0

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

+1

@ holic87 - J'ai mis à jour ma réponse afin que 'PhoneNumber' ait des sous-classes. –

+0

Merci pour la clarification! – holic87

Questions connexes