web-dev-qa-db-fra.com

Comment puis-je ajouter des attributs xml à la classe annotée jaxb XmlElementWrapper?

J'ai une classe avec une annotation XmlElementWrapper comme:

...

  @XmlElementWrapper(name="myList")
    @XmlElements({
    @XmlElement(name="myElement") }
    )
    private List<SomeType> someList = new LinkedList();

... Ce code produit du XML comme

<myList>
  <myElement> </myElement>
  <myElement> </myElement>
  <myElement> </myElement>
</myList>

jusqu'ici tout va bien.

Mais maintenant, je dois ajouter des attributs à la balise de liste pour obtenir du XML comme

<myList number="2">
  <myElement> </myElement>
  <myElement> </myElement>
  <myElement> </myElement>
</myList>

Existe-t-il un "moyen intelligent pour y parvenir sans créer une nouvelle classe qui contient représente la liste?

24
ABX

J'ai une meilleure solution pour votre question.

Pour créer Xml Java, utilisez le code suivant:

import Java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="myList")
public class Root {

    private String number;
    private List<String> someList;

    @XmlAttribute(name="number")
    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @XmlElement(name="myElement")
    public List<String> getSomeList() {
        return someList;
    }

    public void setSomeList(List<String> someList) {
        this.someList = someList;
    } 

    public Root(String numValue,List<String> someListValue) {
        this();
        this.number = numValue;
        this.someList = someListValue;  
    }

    /**
     * 
     */
    public Root() {
        // TODO Auto-generated constructor stub
    }

}

Pour exécuter le code ci-dessus à l'aide de JAXB, utilisez ce qui suit:

   import Java.util.ArrayList;
import Java.util.List;

import javax.xml.bind.*;

public class Demo {

        public static void main(String[] args) throws Exception {
            List<String> arg = new ArrayList<String>();
            arg.add("FOO");
            arg.add("BAR");
            Root root = new Root("123", arg);

            JAXBContext jc = JAXBContext.newInstance(Root.class);
            Marshaller marshaller = jc.createMarshaller();
            marshaller.marshal(root, System.out);
        }
}

Cela produira le XML suivant comme sortie:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <myList number="123">
        <myElement>FOO</myElement>
        <myElement>BAR</myElement>
    </myList>

Je pense que cela vous est plus utile.

Merci..

27
Noby George

L'implémentation JAXB MOXy (je suis le responsable technique) a une extension ( @ XmlPath ) pour gérer ce cas:

import Java.util.*;
import javax.xml.bind.annotation.*;
import org.Eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlPath("myList/@number")
    private int number;

    @XmlElementWrapper(name="myList") 
    @XmlElement(name="myElement") 
    private List<String> someList = new LinkedList<String>();

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public List<String> getSomeList() {
        return someList;
    }

    public void setSomeList(List<String> someList) {
        this.someList = someList;
    } 

}

Produira le XML suivant:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <myList number="123">
      <myElement>FOO</myElement>
      <myElement>BAR</myElement>
   </myList>
</root>

Lorsque ce code est exécuté:

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Root root = new Root();
        root.setNumber(123);
        root.getSomeList().add("FOO");
        root.getSomeList().add("BAR");

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }
}

Pour que cela fonctionne avec du code JAXB strictement standard, vous devrez utiliser un adaptateur XML:

Remarque:

Pour utiliser MOXy JAXB, vous devez ajouter un fichier appelé jaxb.properties avec vos classes de modèle avec l'entrée suivante:

javax.xml.bind.context.factory=org.Eclipse.persistence.jaxb.JAXBContextFactory
11
bdoughan

Si vous n'utilisez pas MOXy ou si vous souhaitez simplement vous en tenir aux annotations JAXB standard, vous pouvez étendre la réponse de Noby pour ajouter la prise en charge d'une classe wrapper générique. La réponse de Noby ne prend actuellement en charge qu'une liste de chaînes, mais disons par exemple que vous allez utiliser la même classe générique d'encapsuleur pour plusieurs classes différentes. Dans mon exemple, je veux créer une classe "PagedList" générique qui rassemblera quelque chose qui ressemble à une liste, mais contient également des informations sur le décalage de page et le nombre total d'éléments dans la liste non paginée.

Le seul inconvénient de cette solution est que vous devez ajouter des mappages @XmlElement supplémentaires pour chaque type de classe qui sera encapsulé. Dans l'ensemble cependant, probablement une meilleure solution que de créer une nouvelle classe pour chaque élément pagable.

@XmlType
public class PagedList<T> {
    @XmlAttribute
    public int offset;

    @XmlAttribute
    public long total;

    @XmlElements({
        @XmlElement(name="order", type=Order.class),
        @XmlElement(name="address", type=Address.class)
        // additional as needed
    })
    public List<T> items;
}

@XmlRootElement(name="customer-profile")
public class CustomerProfile {
    @XmlElement
    public PagedList<Order> orders;
    @XmlElement
    public PagedList<Address> addresses;
}

En rassemblant cet exemple, vous obtiendrez:

<customer-profile>
    <order offset="1" total="100">
        <order> ... </order>
        <order> ... </order>
        <order> ... </order>
        ...
    </orders>
    <addresses offset="1" total="5">
        <address> ... </address>
        <address> ... </address>
        <address> ... </address>
        <address> ... </address>
        <address> ... </address>
    <addresses>
</customer-profile>

J'espère que cela pourra aider. C'est au moins la solution sur laquelle je me suis installé.

4
ɲeuroburɳ