32

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();       
    }

}
0

3 Answers 3

52

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:

1
  • 1
    Thanks, this works. There is a problem somewhere else in my code though, but that is a separate issue that I'll have to investigate. Commented Jun 19, 2014 at 14:26
22

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.

3
  • I tried this, but it did not work either. I updated my question with the full code for the class with these suggestions. Commented Jun 19, 2014 at 13:38
  • @user3429010 - Can you post the code where you populate the object model & marshal it to XML.
    – bdoughan
    Commented Jun 19, 2014 at 13:48
  • I updated my question with the code that I use for marshalling the object to XML. It is part of a RESTful service using Jersey. Commented Jun 19, 2014 at 14:00
0

Above answer by - Blaise Doughan is completely correct

Another simple way is , even if you don't write the - @XmlElementWrapper

 private List<String> keywords;

 @XmlElementWrapper
    @XmlElement(name="keyword")
    public List<String> getKeywords() {
        return keywords;
    }

You can use it this way - write the XmlAccessorType on Class level , then XML element name will be same as the class member name - keywords

import java.util.List;
import javax.xml.bind.annotation.*;

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

    private List<String> keywords;

    public Content() {}


    public List<String> getKeywords() {
        return keywords;
    }

    public void setKeywords(List<String> keywords) {
        this.keywords = keywords;
    }  

}

Not the answer you're looking for? Browse other questions tagged or ask your own question.