restful service interface with jersey

不羁的心 提交于 2019-11-28 12:41:52

Although this is a question posted a year ago, 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 re-used in different paths.

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

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) {
        }

    }
}

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>

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>

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