diff --git a/modules/swagger-gradle-plugin/README.md b/modules/swagger-gradle-plugin/README.md index b537562ac0..803e8686a6 100644 --- a/modules/swagger-gradle-plugin/README.md +++ b/modules/swagger-gradle-plugin/README.md @@ -84,6 +84,7 @@ Parameter | Description | Required | Default `resourceClasses`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false| `prettyPrint`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|`TRUE` `sortOutput`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|`FALSE` +`alwaysResolveAppPath`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|`FALSE` `openApiFile`|openapi file to be merged with resolved specification, equivalent to [config](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties) openAPI|false| `filterClass`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false| `readerClass`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false| @@ -118,3 +119,5 @@ info: Since version 2.1.6, `sortOutput` parameter is available, allowing to sort object properties and map keys alphabetically. Since version 2.1.6, `objectMapperProcessorClass` allows to configure also the ObjectMapper instance used to serialize the resolved OpenAPI +Since version 2.1.9, `alwaysResolveAppPath` parameter is available, allowing to trigger resolving of Application Path from annotaion also not in runtime (e.g. using servlet in separate application, or in maven plugin at build time, etc) + diff --git a/modules/swagger-gradle-plugin/src/main/java/io/swagger/v3/plugins/gradle/tasks/ResolveTask.java b/modules/swagger-gradle-plugin/src/main/java/io/swagger/v3/plugins/gradle/tasks/ResolveTask.java index 1a5e3ed9dd..bc3bcf4be9 100644 --- a/modules/swagger-gradle-plugin/src/main/java/io/swagger/v3/plugins/gradle/tasks/ResolveTask.java +++ b/modules/swagger-gradle-plugin/src/main/java/io/swagger/v3/plugins/gradle/tasks/ResolveTask.java @@ -67,6 +67,8 @@ public enum Format {JSON, YAML, JSONANDYAML}; private String objectMapperProcessorClass; private Boolean sortOutput = Boolean.FALSE; + private Boolean alwaysResolveAppPath = Boolean.FALSE; + private String contextId; @@ -306,6 +308,15 @@ public void setSortOutput(Boolean sortOutput) { this.sortOutput = sortOutput; } + @Input + @Optional + public Boolean getAlwaysResolveAppPath() { + return alwaysResolveAppPath; + } + + public void setAlwaysResolveAppPath(Boolean alwaysResolveAppPath) { + this.alwaysResolveAppPath = alwaysResolveAppPath; + } @TaskAction public void resolve() throws GradleException { @@ -406,6 +417,9 @@ public void resolve() throws GradleException { method=swaggerLoaderClass.getDeclaredMethod("setSortOutput", Boolean.class); method.invoke(swaggerLoader, sortOutput); + method=swaggerLoaderClass.getDeclaredMethod("setAlwaysResolveAppPath", Boolean.class); + method.invoke(swaggerLoader, alwaysResolveAppPath); + method=swaggerLoaderClass.getDeclaredMethod("setReadAllResources", Boolean.class); method.invoke(swaggerLoader, readAllResources); diff --git a/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/GenericOpenApiContext.java b/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/GenericOpenApiContext.java index 9e2127a4c4..1147189d62 100644 --- a/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/GenericOpenApiContext.java +++ b/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/GenericOpenApiContext.java @@ -527,6 +527,9 @@ private OpenAPIConfiguration mergeParentConfiguration(OpenAPIConfiguration confi if (merged.isSortOutput() == null) { merged.setSortOutput(parentConfig.isSortOutput()); } + if (merged.isAlwaysResolveAppPath() == null) { + merged.setAlwaysResolveAppPath(parentConfig.isAlwaysResolveAppPath()); + } if (merged.isReadAllResources() == null) { merged.setReadAllResources(parentConfig.isReadAllResources()); } diff --git a/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/SwaggerConfiguration.java b/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/SwaggerConfiguration.java index 7d5751e138..7091574270 100644 --- a/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/SwaggerConfiguration.java +++ b/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/SwaggerConfiguration.java @@ -32,6 +32,8 @@ public class SwaggerConfiguration implements OpenAPIConfiguration { private Boolean sortOutput; + private Boolean alwaysResolveAppPath; + public Long getCacheTTL() { return cacheTTL; } @@ -256,4 +258,27 @@ public SwaggerConfiguration sortOutput(Boolean sortOutput) { setSortOutput(sortOutput); return this; } + + /** + * @since 2.1.9 + */ + @Override + public Boolean isAlwaysResolveAppPath() { + return alwaysResolveAppPath; + } + + /** + * @since 2.1.9 + */ + public void setAlwaysResolveAppPath(Boolean alwaysResolveAppPath) { + this.alwaysResolveAppPath = alwaysResolveAppPath; + } + + /** + * @since 2.1.9 + */ + public SwaggerConfiguration alwaysResolveAppPath(Boolean alwaysResolveAppPath) { + setAlwaysResolveAppPath(alwaysResolveAppPath); + return this; + } } diff --git a/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/api/OpenAPIConfiguration.java b/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/api/OpenAPIConfiguration.java index f74568c731..8b88cb0541 100644 --- a/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/api/OpenAPIConfiguration.java +++ b/modules/swagger-integration/src/main/java/io/swagger/v3/oas/integration/api/OpenAPIConfiguration.java @@ -44,4 +44,9 @@ public interface OpenAPIConfiguration { */ Boolean isSortOutput(); + /** + * @since 2.1.9 + */ + Boolean isAlwaysResolveAppPath(); + } diff --git a/modules/swagger-jaxrs2-servlet-initializer-v2/src/main/java/io/swagger/v3/jaxrs2/integration/servlet/SwaggerServletInitializer.java b/modules/swagger-jaxrs2-servlet-initializer-v2/src/main/java/io/swagger/v3/jaxrs2/integration/servlet/SwaggerServletInitializer.java index 08d1c4bcad..95d41a2a58 100644 --- a/modules/swagger-jaxrs2-servlet-initializer-v2/src/main/java/io/swagger/v3/jaxrs2/integration/servlet/SwaggerServletInitializer.java +++ b/modules/swagger-jaxrs2-servlet-initializer-v2/src/main/java/io/swagger/v3/jaxrs2/integration/servlet/SwaggerServletInitializer.java @@ -10,6 +10,7 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; +import javax.ws.rs.ApplicationPath; import javax.ws.rs.Path; import java.util.HashSet; import java.util.LinkedHashSet; @@ -20,7 +21,7 @@ * * @since 2.1.2 */ -@HandlesTypes({Path.class, OpenAPIDefinition.class}) +@HandlesTypes({Path.class, OpenAPIDefinition.class, ApplicationPath.class}) public class SwaggerServletInitializer implements ServletContainerInitializer { static final Set ignored = new HashSet(); diff --git a/modules/swagger-jaxrs2-servlet-initializer/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerServletInitializer.java b/modules/swagger-jaxrs2-servlet-initializer/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerServletInitializer.java index cde56ee447..9a8146dca3 100644 --- a/modules/swagger-jaxrs2-servlet-initializer/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerServletInitializer.java +++ b/modules/swagger-jaxrs2-servlet-initializer/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerServletInitializer.java @@ -9,6 +9,7 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; +import javax.ws.rs.ApplicationPath; import javax.ws.rs.Path; import java.util.HashSet; import java.util.LinkedHashSet; @@ -20,7 +21,7 @@ * swagger-jaxrs2-servlet-initializer-v2 */ @Deprecated -@HandlesTypes({Path.class, OpenAPIDefinition.class}) +@HandlesTypes({Path.class, OpenAPIDefinition.class, ApplicationPath.class}) public class SwaggerServletInitializer implements ServletContainerInitializer { static final Set ignored = new HashSet(); diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java index e3867af3a9..e48ff1cb12 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java @@ -132,6 +132,7 @@ public OpenAPI read(Class cls) { * @return the generated OpenAPI definition */ public OpenAPI read(Set> classes) { + Set> sortedClasses = new TreeSet<>((class1, class2) -> { if (class1.equals(class2)) { return 0; @@ -146,6 +147,8 @@ public OpenAPI read(Set> classes) { Map, ReaderListener> listeners = new HashMap<>(); + String appPath = ""; + for (Class cls : sortedClasses) { if (ReaderListener.class.isAssignableFrom(cls) && !listeners.containsKey(cls)) { try { @@ -154,6 +157,14 @@ public OpenAPI read(Set> classes) { LOGGER.error("Failed to create ReaderListener", e); } } + if (config != null && Boolean.TRUE.equals(config.isAlwaysResolveAppPath())) { + if (Application.class.isAssignableFrom(cls)) { + ApplicationPath appPathAnnotation = ReflectionUtils.getAnnotation(cls, ApplicationPath.class); + if (appPathAnnotation != null) { + appPath = appPathAnnotation.value(); + } + } + } } for (ReaderListener listener : listeners.values()) { @@ -163,9 +174,13 @@ public OpenAPI read(Set> classes) { LOGGER.error("Unexpected error invoking beforeScan listener [" + listener.getClass().getName() + "]", e); } } + String appPathRuntime = resolveApplicationPath(); + if (StringUtils.isNotBlank(appPathRuntime)) { + appPath = appPathRuntime; + } for (Class cls : sortedClasses) { - read(cls, resolveApplicationPath(), null, false, null, null, new LinkedHashSet(), new ArrayList(), new HashSet>()); + read(cls, appPath, null, false, null, null, new LinkedHashSet(), new ArrayList(), new HashSet>()); } for (ReaderListener listener : listeners.values()) { diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/JaxrsAnnotationScanner.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/JaxrsAnnotationScanner.java index 7db902c264..b4e99bdbc2 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/JaxrsAnnotationScanner.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/JaxrsAnnotationScanner.java @@ -11,6 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import java.util.HashMap; import java.util.HashSet; @@ -92,6 +93,9 @@ public Set> classes() { try (ScanResult scanResult = graph.scan()) { classes = new HashSet<>(scanResult.getClassesWithAnnotation(javax.ws.rs.Path.class.getName()).loadClasses()); classes.addAll(new HashSet<>(scanResult.getClassesWithAnnotation(OpenAPIDefinition.class.getName()).loadClasses())); + if (Boolean.TRUE.equals(openApiConfiguration.isAlwaysResolveAppPath())) { + classes.addAll(new HashSet<>(scanResult.getClassesWithAnnotation(ApplicationPath.class.getName()).loadClasses())); + } } for (Class cls : classes) { diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletConfigContextUtils.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletConfigContextUtils.java index e6320b6650..e6933913bb 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletConfigContextUtils.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletConfigContextUtils.java @@ -31,6 +31,11 @@ public class ServletConfigContextUtils { */ public static final String OPENAPI_CONFIGURATION_SORTOUTPUT_KEY = "openApi.configuration.sortOutput"; + /** + * @since 2.1.9 + */ + public static final String OPENAPI_CONFIGURATION_ALWAYSRESOLVEAPPPATH_KEY = "openApi.configuration.alwaysResolveAppPath"; + /** * @since 2.0.6 */ diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletOpenApiConfigurationLoader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletOpenApiConfigurationLoader.java index 3c343c56c9..e757b659ad 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletOpenApiConfigurationLoader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/ServletOpenApiConfigurationLoader.java @@ -22,6 +22,7 @@ import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_READER_KEY; import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_SCANNER_KEY; import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_SORTOUTPUT_KEY; +import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.OPENAPI_CONFIGURATION_ALWAYSRESOLVEAPPPATH_KEY; import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.getBooleanInitParam; import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.getInitParam; import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.getLongInitParam; @@ -55,6 +56,7 @@ public OpenAPIConfiguration load(String path) throws IOException { .readAllResources(getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_READALLRESOURCES_KEY)) .prettyPrint(getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_PRETTYPRINT_KEY)) .sortOutput(getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_SORTOUTPUT_KEY)) + .alwaysResolveAppPath(getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_ALWAYSRESOLVEAPPPATH_KEY)) .readerClass(getInitParam(servletConfig, OPENAPI_CONFIGURATION_READER_KEY)) .cacheTTL(getLongInitParam(servletConfig, OPENAPI_CONFIGURATION_CACHE_TTL_KEY)) .scannerClass(getInitParam(servletConfig, OPENAPI_CONFIGURATION_SCANNER_KEY)) @@ -112,6 +114,9 @@ public boolean exists(String path) { if (getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_SORTOUTPUT_KEY) != null) { return true; } + if (getBooleanInitParam(servletConfig, OPENAPI_CONFIGURATION_ALWAYSRESOLVEAPPPATH_KEY) != null) { + return true; + } if (getInitParam(servletConfig, OPENAPI_CONFIGURATION_READER_KEY) != null) { return true; } diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerLoader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerLoader.java index 8c3e4a4f0b..23de8347f2 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerLoader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/integration/SwaggerLoader.java @@ -40,6 +40,8 @@ public class SwaggerLoader { private Boolean sortOutput = false; + private Boolean alwaysResolveAppPath = false; + /** * @since 2.0.6 */ @@ -177,6 +179,19 @@ public void setSortOutput(Boolean sortOutput) { this.sortOutput = sortOutput; } + /** + * @since 2.1.9 + */ + public Boolean getAlwaysResolveAppPath() { + return alwaysResolveAppPath; + } + + /** + * @since 2.1.9 + */ + public void setAlwaysResolveAppPath(Boolean alwaysResolveAppPath) { + this.alwaysResolveAppPath = alwaysResolveAppPath; + } public Map resolve() throws Exception{ @@ -223,7 +238,8 @@ public Map resolve() throws Exception{ .resourcePackages(resourcePackagesSet) .objectMapperProcessorClass(objectMapperProcessorClass) .modelConverterClasses(modelConverterSet) - .sortOutput(sortOutput); + .sortOutput(sortOutput) + .alwaysResolveAppPath(alwaysResolveAppPath); try { GenericOpenApiContextBuilder builder = new JaxrsOpenApiContextBuilder() .openApiConfiguration(config); diff --git a/modules/swagger-maven-plugin/README.md b/modules/swagger-maven-plugin/README.md index cae7c53e13..1d5b3e11b5 100644 --- a/modules/swagger-maven-plugin/README.md +++ b/modules/swagger-maven-plugin/README.md @@ -187,6 +187,7 @@ Parameter | Description | Required | Default `resourceClasses`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false| `prettyPrint`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|`TRUE` `sortOutput`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|`FALSE` +`alwaysResolveAppPath`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false|`FALSE` `openapiFilePath`|path to openapi file to be merged with resolved specification, see [config](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false| `configurationFilePath`|path to swagger config file to be merged with resolved specification, see [config](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration)|false| `filterClass`|see [configuration property](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties)|false| @@ -204,3 +205,4 @@ Since version 2.0.8, `configurationFilePath` parameter is available, allowing to Since version 2.1.6, `sortOutput` parameter is available, allowing to sort object properties and map keys alphabetically. Since version 2.1.6, `objectMapperProcessorClass` allows to configure also the ObjectMapper instance used to serialize the resolved OpenAPI +Since version 2.1.9, `alwaysResolveAppPath` parameter is available, allowing to trigger resolving of Application Path from annotaion also not in runtime (e.g. using servlet in separate application, or in maven plugin at build time, etc) diff --git a/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerMojo.java b/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerMojo.java index 0a01845423..f3ff049b43 100644 --- a/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerMojo.java +++ b/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerMojo.java @@ -151,6 +151,9 @@ private void setDefaultsIfMissing(SwaggerConfiguration config) { if (sortOutput == null) { sortOutput = Boolean.FALSE; } + if (alwaysResolveAppPath == null) { + alwaysResolveAppPath = Boolean.FALSE; + } if (config.isPrettyPrint() == null) { config.prettyPrint(prettyPrint); } @@ -160,6 +163,9 @@ private void setDefaultsIfMissing(SwaggerConfiguration config) { if (config.isSortOutput() == null) { config.sortOutput(sortOutput); } + if (config.isAlwaysResolveAppPath() == null) { + config.alwaysResolveAppPath(alwaysResolveAppPath); + } } /** @@ -294,6 +300,9 @@ private SwaggerConfiguration mergeConfig(OpenAPI openAPIInput, SwaggerConfigurat if (sortOutput != null) { config.sortOutput(sortOutput); } + if (alwaysResolveAppPath != null) { + config.alwaysResolveAppPath(alwaysResolveAppPath); + } if (readAllResources != null) { config.readAllResources(readAllResources); } @@ -388,6 +397,13 @@ private boolean isCollectionNotBlank(Collection collection) { @Parameter(property = "resolve.sortOutput") private Boolean sortOutput; + /** + * @since 2.1.9 + */ + @Parameter(property = "resolve.alwaysResolveAppPath") + private Boolean alwaysResolveAppPath; + + private String projectEncoding = "UTF-8"; private SwaggerConfiguration config;