带有 Jersey 1.19 的 Swagger JAX-RS 给出 'Conflicting URI templates' 错误

Swagger JAX-RS with Jersey 1.19 gives 'Conflicting URI templates' error

我正在尝试将 Swagger 添加到使用 Jersey 1.19 的现有应用程序中。为了将 Swagger 添加到应用程序,我一直在遵循本指南:https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-1.X-Project-Setup-1.5.

当我在 Apache Tomcat 上部署应用程序时,出现以下错误:

SEVERE: Conflicting URI templates. The URI template / for root resource class io.swagger.jaxrs.listing.ApiListingResource and the URI template / transform to the same regular expression (/.*)?

奇怪的是,我的 Jersey servlet 没有部署在根上下文中,而是部署在 /api/* 上下文中,如 web.xml 文件所示:

<servlet>
    <servlet-name>MyApp Service</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>app.MyApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>MyApp Service</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>

My MyApplication class 定义如下:

public class MyApplication extends Application {

private final Set<Object> singletons = new HashSet<Object>();
private final Set<Class<?>> classes = new HashSet<Class<?>>();

public MyApplication() {

    MyResource resource= new MyResource();

    singletons.addAll(Arrays.asList(resource));

    BeanConfig beanConfig = new BeanConfig();
    beanConfig.setBasePath("/api");
    beanConfig.setResourcePackage(getClass().getPackage().getName());
    beanConfig.setTitle("REST API");
    beanConfig.setVersion("1.0.0");
    beanConfig.setScan(true);

    classes.add(io.swagger.jaxrs.listing.ApiListingResource.class);
    classes.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
}

@Override
public Set<Class<?>> getClasses() {
    return classes;
}

@Override
public Set<Object> getSingletons() {
    return singletons;
}}

我尝试了其他配置,比如在web.xml文件中定义Swagger servlet,而不是使用BeanConfig,但还是出现同样的错误。我已经让 Swagger 在另一个使用 Jersey 2 的项目上以这种方式工作,但不幸的是,当前项目必须保留在 Jersey 1.19 上。这是 pom.xml 文件中定义的 Swagger 依赖项:

<dependency>
  <groupId>io.swagger</groupId>
  <artifactId>swagger-jersey-jaxrs</artifactId>
  <version>1.5.0</version>
</dependency>

如有任何帮助,我们将不胜感激。

更新 2: 看起来 swagger-core 的 1.5.8 版本修复了这个问题。有关详细信息,请参阅 this commit


更新: 与其将 Swagger 资源添加为子资源,不如直接覆盖 @Path 映射更容易。有关详细信息,请参阅解决方案 2


我遇到了完全相同的问题。原因是 Swagger 资源被映射到根 @Path("/") public class ApiListingResource.


解决方案 1 - 没有并发映射

一个简单而不灵活的方法是定义任何资源映射到根路径@Path("/")


解决方案 2 - 覆盖 @Path 映射

2.1 覆盖 Swagger 类

ApiListingResource 应该得到一个新的 @Path 映射

package my.api.package.swagger

import javax.ws.rs.Path;

@Path("swagger")
public class ApiListingResource extends io.swagger.jaxrs.listing.ApiListingResource {}

SwaggerSerializers 应该得到新的包裹

package my.api.package.swagger;

import javax.ws.rs.ext.Provider;

@Provider
public class SwaggerSerializers extends io.swagger.jaxrs.listing.SwaggerSerializers {}

2.2 配置覆盖 类

在 Swagger 包配置中添加 my.api.package.swagger 而不是 io.swagger.jaxrs.listing


解决方案 3 - Swagger 资源作为子资源

其他解决方案是将 Swagger 移动到不同的路径,让您的资源可以映射到您喜欢的任何地方。为此,您需要:

3.1 从供应商 类.

移除 ApiListingResource

如果子类化 Application:

public MyApplication() {
    //init BeanConfig
    //add your resource classes

    //classes.add(io.swagger.jaxrs.listing.ApiListingResource.class);
    classes.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
}

如果您使用 com.sun.jersey.config.property.packages 参数通过 web.xml 配置:

<servlet>
    <servlet-name>your-rest-api</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>
            {your_application_packages},
            <!--io.swagger.jaxrs.json,-->
            <!--io.swagger.jaxrs.listing-->
        </param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.config.property.classnames</param-name>
        <param-value>
            io.swagger.jaxrs.listing.SwaggerSerializers,
            io.swagger.jaxrs.json.JacksonJsonProvider
        </param-value>
    </init-param>
</servlet>

顺便说一句,由于 Grizzly related bug.

,我注意到在 web.xml 中使用 <filter/> 配置 Jersey 的 GF 3.1.2.2 不适用于 Swagger

3.2 添加 ApiListingResources 作为您的资源之一的子资源

@Path("/") 
class RootResource {
    @Context ServletContext context;

    @Path("/swagger")
    public ApiListingResource swagger() {
        return new ApiListingSubResource(context);
    }
}

由于 ApiListingResource 现在不由 Jersey 管理,它不会被注入 ServletContext。为了克服这个问题,你必须将它作为构造函数参数传递,并为该子类 ApiListingResource 提供适当的构造函数:

// context has 'default' visibility
// so we need to stay in the same package 
// to be able to access it
package io.swagger.jaxrs.listing;

import javax.servlet.ServletContext;

public class ApiListingSubResource extends ApiListingResource {
    public ApiListingSubResource(ServletContext sc) { this.context = sc; }
}

现在您的 Swagger 描述符将在 http://hostname/app-path/swagger/swagger.json 下,您仍然可以使用根资源。

这条路有点长,但是很管用!希望对您有所帮助。