restful service interface with jersey

江枫思渺然 提交于 2019-12-17 20:38:17

问题


Can I create a restful service with interface and implementation class?

If so, will all JAX-RS related imports go into the interface?

I am using jersey2.4 and jetty8.1.

Here is my MyService interface:

package foo.bar; 

@Path("/abc")
public interface MyService {

     @GET
     @JSONP
     @Path("/method/{id}")
     public MyResponse getStuff(@PathParam("id") Integer id);

}

And an implementation of MyServiceImpl that interface

package foo.bar.impl;

public class MyServiceImpl implements MyService {

     public MyServiceImpl() {}

     @Override
     public MyResponse getStuff(Integer id) {
         // do stuff
         return MyResponse;
     }
}

Here's the web.xml file:

<servlet>
    <servlet-name>Scivantage REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>foo.bar</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

I registered this service provider package (foo.bar) but it complains saying this

javax.servlet.ServletException: A MultiException has 1 exceptions.  They are:|1. java.lang.NoSuchMethodException: Could not find a suitable constructor in foo.bar.MyService class.

When I tried with implementation class package (foo.bar.impl), it complains saying this

I get HTTP ERROR 404; doesn't do anything else; no exceptions on console

When I tried both -- it complains the same as above:

javax.servlet.ServletException: A MultiException has 1 exceptions.  They are:|1. java.lang.NoSuchMethodException: Could not find a suitable constructor in foo.bar.MyService class.

What I am doing wrong?


回答1:


Here's a solution I came across after a few trials (I'm working with jetty 9 and jersey 2.13): instead of annotate the interface (with @Path("/abc")), try to annotate the implementation class instead.

I think this makes good sense since interface are 'abstract' and not supposed to be bound to physical paths. This way, the interface can be reused in different paths.




回答2:


If you want to use interfaces with JAX-RS annotation you can no longer scan a package with the web.xml

<param-name>jersey.config.server.provider.packages</param-name>
<param-value>XXX</param-value>

You need to manually bind your interface with your resource implementation

bind(YourResource.class).to(YourResourceImpl.class);

Reason for this :

We decided for performance reasons that during scanning the interfaces will be ignored. Also we fixed that Jersey will not try to instantiate interfaces.

https://java.net/jira/browse/JERSEY-1004




回答3:


I was struggling with the "Could not find a suitable constructor" issue as well. I wanted to put all of my annotations (including @Path) on my interfaces. I was able to make it work by managing the lifecycle of the resources myself rather than have Jersey instantiate them.

For example, if you had YourImplementation which implements YourRestInterface, you'd do something like this to register an instance of the implementation with Jersey:

public class RestConfig extends ResourceConfig {

    @Inject
    public RestConfig(ServiceLocator locator) {
        super();

        DynamicConfiguration c = Injections.getConfiguration(locator);
        Object implInstance = new YourImplementation();
        ServiceBindingBuilder<Object> bb = Injections.newFactoryBinder(new BeanFactory(locator, implInstance));
         // tell Jersey to use the factory below to get an instance of YourRestInterface.class
        bb.to(YourRestInterface.class);
        Injections.addBinding(bb, c);

            c.commit();
    }

    private static class BeanFactory implements Factory<Object> {

        private ServiceLocator locator;
        private Object bean;

        BeanFactory(ServiceLocator locator, Object bean)
        {
            this.locator = locator;
            this.bean = bean;
        }

        @Override
        public Object provide() {
               // have Jersey inject things annotated with @Context
            locator.inject(bean);
            return bean;
        }

        @Override
        public void dispose(Object instance) {
        }

    }
}



回答4:


In the class ResourceConfig, there is a constructor like this

ResourceConfig(Class<?>... classes)

The constructor create a new resource configuration initialized with a given set of resource/provider classes.
So you can extend ResourceConfig to register the implementation class.

public class RestConfig extends ResourceConfig {

    public RestConfig() {
        // register the implementation class
        super(MyServiceImpl.class);
    }

}

Then, configure web.xml.

<servlet>
    <servlet-name>Scivantage REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <!-- the path of RestConfig -->
        <param-value>foo.bar.RestConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

But the simplest way is that register the implementation class in web.xml.

<servlet>
    <servlet-name>Scivantage REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <!-- the path of implementation class -->
        <param-value>foo.bar.impl.MyServiceImpl</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>



回答5:


Yes you can use the interface to annotate. In our application we have implemented by this way. following quote is taken from Jersy specifications.

JAX-RS annotations MAY be used on the methods and method parameters of a super-class or an implemented interface. Such annotations are inherited by a corresponding sub-class or implementation class method provided that method and its parameters do not have any JAX-RS annotations of its own. Annotations on a super-class take precedence over those on an implemented interface. If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the super class or interface method are ignored

I think in your case the error because of you may have missed mapping please check. <servlet-mapping> <servlet-name>api</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping>



来源:https://stackoverflow.com/questions/20148269/restful-service-interface-with-jersey

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!