views:

1045

answers:

2

I'm trying to create a simple spring based webservice that supports a "post" with xml content.

In spring, I define an AnnotationMethodHandler:

<bean id="inboundMessageAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <util:list>
                <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
                    <property name="marshaller" ref="xmlMarshaller"/>
                    <property name="unmarshaller" ref="xmlMarshaller"/>
                </bean>
            </util:list>
        </property>
    </bean>

And a jaxb based xml marshaller:

<bean id="xmlMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="contextPaths">
            <array>
                <value>com.company.schema</value>
            </array>
        </property>
        <property name="schemas">
            <array>
                <value>classpath:core.xsd</value>
            </array>
        </property>
    </bean>

My controller is annotated as follows, where "Resource" is a class autogenerated by jaxb:

@RequestMapping(method = POST, value = "/resource")
    public Resource createResource(@RequestBody Resource resource) {
       // do work
    }

The result of a webservice call is always "HTTP/1.1 415 Unsupported Media Type". Here is an example service call:

HttpPost post = new HttpPost(uri);
post.addHeader("Accept", "application/xml");
post.addHeader("Content-Type", "application/xml");

StringEntity entity = new StringEntity(request, "UTF-8");
entity.setContentType("application/xml");
post.setEntity(entity);

It seems to me that I am setting the correct media type everywhere possible. Anyone have an ideas?

Edit: after further debugging, it looks as though it never gets as far as trying to unmarshal the object. I don't quite understand the black magic behind how the AnnotationMethodHandler knows that something of type application/xml should go to the MarshallingHttpConverter. Can anyone shed any light on that?

+1  A: 

The most likely reason is that the JAXB context doesn't know how to unmarshal to a Resource object.

Does Resource have an @XMLRootElement annotation? If not, then Jaxb2Marshaller will not accept the parameter, and you'll get the 415 error. This is done by delegation from Sprng to the JAXB runtime, Spring doesn't really have much say in the matter.

edit: The actual coercion of the data on to the @RequestBody parameter is done in HandlerMethodInvoker.resolveRequestBody(). There are quite a number of conditions that must be met before the match is made, including matching of MIME type and parameter class type, and if it fails, there's no logging, just the HTTP 415. Have a look at the source for that method, and better yet, do some remote debugging to see where the logic is failing for your setup.

skaffman
Thanks for the suggestion, skaffman. I check and the class does indeed have an @XMLRootElement tag.
Mayra
@Mayra: And `Resource` is in the `com.company.schema` package? Try writing a unit test that constructs a `Jaxb2Marshaller` with your config, and make sure `support(Resource.class)` returns `true`. That needs to work before you can get any further.
skaffman
No dice, I created a Jaxb2Marshaller object, set the contextPath and schema as I have in my spring file, and it says it supports my class.
Mayra
@Mayra: See edited answer.
skaffman
@skaffman: Thanks, that brought me to the right answer! Turns out it had nothing to do with that configuration, another definition of the AnnotationMethodHandler elsewhere in the server was conflicting with my definition.
Mayra
@Mayra: Glad to hear it. It had to be in there somewhere :)
skaffman
A: 

Hi,

I am trying to do the exact same RESTFUL thing that you are doing and have been struggling with how to put all these together (not just bits and pieces).

I desperately need server-side Sample Code.

Can anyone help me on this, please?

Some of the key words included in this Sample Code would be:

JAXB @ReqestBody @xmlRootElement MarshallingView MarshallingHttpMessageConverter RestTemplate etc.

Mimi
Why did it says this question was answered? I don't see an answer here.
Mimi
The snippets in the original post are sufficient. I marked the other answer as "answered" because it brought me to the realization that there was nothing wrong with what I was doing in that sample code, I was just including the wrong spring files.
Mayra