This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/master by this push:
new e95834d Enhancing OpenApiCustomizer to properly calculate dynamic
base path in certain scenarios when application path is also available (through
application instance for example).
e95834d is described below
commit e95834d53d583c157a565f88ed70dad9ceda8b6c
Author: reta <[email protected]>
AuthorDate: Mon Feb 5 20:33:38 2018 -0500
Enhancing OpenApiCustomizer to properly calculate dynamic base path in
certain scenarios when application path is also available (through application
instance for example).
---
.../cxf/jaxrs/openapi/OpenApiCustomizer.java | 51 ++++++++++++++++------
.../apache/cxf/jaxrs/openapi/OpenApiFeature.java | 9 +++-
.../AbstractOpenApiServiceDescriptionTest.java | 23 ++++++----
.../description/openapi/BookStoreApplication.java | 27 ++++++++++++
.../description/openapi/OpenApiCustomizerTest.java | 37 ++++++++++++++++
5 files changed, 124 insertions(+), 23 deletions(-)
diff --git
a/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiCustomizer.java
b/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiCustomizer.java
index 4f033fc..88978ef 100644
---
a/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiCustomizer.java
+++
b/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiCustomizer.java
@@ -26,14 +26,18 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.ws.rs.ApplicationPath;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.model.ApplicationInfo;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.model.doc.DocumentationProvider;
import org.apache.cxf.jaxrs.model.doc.JavaDocProvider;
import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
import io.swagger.v3.oas.integration.api.OpenAPIConfiguration;
import io.swagger.v3.oas.models.OpenAPI;
@@ -44,14 +48,11 @@ import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.tags.Tag;
public class OpenApiCustomizer {
-
- protected boolean dynamicBasePath;
-
- protected boolean replaceTags;
-
- protected DocumentationProvider javadocProvider;
-
- protected List<ClassResourceInfo> cris;
+ private boolean dynamicBasePath;
+ private boolean replaceTags;
+ private DocumentationProvider javadocProvider;
+ private List<ClassResourceInfo> cris;
+ private String applicationPath;
public OpenAPIConfiguration customize(final OpenAPIConfiguration
configuration) {
if (configuration == null) {
@@ -60,7 +61,13 @@ public class OpenApiCustomizer {
if (dynamicBasePath) {
final MessageContext ctx = createMessageContext();
- final String url =
StringUtils.substringBeforeLast(ctx.getUriInfo().getRequestUri().toString(),
"/");
+
+ // If the JAX-RS application with custom path is defined, it might
be present twice, in the
+ // request URI as well as in each resource operation URI. To
properly represent server URL,
+ // the application path should be removed from it.
+ final String url = StringUtils.removeEnd(
+
StringUtils.substringBeforeLast(ctx.getUriInfo().getRequestUri().toString(),
"/"),
+ applicationPath);
final Collection<Server> servers =
configuration.getOpenAPI().getServers();
if (servers == null || servers.stream().noneMatch(s ->
s.getUrl().equalsIgnoreCase(url))) {
@@ -71,10 +78,6 @@ public class OpenApiCustomizer {
return configuration;
}
- protected MessageContext createMessageContext() {
- return JAXRSUtils.createContextValue(JAXRSUtils.getCurrentMessage(),
null, MessageContext.class);
- }
-
public void customize(final OpenAPI oas) {
if (replaceTags || javadocProvider != null) {
Map<String, ClassResourceInfo> operations = new HashMap<>();
@@ -202,4 +205,26 @@ public class OpenApiCustomizer {
this.javadocProvider = new JavaDocProvider(javaDocURLs);
}
+ public void setApplicationInfo(ApplicationInfo application) {
+ if (application != null && application.getProvider() != null) {
+ final Class<?> clazz = application.getProvider().getClass();
+ final ApplicationPath path =
ResourceUtils.locateApplicationPath(clazz);
+
+ if (path != null) {
+ applicationPath = path.value();
+
+ if (!applicationPath.startsWith("/")) {
+ applicationPath = "/" + applicationPath;
+ }
+
+ if (applicationPath.endsWith("/")) {
+ applicationPath = applicationPath.substring(0,
applicationPath.lastIndexOf("/"));
+ }
+ }
+ }
+ }
+
+ private MessageContext createMessageContext() {
+ return JAXRSUtils.createContextValue(JAXRSUtils.getCurrentMessage(),
null, MessageContext.class);
+ }
}
diff --git
a/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiFeature.java
b/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiFeature.java
index ef6f2f3..c327b1f 100644
---
a/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiFeature.java
+++
b/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiFeature.java
@@ -127,6 +127,7 @@ public class OpenApiFeature extends AbstractFeature
implements SwaggerUiSupport,
Properties swaggerProps = null;
GenericOpenApiContextBuilder<?> openApiConfiguration;
+ final Application application = getApplicationOrDefault(server,
factory, sfb, bus);
if (StringUtils.isEmpty(getConfigLocation())) {
swaggerProps = getSwaggerProperties(propertiesLocation, bus);
@@ -147,11 +148,11 @@ public class OpenApiFeature extends AbstractFeature
implements SwaggerUiSupport,
.resourcePackages(getOrFallback(packages, swaggerProps,
RESOURCE_PACKAGE_PROPERTY));
openApiConfiguration = new JaxrsOpenApiContextBuilder<>()
- .application(getApplicationOrDefault(server, factory, sfb,
bus))
+ .application(application)
.openApiConfiguration(config);
} else {
openApiConfiguration = new JaxrsOpenApiContextBuilder<>()
- .application(getApplicationOrDefault(server, factory, sfb,
bus))
+ .application(application)
.configLocation(getConfigLocation());
}
@@ -163,6 +164,10 @@ public class OpenApiFeature extends AbstractFeature
implements SwaggerUiSupport,
.getUserDefinedOptions());
registerOpenApiResources(sfb, packages,
context.getOpenApiConfiguration());
registerSwaggerUiResources(sfb, combine(swaggerProps,
userProperties), factory, bus);
+
+ if (customizer != null) {
+
customizer.setApplicationInfo(factory.getApplicationProvider());
+ }
} catch (OpenApiConfigurationException ex) {
throw new RuntimeException("Unable to initialize OpenAPI context",
ex);
}
diff --git
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/AbstractOpenApiServiceDescriptionTest.java
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/AbstractOpenApiServiceDescriptionTest.java
index 25517ef..a386bbd 100644
---
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/AbstractOpenApiServiceDescriptionTest.java
+++
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/AbstractOpenApiServiceDescriptionTest.java
@@ -133,7 +133,7 @@ public abstract class AbstractOpenApiServiceDescriptionTest
extends AbstractBusC
doTestApiListingIsProperlyReturnedJSON(createWebClient("/openapi.json"),
useXForwarded, basePath);
checkUiResource();
}
- protected static void doTestApiListingIsProperlyReturnedJSON(final
WebClient client,
+ protected void doTestApiListingIsProperlyReturnedJSON(final WebClient
client,
boolean useXForwarded, String basePath) throws Exception {
if (useXForwarded) {
client.header("USE_XFORWARDED", true);
@@ -158,7 +158,7 @@ public abstract class AbstractOpenApiServiceDescriptionTest
extends AbstractBusC
assertEquals(3, map.size());
UserOperation getBooksOp = map.get("getBooks");
assertEquals(HttpMethod.GET, getBooksOp.getVerb());
- assertEquals("/bookstore", getBooksOp.getPath());
+ assertEquals(getApplicationPath() + "/bookstore",
getBooksOp.getPath());
// see https://github.com/swagger-api/swagger-core/issues/2646
if (getBooksOp.getProduces() != null) {
assertEquals(MediaType.APPLICATION_JSON,
getBooksOp.getProduces());
@@ -168,14 +168,14 @@ public abstract class
AbstractOpenApiServiceDescriptionTest extends AbstractBusC
assertEquals(ParameterType.QUERY,
getBooksOpParams.get(0).getType());
UserOperation getBookOp = map.get("getBook");
assertEquals(HttpMethod.GET, getBookOp.getVerb());
- assertEquals("/bookstore/{id}", getBookOp.getPath());
+ assertEquals(getApplicationPath() + "/bookstore/{id}",
getBookOp.getPath());
assertEquals(MediaType.APPLICATION_JSON, getBookOp.getProduces());
List<Parameter> getBookOpParams = getBookOp.getParameters();
assertEquals(1, getBookOpParams.size());
assertEquals(ParameterType.PATH, getBookOpParams.get(0).getType());
UserOperation deleteOp = map.get("delete");
assertEquals(HttpMethod.DELETE, deleteOp.getVerb());
- assertEquals("/bookstore/{id}", deleteOp.getPath());
+ assertEquals(getApplicationPath() + "/bookstore/{id}",
deleteOp.getPath());
List<Parameter> delOpParams = deleteOp.getParameters();
assertEquals(1, delOpParams.size());
assertEquals(ParameterType.PATH, delOpParams.get(0).getType());
@@ -196,7 +196,7 @@ public abstract class AbstractOpenApiServiceDescriptionTest
extends AbstractBusC
// Test that Swagger UI resources do not interfere with
// application-specific ones.
WebClient uiClient = WebClient
- .create("http://localhost:" + getPort() + "/css/book.css")
+ .create(getBaseUrl() + "/css/book.css")
.accept("text/css");
String css = uiClient.get(String.class);
assertThat(css, equalTo("body { background-color: lightblue; }"));
@@ -207,16 +207,23 @@ public abstract class
AbstractOpenApiServiceDescriptionTest extends AbstractBusC
// Test that Swagger UI resources do not interfere with
// application-specific ones and are accessible.
WebClient uiClient = WebClient
- .create("http://localhost:" + getPort() + "/swagger-ui.css")
+ .create(getBaseUrl() + "/swagger-ui.css")
.accept("text/css");
String css = uiClient.get(String.class);
assertThat(css, containsString(".swagger-ui{font"));
}
+ protected String getApplicationPath() {
+ return "";
+ }
+
+ protected String getBaseUrl() {
+ return "http://localhost:" + getPort();
+ }
protected WebClient createWebClient(final String url) {
return WebClient
- .create("http://localhost:" + getPort() + url,
+ .create(getBaseUrl() + url,
Arrays.< Object >asList(new JacksonJsonProvider()),
Arrays.< Feature >asList(new LoggingFeature()),
null)
@@ -224,7 +231,7 @@ public abstract class AbstractOpenApiServiceDescriptionTest
extends AbstractBusC
}
protected void checkUiResource() {
- WebClient uiClient = WebClient.create("http://localhost:" + getPort()
+ "/api-docs")
+ WebClient uiClient = WebClient.create(getBaseUrl() + "/api-docs")
.accept(MediaType.WILDCARD);
String uiHtml = uiClient.get(String.class);
assertTrue(uiHtml.contains("<title>Swagger UI</title>"));
diff --git
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/BookStoreApplication.java
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/BookStoreApplication.java
new file mode 100644
index 0000000..4faa65f
--- /dev/null
+++
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/BookStoreApplication.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.jaxrs.description.openapi;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+@ApplicationPath("/api")
+public class BookStoreApplication extends Application {
+
+}
diff --git
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/OpenApiCustomizerTest.java
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/OpenApiCustomizerTest.java
index 26b9f7d..c7a7091 100644
---
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/OpenApiCustomizerTest.java
+++
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/description/openapi/OpenApiCustomizerTest.java
@@ -18,6 +18,15 @@
*/
package org.apache.cxf.systest.jaxrs.description.openapi;
+import java.util.Arrays;
+import java.util.Collections;
+
+import javax.ws.rs.ext.RuntimeDelegate;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
import org.apache.cxf.jaxrs.openapi.OpenApiCustomizer;
import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
@@ -37,12 +46,31 @@ public class OpenApiCustomizerTest extends
AbstractOpenApiServiceDescriptionTest
}
@Override
+ protected void run() {
+ final JAXRSServerFactoryBean sf = RuntimeDelegate
+ .getInstance()
+ .createEndpoint(new BookStoreApplication(),
JAXRSServerFactoryBean.class);
+ sf.setResourceClasses(BookStoreOpenApi.class);
+ sf.setResourceClasses(BookStoreStylesheetsOpenApi.class);
+ sf.setResourceProvider(BookStoreOpenApi.class,
+ new SingletonResourceProvider(new BookStoreOpenApi()));
+ sf.setProvider(new JacksonJsonProvider());
+ final OpenApiFeature feature = createOpenApiFeature();
+ sf.setFeatures(Arrays.asList(feature));
+ sf.setAddress("http://localhost:" + port + "/api");
+ sf.create();
+ }
+
+
+ @Override
protected OpenApiFeature createOpenApiFeature() {
final OpenApiCustomizer customizer = new OpenApiCustomizer();
customizer.setDynamicBasePath(true);
final OpenApiFeature feature = super.createOpenApiFeature();
feature.setCustomizer(customizer);
+ feature.setScan(false);
+
feature.setResourcePackages(Collections.singleton(getClass().getPackage().getName()));
return feature;
}
@@ -58,6 +86,15 @@ public class OpenApiCustomizerTest extends
AbstractOpenApiServiceDescriptionTest
return PORT;
}
+ @Override
+ protected String getBaseUrl() {
+ return "http://localhost:" + getPort() + getApplicationPath();
+ }
+
+ protected String getApplicationPath() {
+ return "/api";
+ }
+
@Test
public void testApiListingIsProperlyReturnedJSON() throws Exception {
doTestApiListingIsProperlyReturnedJSON(false, "http://localhost:" +
getPort());
--
To stop receiving notification emails like this one, please contact
[email protected].