Я разрабатываю веб-сервис JAX-RS с использованием RestEasy 2.2.2 для развертывания в Tomcat 7. Сервис возвращает (должен возвращать) XML с использованием JAXB.Возвращенный 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
) должны быть реализованы и использованы.У меня есть книга Билла Бёрка "RESTful Java с JAX-RS".Это очень полезно с точки зрения помощи в разработке сервисов JAX-RS, но я не смог найти достаточно подробностей о функциональности MessageBodyWriter
в соответствующем разделе.Мои интернет-поиски также не дали ничего, что могло бы направить меня в правильном направлении.
Я был бы признателен, если бы кто-нибудь мог помочь мне выяснить, как правильно реализовать интерфейсы MessageBodyWriter
(и 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
Я предполагаю, что причина заключается в отсутствии «правильного установщика», так что unmarshaller не пытается добавлять элементы в Collection
, но я не знаю, как этосеттер будет выглядеть так.Если кто-нибудь знает, как это сделать, я был бы признателен за помощь.
Заранее спасибо.
РЕДАКТИРОВАТЬ 2:
Кстати, я виделОтвет Криса, где он предлагает использовать @XmlJavaTypeAdapter
.Я попробовал предложение, и оно приближает меня к XML, который мне нужен.Однако в XML, который я получаю с помощью @XmlJavaTypeAdapter, есть дополнительный уровень (<class><items><item>
вместо <items><item>
--- как видно из моих примеров, у меня есть ConcurrentHashMap
экземпляры в качестве переменной-члена класса).Я также не могу изменить имя элемента отдельных элементов карты (они всегда называются «элемент»).
Это не большие проблемы, и я могу внести необходимые изменения и жить с ними при необходимости.Однако, если это возможно, я бы не хотел, чтобы они были в первую очередь.В образовательных целях я также хотел бы понять, почему код в EDIT 1 не работает для демаршаллинга (и как это исправить, если это возможно).
Заранее спасибо за помощь.