Reputation: 1896
I'm trying to implement Swagger on a Java application that has two Application classes due to the fact that one deals with "public" web services and the other deals with "admin" web services. I'm trying to generate two separate swagger.json files, one for each Application class. However, only one of them is being generated for both urls. Here's some code:
Public Application class:
@WebServlet
@ApplicationPath("/public")
public class PublicApplication extends Application {
public PublicApplication() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0");
beanConfig.setTitle("A Fine Title");
beanConfig.setDescription("A Fine Description.");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setBasePath("/api");
beanConfig.setResourcePackage("com.test.rest.resource.external");
beanConfig.setPrettyPrint(true);
beanConfig.setScan(true);
}
}
Private Application class:
@WebServlet
@ApplicationPath("/admin")
public class AdminApplication extends Application {
public AdminApplication() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0");
beanConfig.setTitle("Another Fine Title");
beanConfig.setDescription("Another Fine Description.");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setBasePath("/apiTwo");
beanConfig.setResourcePackage("com.test.rest.resource.internal");
beanConfig.setPrettyPrint(true);
beanConfig.setScan(true);
}
}
Now if I hit either of these urls I get the same "public" swagger json file:
What am I doing wrong?
Thanks to all who read!
Upvotes: 8
Views: 4145
Reputation: 11
I run into the same issue but with with swagger v3. It took me quiet some effort to solve it so I want to share it.
import io.swagger.v3.jaxrs2.Reader
import io.swagger.v3.jaxrs2.integration.JaxrsApplicationScanner
import io.swagger.v3.jaxrs2.integration.JaxrsOpenApiContext
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
import io.swagger.v3.oas.models.servers.Server
import javax.enterprise.inject.Instance
import javax.inject.Inject
import javax.servlet.ServletConfig
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.core.Application
import javax.ws.rs.core.Context
import javax.ws.rs.core.MediaType
@Path("/openapi.json")
open class OpenApiPath {
@field:Inject
private lateinit var applications: Instance<Application>
@field:Context
private lateinit var servletConfig: ServletConfig
private val openApi by lazy { initOpenApi() }
@GET
@Produces(MediaType.APPLICATION_JSON)
@Operation(hidden = true)
open fun getSchema() = openApi
private fun initOpenApi(): OpenAPI {
val initial = OpenAPI().apply {
info(Info().title("Application title"))
servers(
listOf(
Server().url(servletConfig.servletContext.contextPath)
)
)
}
val applications = applications.toList()
val openApi = applications.fold(initial) { initial, app ->
val context = JaxrsOpenApiContext<JaxrsOpenApiContext<*>>()
context.app(app)
context.setOpenApiReader(Reader(initial).apply { setApplication(app) })
context.setOpenApiScanner(JaxrsApplicationScanner().application(app))
context.read()
}
return openApi
}
}
This works if you have registered all your jaxrs resources in the Application
class.
Don't forget to register io.swagger.v3.jaxrs2.SwaggerSerializers
.
Upvotes: 0
Reputation: 2171
By default, Swagger does initialization of scanner and configuration once. If you have multiple applications or configs, you need to set a configId, scannerId & contextId to each of your application via BeanConfig
and this should match with the values in your servlet config. And this settings work only with latest versions of swagger I think. I tried with swagger-1.5.13. An example is shown below.
public class PublicApplication extends Application {
public PublicApplication() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0");
beanConfig.setTitle("A Fine Title");
beanConfig.setDescription("A Fine Description.");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setBasePath("/api");
beanConfig.setResourcePackage("com.test.rest.resource.external");
beanConfig.setPrettyPrint(true);
// Set configId,contextId & scannerId
beanConfig.setConfigId("public");
beanConfig.setContextId("public");
beanConfig.setScannerId("public");
beanConfig.setScan(true);
}
Your AdminApplication class
public AdminApplication() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0");
beanConfig.setTitle("Another Fine Title");
beanConfig.setDescription("Another Fine Description.");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setBasePath("/apiTwo");
beanConfig.setResourcePackage("com.test.rest.resource.internal");
beanConfig.setPrettyPrint(true);
// Set configId,contextId & scannerId
beanConfig.setConfigId("admin");
beanConfig.setContextId("admin");
beanConfig.setScannerId("admin");
beanConfig.setScan(true);
beanConfig.setScan(true);
}
You should also specify the configId, contextId & scannerId in your servlet config as init parameter as shown below.
<servlet>
<servlet-name>jersey-rest-public</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.rest.resource.PublicApplication</param-value>
</init-param>
<init-param>
<param-name>swagger.scanner.id</param-name>
<param-value>public</param-value>
</init-param>
<init-param>
<param-name>swagger.context.id</param-name>
<param-value>public</param-value>
</init-param>
<init-param>
<param-name>swagger.config.id</param-name>
<param-value>public</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>jersey-rest-admin</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.rest.resource.AdminApplication</param-value>
</init-param>
<init-param>
<param-name>swagger.context.id</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>swagger.scanner.id</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>swagger.config.id</param-name>
<param-value>admin</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Upvotes: 7