Весенний спокойный клиент:исключение корневого тега
Вопрос
Я пытаюсь проанализировать результат вызова RESTfull, используя RestTemplate, следуя этому примеру http://thekspace.com/home/component/content/article/57-restful-clients-in-spring-3.html
XML-ответ - это что-то вроде этого:
<brands>
<brand>
<nodeRef>1111111</nodeRef>
<name>Test</name>
</brand>
</brands>
Во-первых, я настроил свой application-context.xml следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean id="messageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
</list>
</property>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="brand">com.kipcast.dataModel.drugs.bean.BrandViewList</prop>
</props>
</property>
</bean>
</beans>
Класс com.kipcast.DataModel.drugs.bean.BrandViewList - это компонент с определенным @XStreamAlias ("бренд").
Вот как я делаю остальные звонки:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml", WebscriptCaller.class);
RestTemplate restTemplate = applicationContext.getBean("restTemplate", RestTemplate.class);
String url = "http://localhost:8081/alfresco/service/search/brand.xml?q={keyword}&alf_ticket={ticket}";
List<BrandViewList> results = (List<BrandViewList>) restTemplate.getForObject(url, List.class, params);
WebscriptCaller.class это класс, из которого я выполняю эти инструкции.
Когда я пытаюсь выполнить это, getForObject() завершается с ошибкой, и я получаю это исключение:
XStream unmarshalling exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: brands
Мой вопрос в том, как я могу это исправить?Почему я получаю такого рода Исключение?Как я могу сказать ему, чтобы он пропустил корневой тег?
-------------- ОБНОВЛЕНО --------------
исправлены некоторые проблемы, в частности:
List<Brand> brandViewList = (List<Brand>) restTemplate.getForObject(url, Brand.class, params);
но результат сейчас таков:
org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class com.kipcast.dataModel.drugs.bean.Brand]; nested exception is org.springframework.oxm.UnmarshallingFailureException: XStream unmarshalling exception; nested exception is com.thoughtworks.xstream.converters.ConversionException: nodeRef : nodeRef
---- Debugging information ----
message : nodeRef
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : nodeRef
class : java.util.ArrayList
required-type : java.util.ArrayList
converter-type : com.thoughtworks.xstream.converters.collections.CollectionConverter
path : /brands/brand/nodeRef
line number : 3
class[1] : com.kipcast.dataModel.drugs.bean.Brands
converter-type[1] : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
version : null
-------------------------------
Решение
Редактировать:обновлено, чтобы содержать только относящуюся к делу информацию
Лучше всего, если у вас есть отдельные классы, обрабатывающие теги "бренды" и "brand".Я бы создал Brand
класс, переименовать BrandList
Для Brands
(чтобы быть ближе к частям XML, на которые они ссылаются), и пусть Brands
держать в руках List<Brand>
.Поместите соответствующие аннотации к обоим классам, и все будет готово, например:
@XStreamAlias("brands")
class Brands {
@XStreamImplicit
List<Brand> brand;
}
@XStreamAlias("brand")
class Brand {
String nodeRef;
String name;
}
Приведенный выше код отлично работает при маршалировании объектов в XML, но терпит неудачу, как вы описали, при отмене маршалинга из XML в объекты.Чтобы это работало нормально, вам нужно сообщить маршалл-программе, какие аннотированные классы у вас есть:
<bean name="marshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
<property name="annotatedClasses">
<array>
<value>com.kipcast.dataModel.drugs.bean.BrandViewList</value>
<value>com.kipcast.dataModel.drugs.bean.BrandView</value>
</array>
</property>
</bean>
Я создал примерный проект где я проверяю настройку.
Другие советы
Я решил эту проблему, используя тип ArrayList .Поэтому нет необходимости использовать поддельный класс для обработки списка.У меня это сработало с чем-то вроде этого (без каких-либо используемых аннотаций). :
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="brands">java.util.ArrayList</prop>
<prop key="brand">com.kipcast.dataModel.drugs.bean.BrandView</prop>
</props>
</property>
</bean>