Question

I'm trying to parse the result from a RESTFull call using RestTemplate following this sample http://thekspace.com/home/component/content/article/57-restful-clients-in-spring-3.html

The XML Response is something like that:

<brands>
    <brand>
        <nodeRef>1111111</nodeRef>
        <name>Test</name>
    </brand>
</brands>

For first, I configured my application-context.xml like that:

<?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>

The class com.kipcast.dataModel.drugs.bean.BrandViewList is a bean with an @XStreamAlias("brand") defined.

Here how I do the rest call:

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 is the class from which I execute these instructions.

When I try to execute that, the getForObject() fails and I get that exception:

XStream unmarshalling exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: brands

My question is, how can I fix that? Why I get this kind of Exception? How can I tell him to skip root tag?

-------------- UPDATED --------------
fixed some issue and in particular:

List<Brand> brandViewList = (List<Brand>) restTemplate.getForObject(url, Brand.class, params);

but the result now is:

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
-------------------------------
Was it helpful?

Solution

EDIT: updated to contain only pertaining information

It's best if you have distinct classes handling "brands" and "brand" tags. I would create a Brand class, rename BrandList to Brands (to be closer to the XML parts they refer to), and let Brands hold a List<Brand>. Put the proper annotations to both classes and you should be done, e.g.:

@XStreamAlias("brands")
class Brands {
  @XStreamImplicit
  List<Brand> brand;
}

@XStreamAlias("brand")
class Brand {
  String nodeRef;
  String name;
}

The above code works perfectly when marshalling objects to XML, but fails as you describe when unmarshalling from XML to objects. For that to work fine, you need to tell the marshaller which annotated classes you have:

<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>

I created a sample project where I verify the setup.

OTHER TIPS

I solved this problem by using the ArrayList type. So no need to use a fake class to handle the list. It worked for me with something like this (without any annotation used) :

<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>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top