How to annotate a list using @XmlElement?
Solution 1
You need to leverage @XmlElementWrapper
and @XmlElement
.
Java Model
Content
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class Content {
private List<String> keywords;
public Content() {}
@XmlElementWrapper
@XmlElement(name="keyword")
public List<String> getKeywords() {
return keywords;
}
public void setKeywords(List<String> keywords) {
this.keywords = keywords;
}
}
Demo Code
Demo
import java.util.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Content.class);
List<String> strings = new ArrayList<String>(2);
strings.add("foo");
strings.add("bar");
Content content = new Content();
content.setKeywords(strings);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(content, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<content>
<keywords>
<keyword>foo</keyword>
<keyword>bar</keyword>
</keywords>
</content>
For More Information
Below are links to a couple articles from my blog that provide additional information:
- http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html
- http://blog.bdoughan.com/2012/12/jaxb-representing-null-and-empty.html
Solution 2
Use this form:
@XmlElementWrapper(name="keywords")
@XmlElement(name="keyword")
Please note that if keywords
is empty then you will get <keywords />
.
Sometimes you will need to add @XmlRootElement
to your class (depends on the context) and the @XmlAccessorType(XmlAccessType.?)
annotation. I usually use @XmlAccessorType(XmlAccessType.FIELD)
and annotate my fields with @XmlElement
.
user3429010
Updated on November 07, 2020Comments
-
user3429010 over 3 years
I have the following annotation using
javax.xml.bind.annotation.XmlElement
:@XmlElement public List<String> getKeywords() { return keywords; }
Which produces the following XML when I marshall some example content:
<keywords>keyword1</keywords> <keywords>keyword2</keywords>
I would like to get the following XML:
<keywords> <keyword>keyword1</keyword> <keyword>keyword2</keyword> </keywords>
What kind of an annotation should I use?
I've tried
@XmlElementWrapper @XmlElement(name="keyword")
But then the whole content disappears and the result is:
<keywords/>
The same happens also if I only try to rename the element:
@XmlElement(name="keyword")
What am I doing wrong?
UPDATE:
Here is the updated full code for the class according to the first answers, but it is still not working (the result is an empty list
<keywords/>
when marshalled to XML):import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Content { private List<String> keywords; public Content() {} @XmlElementWrapper(name="keywords") @XmlElement(name="keyword") public List<String> getKeywords() { return keywords; } public void setKeywords(List<String> keywords) { this.keywords = keywords; } }
I also tried the following with the same result:
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.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Content { @XmlElementWrapper(name="keywords") @XmlElement(name="keyword") private List<String> keywords; public Content() {} public List<String> getKeywords() { return keywords; } public void setKeywords(List<String> keywords) { this.keywords = keywords; } }
However, the keywords are not empty as the following produces
<keywords>keyword1</keywords><keywords>keyword2</keywords>
instead of an empty list:import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Content { private List<String> keywords; public Content() {} @XmlElement public List<String> getKeywords() { return keywords; } public void setKeywords(List<String> keywords) { this.keywords = keywords; } }
The code for marshalling is (JAX-RS):
import java.io.StringWriter; import javax.ws.rs.Consumes; import javax.ws.rs.Path; import javax.ws.rs.POST; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @Path("process") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_XML) public class ContentHandler { @POST public Response process(Content content) { StringWriter stringWriter = new StringWriter(); try { JAXBContext jaxbContext = JAXBContext.newInstance(Content.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); jaxbMarshaller.marshal(content, stringWriter); } catch (JAXBException e) { return Response.serverError().entity(e.getMessage()).build(); } return Response.ok(stringWriter.toString(), MediaType.APPLICATION_XML).build(); } }