【问题标题】:restful service interface with jersey带有球衣的宁静服务接口
【发布时间】:2013-12-07 12:49:40
【问题描述】:

我可以创建一个带有接口和实现类的restful服务吗?

如果是这样,所有与 JAX-RS 相关的导入都会进入接口吗?

我正在使用 jersey2.4 和 jetty8.1。

这是我的MyService界面:

package foo.bar; 

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

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

}

以及MyServiceImpl该接口的实现

package foo.bar.impl;

public class MyServiceImpl implements MyService {

     public MyServiceImpl() {}

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

这是 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.packages</param-name>
        <param-value>foo.bar</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

我注册了这个服务提供商包 (foo.bar) 但它抱怨说这个

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.

当我尝试使用实现类包 (foo.bar.impl) 时,它抱怨说这个

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

当我尝试两者时 - 它的抱怨与上述相同:

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.

我做错了什么?

【问题讨论】:

  • 你有没有想过这个问题?我有同样的问题。
  • 是的,但不是我描述的方式。我们分离了资源类和服务类。资源类将“组成”服务对象引用。您可以遵循服务对象的继承原则。希望这会有所帮助。
  • 我发现这是 Jersey 的一个错误,当您使用它的包扫描自动搜索提供者/等时。如果您显式注册资源/提供者类,则不会出现此错误。

标签: web-services jetty jackson jersey-2.0 jetty-8


【解决方案1】:

这是我经过几次试验后遇到的解决方案(我正在使用 jetty 9 和 jersey 2.13):而不是注释界面(使用 @Path("/abc") ),尝试对实现类进行注解。

我认为这很有意义,因为接口是“抽象的”,不应该绑定到物理路径。这样,接口可以在不同的路径中重复使用。

【讨论】:

  • 这不会阻止您使用接口生成客户端代理吗?
【解决方案2】:

如果你想使用带有 JAX-RS 注释的接口,你不能再扫描带有 web.xml 的包

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

你需要手动绑定你的接口和你的资源实现

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

原因:

出于性能原因,我们决定在扫描期间忽略接口。我们还修复了 Jersey 不会尝试实例化接口的问题。

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

【讨论】:

  • 关于Also we fixed that Jersey will not try to instantiate interfaces.:看起来这个问题还没有修复?我正在使用 2.13
  • @Ronan Quillevere,应该手动绑定哪个文件。我已经习惯了 SpringBoot 的事情只是发生在你身上。
【解决方案3】:

我也在为“找不到合适的构造函数”问题而苦苦挣扎。我想把我所有的注释(包括@Path)放在我的接口上。我能够通过自己管理资源的生命周期来使其工作,而不是让 Jersey 实例化它们。

例如,如果您有实现 YourRestInterface 的 YourImplementation,您会执行以下操作来向 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】:

    在ResourceConfig类中,有这样一个构造函数

    ResourceConfig(Class<?>... classes)
    

    构造函数创建一个新的资源配置,并使用一组给定的资源/提供者类进行初始化。
    所以你可以扩展ResourceConfig来注册实现类。

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

    然后,配置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>
    

    但最简单的方法是在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>
    

    【讨论】:

    • 就我而言,我必须扩展 DefaultResourceConfig
    【解决方案5】:

    是的,您可以使用该界面进行注释。在我们的应用程序中,我们已经通过这种方式实现了。以下引用来自 Jersy specifications。

    JAX-RS 注解可以用在方法和方法参数上 超类或实现的接口。这样的注释是 由对应的子类或实现类方法继承 前提是该方法及其参数没有任何 JAX-RS 自己的注解。超类的注释优先 在已实现的接口上。如果一个子类或 实现方法具有任何 JAX-RS 注释,然后所有 忽略超类或接口方法上的注解

    我认为在您的情况下,由于您可能错过了映射,请检查错误。 <servlet-mapping> <servlet-name>api</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping>

    【讨论】:

      猜你喜欢
      • 2015-07-19
      • 2018-04-21
      • 2016-12-17
      • 1970-01-01
      • 2013-07-29
      • 2015-12-17
      • 1970-01-01
      • 1970-01-01
      • 2014-04-06
      相关资源
      最近更新 更多