带有 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
下,您仍然可以使用根资源。
这条路有点长,但是很管用!希望对您有所帮助。
我正在尝试将 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
下,您仍然可以使用根资源。
这条路有点长,但是很管用!希望对您有所帮助。