我正在使用 RestEasy 2.2.2 开发一个 JAX-RS Web 服务以部署到 Tomcat 7。该服务通过使用 JAXB 返回(应该返回)XML。返回的 XML 应包含 ConcurrentHashMap 的表示,类似于它在以下代码中的使用方式:
@XmlRootElement(name="items")
@XmlAccessorType(XmlAccessType.NONE)
public class ItemCollection
{
@XmlElement(name="item")
private ConcurrentHashMap<String, Item> items;
public ItemCollection()
{
items = new ConcurrentHashMap<String, item>();
// fill the map
}
}
该类Item
还包含一个ConcurrentHashMap
需要序列化为 XML 的类。
这是资源类:
@Path("/items")
public class ItemResource
{
@GET
@Produces(MediaType.APPLICATION_XML)
public ItemCollection getAllItems()
{
// get itemManager
return itemManager.getItems(); // ItemManager holds an instance of ItemCollection
}
}
此代码运行,但生成一个没有内容的 XML:
<items>
<item/>
</items>
我想要得到的输出是这样的:
<items>
<item id="...">
<data>...</data>
<otheritems>
<otheritem id="...">
<someotherdata>...</someotherdata>
</otheritem>
</otheritems>
</item>
<item id="...">
<data>...</data>
<otheritems>
<otheritem id="...">
<someotherdata>...</someotherdata>
</otheritem>
<otheritem id="...">
<someotherdata>...</someotherdata>
</otheritem>
<otheritem id="...">
<someotherdata>...</someotherdata>
</otheritem>
</otheritems>
</item>
</items>
我发现MessageBodyWriter
在内置功能不足的情况下需要实现。我试图想出一个MessageBodyWriter
实现来编组ConcurrentHashMap
,但到目前为止我还不能让它工作(即我可以得到被调用的代码,但它会因各种异常而停止)。
似乎我不太了解应该如何MessageBodyWriter
(和MessageBodyReader
)实现和使用接口。我有 Bill Burke 的“带有 JAX-RS 的 RESTful Java”一书。MessageBodyWriter
它在帮助设计 JAX-RS 服务方面非常有用,但我在相关部分中找不到有关该功能的足够详细信息。我的互联网搜索也没有产生任何可以引导我朝着正确方向前进的东西。
如果有人能帮助我弄清楚如何正确实现MessageBodyWriter
(and MessageBodyReader
) 接口,我将不胜感激。我不知道我是否遗漏了注释、放错了注释,或者我是否需要一种全新的方法。
提前感谢您的帮助。
编辑:
将代码修改为以下使我成功了一半:
@XmlRootElement(name="items")
@XmlAccessorType(XmlAccessType.NONE)
public class ItemCollection
{
private ConcurrentHashMap<String, Item> items;
public ItemCollection()
{
items = new ConcurrentHashMap<String, item>();
// fill the map
}
@XmlElement(name="item")
public Collection<Item> getItems()
{
return items.values();
}
}
这会生成我需要的 XML(上面包含的示例)。但是,此代码在解组时不起作用。我得到以下异常:
java.lang.UnsupportedOperationException
java.util.AbstractCollection.add(AbstractCollection.java:221)
com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.addToPack(Lister.java:290)
com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.addToPack(Lister.java:254)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Scope.add(Scope.java:106)
com.sun.xml.internal.bind.v2.runtime.property.ArrayERProperty$ReceiverImpl.receive(ArrayERProperty.java:195)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.endElement(UnmarshallingContext.java:507)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:145)
com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2938)
com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:200)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:173)
javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:137)
javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:142)
javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:151)
javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:169)
// ... the rest
我认为原因是缺少“正确的设置器”,因此解组器不会尝试将项目添加到 aCollection
但我不知道该设置器的外观。如果有人知道如何做到这一点,我将不胜感激。
提前致谢。
编辑2:
顺便说一句,我已经看到 Chris 的回复,他建议使用@XmlJavaTypeAdapter
. 我已经尝试过这个建议,它让我接近我需要的 XML。但是,我使用 @XmlJavaTypeAdapter 获得的 XML 在其中有一个额外的级别(<class><items><item>
而不是<items><item>
--- 如我的示例中所见,我将ConcurrentHashMap
实例作为类的成员变量)。我似乎也无法更改各个地图项的元素名称(它们总是被称为“项目”)。
这些都不是什么大问题,我可以做出必要的改变,并在必要时接受它们。但是,如果可能的话,我希望一开始就没有它们。出于教育目的,我还想了解为什么 EDIT 1 中的代码不能用于解组(以及如何修复它,如果可能的话)。
提前感谢所有帮助。