简体   繁体   中英

Bind generated REST service interface implementation to servlet

I have got a wadl file from which I'm generating objects and interfaces for the REST services with the wadl2java tool. I have implementations for these interfaces and all is fine so far. I have also configured the servlet in the web.xml but I just can´t get this to work. For now my web xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.classnames</param-name>
            <param-value>com.foo.ws.RestServiceImpl</param-value>               
        </init-param>    
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

The generated rest interface looks like following:

package com.foo.schemas;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import com.foo.schemas.BarRequest;
import com.foo.schemas.BarResponse;
import com.foo.schemas.FooRequest;
import com.foo.schemas.FooResponse;

@Path("services")
public interface RestService {

    @POST
    @Consumes("application/xml")
    @Produces("application/xml")
    BarResponse getBar(BarRequest barRequest);

    @POST
    @Consumes("application/xml")
    @Produces("application/xml")
    FooResponse getFoo(FooRequest fooRequest);
}

And it's implementation:

package com.foo.ws;

import org.glassfish.jersey.server.ResourceConfig;
import com.foo.RestService;
import com.foo.schemas.BarRequest;
import com.foo.schemas.BarResponse;
import com.foo.schemas.FooRequest;
import com.foo.schemas.FooResponse;

public class RestServiceImpl extends ResourceConfig implements RestService {
    public RestServiceImpl () {
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(RestServiceImpl.class).to(RestService.class);
            }
        });
    }

    @Override
    BarResponse getBar(BarRequest barRequest) {
        // Implementation omitted...
    }

    @Override
    FooResponse getFoo(FooRequest FooRequest) {
        // Implementation omitted...
    }
}

I think this looks fine but when I'm starting the web service I get following HTTP ERROR 503 :

Problem accessing /my-web-service/. Reason:

org.glassfish.jersey.server.model.ModelValidationException: Validation of    
the application resource model has failed during application initialization.
[[FATAL] A resource model has ambiguous (sub-)resource method for HTTP 
method POST and input mime-types as defined by"@Consumes" and "@Produces" 
annotations at Java methods public com.foo.schemas.BarResponse 
com.foo.ws.RestServiceImpl.getBar(com.foo.schemas.BarRequest) and public 
com.foo.schemas.FooResponse 
com.foo.ws.RestServiceImpl.getFoo(com.foo.schemas.FooRequest) at matching 
regular expression /services. These two methods produces and consumes 
exactly the same mime-types and therefore their invocation as a resource 
methods will always fail.; 
source='org.glassfish.jersey.server.model.RuntimeResource@5690c2a8'

It looks like the binding between the interface and implementation is correct but I don't really understand why I get this error? Yes the methods are defined with the same MIME-types for both the @Consumes and @Produces annotations but this is how wadl2java generated the interface? I have no idea how to solve this, are there any configuration errors for the servlet or wadl2java tool? I have not a clue, any help in this is really appreciated as I'm stuck with this one.

EDIT - Added wadl file

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xs="http://www.w3.org/2001/XMLSchema" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:foo="http://schemas.foo.com" 
         xsi:schemaLocation="http://wadl.dev.java.net/2009/02    http://www.w3.org/Submission/wadl/wadl.xsd" 
         xmlns="http://wadl.dev.java.net/2009/02">
<doc xml:lang="en">This wadl describes....</doc>
<grammars>
    <include href="foo.xsd"/>
</grammars>
<resources base="/foo">
    <resource path="services">
        <method id="getBar" name="POST">
            <doc xml:lang="en">Get all bars.</doc>
            <request>
                <representation mediaType="application/xml">
                    <param required="true" style="plain" id="barRequest" name="barRequest" type="foo:BarRequest"/>
                </representation>
            </request>
            <response status="200">
                <representation mediaType="application/xml">
                    <param required="true" style="plain" id="barResponse" name="barResponse" type="foo:BarResponse"/>
                </representation>
            </response>
        </method>
        <method id="getFoo" name="POST">
            <doc xml:lang="en">Get all foos.</doc>
            <request>
                <representation mediaType="application/xml">
                    <param required="true" style="plain" id="fooRequest" name="fooRequest" type="foo:FooRequest"/>
                </representation>
            </request>
            <response status="200">
                <representation mediaType="application/xml">
                    <param required="true" style="plain" id="fooResponse" name="fooResponse" type="foo:FooResponse"/>
                </representation>
            </response>
        </method>
    </resource>
</resources>

The issue is wrt how the resources are exposed.

  1. There are 2 POST Method's exposed, both listening to path " /services ".
  2. Both these methods Consume and Produce the same MimeType .

The problem - is if this resource is hit. Then Jersey would not understand which API to invoke in order to get the result. Is it getBar() or getFoo()

Now, the change depends on what the expectation is (which & when an API needs to be invoked, based on the requirement). You'll have to modify the WADL accordingly to make sure each resource listens to a unique path/consume/produce type.

@Path("services")
public interface RestService {

    @POST
    @Consumes("application/xml")
    @Produces("application/xml")
    BarResponse getBar(BarRequest barRequest);

    @POST
    @Consumes("application/xml")
    @Produces("application/xml")
    FooResponse getFoo(FooRequest fooRequest);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM