问题
I have a Spring-MVC
@RestController
that uses generic names rather than the names I have configured with @XmlRootElement
or @JacksonXmlRootElement
. I want XML
to look like this:
<list>
<foo>
<name>John</name>
</foo>
</list>
but I get the following:
<ArrayList>
<item>
<name>John</name>
</item>
</ArrayList>
Marshalling a single instance correctly looks like this:
<foo>
<name>John</name>
</foo>
To try and solve this, I've tried using both Jackson
and JAXB
annotations. I've also conducted an extensive search for someone else's solution on Stack Overflow, various blogs, and issues reported against Jackson
and Spring-mvc
.
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.XmlRootElement;
import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
public class JacksonXmlTest {
@XmlRootElement(name="foo")
@XmlAccessorType(XmlAccessType.FIELD)
public static class Foo {
private String name;
public Foo(String name) {
setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Test
public void understandListTest() throws JsonProcessingException {
// This is a JUnit test.....
List<Foo> fooList = new ArrayList<>();
fooList.add(new Foo("John"));
XmlMapper mapper = new XmlMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.registerModule(new JaxbAnnotationModule());
System.err.println(mapper.writeValueAsString(fooList));
System.err.println();
System.err.println(mapper.writeValueAsString(fooList.get(0)));
}
}
Please help me configure jackson to output the list wrapped in "list" tags and have each Foo object contained in "foo" tags rather than "item" tags.
回答1:
You should create a class ListFoo that contains a list of Foo Object:
@XmlRootElement(name="list")
@XmlAccessorType(XmlAccessType.FIELD)
public class ListFoo {
@XmlElement(name = "foo")
private List<Foo> listFoo;
// getters & setters
}
回答2:
Using MixIn feature you can define name for an ArrayList
class and others from java.util.*
.
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.addMixIn(ArrayList.class, ArrayListMixIn.class);
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
List<Item> items = new ArrayList<>();
items.add(new Item());
items.add(new Item());
System.out.println(xmlMapper.writeValueAsString(items));
}
}
@JacksonXmlRootElement(localName = "list")
interface ArrayListMixIn {
}
class Item {
private String name = "random - " + ThreadLocalRandom.current().nextDouble();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Above code prints:
<list>
<item>
<name>random - 0.2256442724594785</name>
</item>
<item>
<name>random - 0.9958813192003821</name>
</item>
</list>
来源:https://stackoverflow.com/questions/57596464/how-should-i-configure-jackson-to-produce-xml-using-the-xmlrootelement-on-list