java-使用JAXB解组/编组List
我正在尝试创建一个非常简单的REST服务器。 我只是有一个测试方法,它将返回字符串列表。 这是代码:
它给出以下错误:
SEVERE: A message body writer for Java type,
class java.util.Vector, and MIME media type,
application/octet-stream, was not found
我希望JAXB对诸如String,Integer等简单类型具有默认设置。我想不是。 这是我的想象:
a
b
使这种方法最简单的方法是什么?
User1 asked 2020-07-05T10:56:44Z
12个解决方案
46 votes
我使用@LiorH的示例并将其扩展为:
请注意,它使用泛型,因此您可以将其与String以外的其他类一起使用。 现在,应用程序代码很简单:
为什么JAXB包中不存在这个简单的类? 有人在其他地方看到类似的东西吗?
User1 answered 2020-07-05T10:57:12Z
32 votes
@GET
@Path("/test2")
public Response test2(){
List list=new Vector();
list.add("a");
list.add("b");
final GenericEntity> entity = new GenericEntity>(list) { };
return Response.ok().entity(entity).build();
}
Sample Code answered 2020-07-05T10:57:28Z
12 votes
如果任何人都想为包含多个类的元素的列表编写列表包装器,并且想要根据类类型给出单独的XmlElement名称而不编写X Wrapper类,则可以使用@XmlElementRef注释。这样,JAXB根据@XmlRootElement设置的值来命名列表中的项目。这样做时,您必须使用@XmlSeeAlso指定可能在列表中的类
例:
列表中可能的类
@XmlRootElement(name="user")
public class User {/*...*/}
@XmlRootElement(name="entry")
public class LogEntry {/*...*/}
包装类
@XmlRootElement(name="records")
@XmlSeeAlso({User.class, LogEntry.class})
public static class JaxbList{
protected List records;
public JaxbList(){}
public JaxbList(List list){
this.records=list;
}
@XmlMixed
public List getRecords(){
return records;
}
}
例:
List l = new List();
l.add(new User("userA"));
l.add(new LogEntry(new UserB()));
XStream xStream = new XStream();
String result = xStream.toXML(l);
结果:
...
...
另外,您可以使用2952940390271419419392注释直接在包装类中指定XmlElement名称。
@XmlRootElement(name="records")
@XmlSeeAlso({User.class, LogEntry.class})
public static class JaxbList{
protected List records;
public JaxbList(){}
public JaxbList(List list){
this.records=list;
}
@XmlElementRefs({
@XmlElementRef(name="item", type=Object.class),
@XmlElementRef(name="user", type=User.class),
@XmlElementRef(name="entry", type=LogEntry.class)
})
public List getRecords(){
return records;
}
}
Zounadire answered 2020-07-05T10:58:14Z
11 votes
从个人博客文章中,不必创建特定的JaxbList < T >对象。
假设一个对象带有字符串列表:
@XmlRootElement
public class ObjectWithList {
private List list;
@XmlElementWrapper(name="MyList")
@XmlElement
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
}
JAXB往返:
public static void simpleExample() throws JAXBException {
List l = new ArrayList();
l.add("Somewhere");
l.add("This and that");
l.add("Something");
// Object with list
ObjectWithList owl = new ObjectWithList();
owl.setList(l);
JAXBContext jc = JAXBContext.newInstance(ObjectWithList.class);
ObjectWithList retr = marshallUnmarshall(owl, jc);
for (String s : retr.getList()) {
System.out.println(s);
} System.out.println(" ");
}
产生以下内容:
Somewhere
This and that
Something
Jérôme Verstrynge answered 2020-07-05T10:58:48Z
11 votes
使用出色的XStream库,可以更轻松地完成此操作。 没有包装,没有注释。
目标XML
a
b
序列化
(String别名可以通过使用小写2952941757329310710721标签来避免,但我使用的是OP的代码)
List list = new ArrayList ();
list.add("a");
list.add("b");
XStream xStream = new XStream();
xStream.alias("Strings", List.class);
xStream.alias("String", String.class);
String result = xStream.toXML(list);
反序列化
反序列化为ArrayList
XStream xStream = new XStream();
xStream.alias("Strings", ArrayList.class);
xStream.alias("String", String.class);
xStream.addImplicitArray(ArrayList.class, "elementData");
List result = (List )xStream.fromXML(file);
反序列化为String []
XStream xStream = new XStream();
xStream.alias("Strings", String[].class);
xStream.alias("String", String.class);
String[] result = (String[])xStream.fromXML(file);
请注意,XStream实例是线程安全的,并且可以预先配置,从而使代码量减少到一线。
XStream也可以用作JAX-RS服务的默认序列化机制。 可以在此处找到在Xersey中插入XStream的示例
Alex Abdugafarov answered 2020-07-05T10:59:44Z
8 votes
我几次遇到这种模式,我发现最简单的方法是用JaxB批注定义内部类。 (无论如何,您可能需要定义根标签名称)
所以你的代码看起来像这样
@GET
@Path("/test2")
public Object test2(){
MyResourceWrapper wrapper = new MyResourceWrapper();
wrapper .add("a");
wrapper .add("b");
return wrapper ;
}
@XmlRootElement(name="MyResource")
private static class MyResourceWrapper {
@XmlElement(name="Item")
List list=new ArrayList();
MyResourceWrapper (){}
public void add(String s){ list.add(s);}
}
如果您使用javax.rs(jax-rs),我将返回包装为对象的Response对象
LiorH answered 2020-07-05T11:00:13Z
3 votes
最后,我使用context.xml解决了它。您需要在Spring JacksonJaxbJsonProvider和Maven 中进行一些更改
在您的春季context.xml中将JacksonJaxbJsonProvider添加到:
在您的Maven pom.xml中添加:
org.codehaus.jackson
jackson-jaxrs
1.9.0
petrsyn answered 2020-07-05T11:00:42Z
2 votes
User1的示例对我来说效果很好。 但是,作为警告,除非添加@XmlSeeAlso批注,否则它不能用于简单的String / Integer类型。
@XmlRootElement(name = "List")
@XmlSeeAlso(MovieTicket.class)
public class MovieTicketList {
protected List list;
尽管可以阻止我在整个应用程序中使用单个通用列表类,但此方法还可以。 它还可能解释了为什么在JAXB包中不存在这个看似明显的类。
piepera answered 2020-07-05T11:01:07Z
0 votes
确保在JaxbList中使用特定类添加@XmlSeeAlso标记。 非常重要,否则会引发HttpMessageNotWritableException
Maggy answered 2020-07-05T11:01:27Z
0 votes
如果我早点找到Resteasy Jackson Provider,我会节省时间。
只需添加Resteasy Jackson Provider JAR。 没有实体包装。 没有XML注释。 没有自定义消息正文编写器。
mstrthealias answered 2020-07-05T11:01:51Z
0 votes
如果您在jersey项目中使用maven,请在pom.xml中添加以下内容并更新项目依赖项,以便Jaxb能够检测模型类并将列表转换为Media类型应用程序XML:
com.sun.xml.bind
jaxb-core
2.2.11
user7455210 answered 2020-07-05T11:02:12Z
0 votes
对于更通用的解决方案,对于只需要编写一个新类的任何顶级列表的JAXB-XML序列化,请查看此问题中给出的解决方案:
是否可以以编程方式配置JAXB?
public class Wrapper {
private List items = new ArrayList();
@XmlAnyElement(lax=true)
public List getItems() {
return items;
}
}
//JAXBContext is thread safe and so create it in constructor or
//setter or wherever:
...
JAXBContext jc = JAXBContext.newInstance(Wrapper.class, clazz);
...
public String marshal(List things, Class clazz) {
//configure JAXB and marshaller
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//Create wrapper based on generic list of objects
Wrapper wrapper = new Wrapper(things);
JAXBElement wrapperJAXBElement = new JAXBElement(new QName(clazz.getSimpleName().toLowerCase()+"s"), Wrapper.class, wrapper);
StringWriter result = new StringWriter();
//marshal!
m.marshal(wrapperJAXBElement, result);
return result.toString();
}
Gonen I answered 2020-07-05T11:02:36Z