1
votes

I need to unmarshal a XML string into a class that already exists in my project, but I can't figure out how to unmarshal a certain part of the XML to a list of objects. Let me explain with some code:

I have this XML:

<user>
  <id>123</id>
  <name>John Doe</name>
  <vaddresses>
    <address>
      <street>Street XYZ</street>
    </address>
    <address>
      <street>Street ABC</street>
    </address>
  </vaddresses>
</user>

And I have these classes:

  • User
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "User", propOrder = {"id", "name", "addresses"})
public class User {

    @XmlElement
    private int id;

    @XmlElement
    private String name;

    @XmlElement
    private List<Address> addresses;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }
  • Address
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Address", propOrder = {"street"})
public class Address {

    @XmlElement
    private String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }
}

When I try to unmarshal the XML into these classes, fields id and name are processed correctly, but the same doesn't occur with the addresses:

  • Output
User: 
    Id: 123
    Nome: John Doe
    Addresses: null

How do I solve this problem? Is there some JAXB annotation that I can use? And how? Or do I need to create some type of XmlAdapter? (I've tried this one but without success...)

3
Shouldn't addresses be vadresses in your Java code?Claus

3 Answers

1
votes

You can leverage @XmlElementWrapper to add a grouping element around your collection:

@XmlElementWrapper(name="vaddresses")
@XmlElement(name="address")
private List<Address> addresses;

Note

You are adding more annotations than are necessary. JAXB is configuration by exception so you only need to annotate where you want the XML representation to differ from the default.

1
votes

I think you have to change the type of the private property addresses:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "User", propOrder = {"id", "name", "vaddresses"})
public class User {

    @XmlElement
    private int id;

    @XmlElement
    private String name;

    @XmlElement
    private VAddress vaddresses;

    //...
 }

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "VAddress", propOrder = {"addresses"})
public class VAddress {

    @XmlElement
    private List<Address> addresses;

    //...
 }

Maybe you can also try the annotation @XmlElementWrapper.

Regards,

0
votes

User.java

package generated;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "id",
    "name",
    "vaddresses"
})
@XmlRootElement(name = "user")
public class User {

    protected int id;
    @XmlElement(required = true)
    protected String name;
    @XmlElement(required = true)
    protected User.Vaddresses vaddresses;

    public int getId() {
        return id;
    }


    public void setId(int value) {
        this.id = value;
    }

    public String getName() {
        return name;
    }


    public void setName(String value) {
        this.name = value;
    }


    public User.Vaddresses getVaddresses() {
        return vaddresses;
    }

    public void setVaddresses(User.Vaddresses value) {
        this.vaddresses = value;
    }


    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "address"
    })
    public static class Vaddresses {

        @XmlElement(required = true)
        protected List<User.Vaddresses.Address> address;

        public List<User.Vaddresses.Address> getAddress() {
            if (address == null) {
                address = new ArrayList<User.Vaddresses.Address>();
            }
            return this.address;
        }


        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
            "street"
        })
        public static class Address {

            @XmlElement(required = true)
            protected String street;


            public String getStreet() {
                return street;
            }

            public void setStreet(String value) {
                this.street = value;
            }

        }

    }

}

JaxBExample.java

package generated;
import generated.User.Vaddresses.Address;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

public class JAXBExample {
    public static void main(String[] args) {

     try {

        File file = new File("D:\\StackOverFlow\\JAXBTest\\file.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(User.class);

        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        User user = (User) jaxbUnmarshaller.unmarshal(file);
        System.out.println("ID::"+user.getId());
        System.out.println("Name::"+user.getName());
        System.out.print("Addresses::");
        for(Address address:user.getVaddresses().getAddress())
        {
            System.out.println(address.getStreet());
        }


      } catch (JAXBException e) {
        e.printStackTrace();
      }

    }
}

output:--

ID::123 Name::John Doe Addresses::Street XYZ Street ABC