You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by de...@apache.org on 2019/01/23 13:42:15 UTC

[cxf] branch CXF-7601_microProfileOpenApi created (now ace2c8f)

This is an automated email from the ASF dual-hosted git repository.

deki pushed a change to branch CXF-7601_microProfileOpenApi
in repository https://gitbox.apache.org/repos/asf/cxf.git.


      at ace2c8f  [CXF-7601] Add support for Microprofile OpenAPI implementation (as an alternative to Swagger Core 2.0)

This branch includes the following new commits:

     new ace2c8f  [CXF-7601] Add support for Microprofile OpenAPI implementation (as an alternative to Swagger Core 2.0)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[cxf] 01/01: [CXF-7601] Add support for Microprofile OpenAPI implementation (as an alternative to Swagger Core 2.0)

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

deki pushed a commit to branch CXF-7601_microProfileOpenApi
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit ace2c8f9942c797e3d4e2f53f19781d5765065ff
Author: Dennis Kieselhorst <de...@apache.org>
AuthorDate: Wed Jan 23 14:41:54 2019 +0100

    [CXF-7601] Add support for Microprofile OpenAPI implementation (as an alternative to Swagger Core 2.0)
---
 rt/rs/description-microprofile-openapi/pom.xml     |  99 +++++
 .../cxf/jaxrs/mpopenapi/OpenApiEndpoint.java       |  43 ++
 .../apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java | 474 +++++++++++++++++++++
 .../cxf/jaxrs/mpopenapi/SwaggerProperties.java     |  69 +++
 .../org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java  |  47 ++
 rt/rs/pom.xml                                      |   1 +
 6 files changed, 733 insertions(+)

diff --git a/rt/rs/description-microprofile-openapi/pom.xml b/rt/rs/description-microprofile-openapi/pom.xml
new file mode 100644
index 0000000..e505aad
--- /dev/null
+++ b/rt/rs/description-microprofile-openapi/pom.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cxf-rt-rs-service-description-microprofile-openapi</artifactId>
+    <packaging>jar</packaging>
+    <name>Apache CXF JAX-RS Service Description Microprofile OpenAPI</name>
+    <description>Apache CXF JAX-RS Service Description Microprofile OpenAPI</description>
+    <url>http://cxf.apache.org</url>
+    <parent>
+        <groupId>org.apache.cxf</groupId>
+        <artifactId>cxf-parent</artifactId>
+        <version>3.3.0-SNAPSHOT</version>
+        <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+    <properties>
+        <cxf.module.name>org.apache.cxf.rs.openapi.microprofile</cxf.module.name>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${cxf.servlet-api.group}</groupId>
+            <artifactId>${cxf.servlet-api.artifact}</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-rs-service-description-swagger-ui</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-rs-json-basic</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.openapi</groupId>
+            <artifactId>microprofile-openapi-api</artifactId>
+            <version>1.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo</groupId>
+            <artifactId>geronimo-openapi-impl</artifactId>
+            <version>1.0.5-SNAPSHOT</version>
+        </dependency>
+        <!--<dependency>-->
+            <!--<groupId>org.apache.geronimo.specs</groupId>-->
+            <!--<artifactId>geronimo-jsonb_1.0_spec</artifactId>-->
+            <!--<version>1.0</version>-->
+            <!--<scope>compile</scope>-->
+        <!--</dependency>-->
+        <!--<dependency>-->
+            <!--<groupId>org.apache.geronimo.specs</groupId>-->
+            <!--<artifactId>geronimo-json_1.1_spec</artifactId>-->
+            <!--<version>1.0</version>-->
+            <!--<scope>compile</scope>-->
+        <!--</dependency>-->
+        <!--<dependency>-->
+            <!--<groupId>org.apache.johnzon</groupId>-->
+            <!--<artifactId>johnzon-jsonb</artifactId>-->
+            <!--<version>${cxf.johnzon.version}</version>-->
+        <!--</dependency>-->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiEndpoint.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiEndpoint.java
new file mode 100644
index 0000000..6b82611
--- /dev/null
+++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiEndpoint.java
@@ -0,0 +1,43 @@
+/**
+ * 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.jaxrs.mpopenapi;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.geronimo.microprofile.openapi.jaxrs.OpenAPIEndpoint;
+import org.eclipse.microprofile.openapi.models.OpenAPI;
+
+@Path("/openapi.{type:json|yaml}")
+public class OpenApiEndpoint extends OpenAPIEndpoint {
+    private OpenAPI openApi;
+
+    public OpenApiEndpoint(OpenAPI openApi) {
+        this.openApi = openApi;
+    }
+
+    @Override
+    @GET
+    @Produces({MediaType.APPLICATION_JSON, "application/yaml"})
+    public OpenAPI get() {
+        return openApi;
+    }
+}
diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java
new file mode 100644
index 0000000..c65fd9b
--- /dev/null
+++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/OpenApiFeature.java
@@ -0,0 +1,474 @@
+/**
+ * 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.jaxrs.mpopenapi;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.ws.rs.core.Application;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.annotations.Provider;
+import org.apache.cxf.annotations.Provider.Scope;
+import org.apache.cxf.annotations.Provider.Type;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean;
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.jaxrs.model.ApplicationInfo;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.provider.ServerProviderFactory;
+import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiConfig;
+import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiSupport;
+import org.apache.geronimo.microprofile.openapi.config.GeronimoOpenAPIConfig;
+import org.apache.geronimo.microprofile.openapi.impl.model.ContactImpl;
+import org.apache.geronimo.microprofile.openapi.impl.model.InfoImpl;
+import org.apache.geronimo.microprofile.openapi.impl.model.LicenseImpl;
+import org.apache.geronimo.microprofile.openapi.impl.model.OpenAPIImpl;
+import org.apache.geronimo.microprofile.openapi.impl.processor.AnnotationProcessor;
+import org.apache.geronimo.microprofile.openapi.impl.processor.reflect.ClassElement;
+import org.apache.geronimo.microprofile.openapi.impl.processor.reflect.MethodElement;
+import org.apache.geronimo.microprofile.openapi.impl.processor.spi.NamingStrategy;
+import org.eclipse.microprofile.openapi.models.OpenAPI;
+
+
+@Provider(value = Type.Feature, scope = Scope.Server)
+public class OpenApiFeature extends AbstractFeature implements SwaggerUiSupport, SwaggerProperties {
+    private static final Logger LOG = LogUtils.getL7dLogger(OpenApiFeature.class);
+
+    private static final String DEFAULT_PROPS_LOCATION = "/swagger.properties";
+
+    private String version;
+    private String title;
+    private String description;
+    private String contactName;
+    private String contactEmail;
+    private String contactUrl;
+    private String license;
+    private String licenseUrl;
+    private String termsOfServiceUrl;
+    // Read all operations also with no @Operation
+    private boolean readAllResources = true; 
+    // Scan all JAX-RS resources automatically
+    private boolean scan = true;
+    private boolean prettyPrint = true;
+    private boolean runAsFilter;
+    private Collection<String> ignoredRoutes;
+    private Set<String> resourcePackages;
+    private Set<String> resourceClasses;
+    private String filterClass;
+
+    private Boolean supportSwaggerUi;
+    private String swaggerUiVersion;
+    private String swaggerUiMavenGroupAndArtifact;
+    private Map<String, String> swaggerUiMediaTypes;
+
+    // Allows to pass the configuration location, usually openapi-configuration.json
+    // or openapi-configuration.yml file.
+    private String configLocation;
+    // Allows to pass the properties location, by default swagger.properties
+    private String propertiesLocation = DEFAULT_PROPS_LOCATION;
+    // Allows to disable automatic scan of known configuration locations (enabled by default)
+    private boolean scanKnownConfigLocations = true;
+    // Swagger UI configuration parameters (to be passed as query string).
+    private SwaggerUiConfig swaggerUiConfig;
+
+    protected static class DefaultApplication extends Application {
+
+        private final Set<Class<?>> serviceClasses;
+
+        DefaultApplication(final List<ClassResourceInfo> cris, final Set<String> resourcePackages) {
+            this.serviceClasses = cris.stream().map(ClassResourceInfo::getServiceClass).
+                    filter(cls -> (resourcePackages == null || resourcePackages.isEmpty()) || resourcePackages.stream().
+                            anyMatch(pkg -> cls.getPackage().getName().startsWith(pkg))).collect(Collectors.toSet());
+        }
+
+        @Override
+        public Set<Class<?>> getClasses() {
+            return serviceClasses;
+        }
+    }
+
+    @Override
+    public void initialize(Server server, Bus bus) {
+        final JAXRSServiceFactoryBean sfb = (JAXRSServiceFactoryBean)server
+            .getEndpoint()
+            .get(JAXRSServiceFactoryBean.class.getName());
+
+        final ServerProviderFactory factory = (ServerProviderFactory)server
+            .getEndpoint()
+            .get(ServerProviderFactory.class.getName());
+
+        final Set<String> packages = new HashSet<>();
+        if (resourcePackages != null) {
+            packages.addAll(resourcePackages);
+        }
+
+        final Application application = getApplicationOrDefault(server, factory, sfb, bus);
+
+        final AnnotationProcessor processor = new AnnotationProcessor(GeronimoOpenAPIConfig.create(),
+                new NamingStrategy.Http());
+
+        final OpenAPIImpl api = new OpenAPIImpl();
+
+        if (isScan()) {
+            packages.addAll(scanResourcePackages(sfb));
+        }
+        if (application != null) {
+            processor.processApplication(api, new ClassElement(application.getClass()));
+            LOG.fine("Processed application " + application);
+        }
+        Set<Class<?>> endpointClasses = sfb
+                .getClassResourceInfo()
+                .stream()
+                .map(AbstractResourceInfo::getServiceClass)
+                .collect(Collectors.toSet());
+        if (!endpointClasses.isEmpty()) {
+            final String binding = application == null ? "" : processor.getApplicationBinding(application.getClass());
+            endpointClasses.stream()
+                    .peek(c -> LOG.info("Processing class " + c.getName()))
+                    .forEach(c -> processor.processClass(
+                            binding, api, new ClassElement(c),
+                            Stream.of(c.getMethods()).map(MethodElement::new)));
+        } else {
+            LOG.warning("No <endpointClasses> registered, your OpenAPI will be empty.");
+        }
+        Properties swaggerProps = getSwaggerProperties(propertiesLocation, bus);
+        if (api.getInfo() == null) {
+            api.setInfo(getInfo(swaggerProps));
+        }
+
+        registerOpenApiResources(sfb, api);
+        registerSwaggerUiResources(sfb, swaggerProps, factory, bus);
+    }
+
+    public boolean isScan() {
+        return scan;
+    }
+
+    public void setScan(boolean scan) {
+        this.scan = scan;
+    }
+
+    public String getFilterClass() {
+        return filterClass;
+    }
+
+    public void setFilterClass(String filterClass) {
+        this.filterClass = filterClass;
+    }
+    
+    public Set<String> getResourcePackages() {
+        return resourcePackages;
+    }
+    
+    public void setResourcePackages(Set<String> resourcePackages) {
+        this.resourcePackages = (resourcePackages == null) ? null : new HashSet<>(resourcePackages);
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getContactName() {
+        return contactName;
+    }
+
+    public void setContactName(String contactName) {
+        this.contactName = contactName;
+    }
+
+    public String getContactEmail() {
+        return contactEmail;
+    }
+
+    public void setContactEmail(String contactEmail) {
+        this.contactEmail = contactEmail;
+    }
+
+    public String getContactUrl() {
+        return contactUrl;
+    }
+
+    public void setContactUrl(String contactUrl) {
+        this.contactUrl = contactUrl;
+    }
+
+    public String getLicense() {
+        return license;
+    }
+
+    public void setLicense(String license) {
+        this.license = license;
+    }
+
+    public String getLicenseUrl() {
+        return licenseUrl;
+    }
+
+    public void setLicenseUrl(String licenseUrl) {
+        this.licenseUrl = licenseUrl;
+    }
+
+    public String getTermsOfServiceUrl() {
+        return termsOfServiceUrl;
+    }
+
+    public void setTermsOfServiceUrl(String termsOfServiceUrl) {
+        this.termsOfServiceUrl = termsOfServiceUrl;
+    }
+
+    public boolean isReadAllResources() {
+        return readAllResources;
+    }
+
+    public void setReadAllResources(boolean readAllResources) {
+        this.readAllResources = readAllResources;
+    }
+
+    public Set<String> getResourceClasses() {
+        return resourceClasses;
+    }
+
+    public void setResourceClasses(Set<String> resourceClasses) {
+        this.resourceClasses = (resourceClasses == null) ? null : new HashSet<>(resourceClasses);
+    }
+
+    public Collection<String> getIgnoredRoutes() {
+        return ignoredRoutes;
+    }
+
+    public void setIgnoredRoutes(Collection<String> ignoredRoutes) {
+        this.ignoredRoutes = (ignoredRoutes == null) ? null : new HashSet<>(ignoredRoutes);
+    }
+
+    public boolean isPrettyPrint() {
+        return prettyPrint;
+    }
+
+    public void setPrettyPrint(boolean prettyPrint) {
+        this.prettyPrint = prettyPrint;
+    }
+    
+    public boolean isRunAsFilter() {
+        return runAsFilter;
+    }
+    
+    @Override
+    public Boolean isSupportSwaggerUi() {
+        return supportSwaggerUi;
+    }
+
+    public void setSupportSwaggerUi(Boolean supportSwaggerUi) {
+        this.supportSwaggerUi = supportSwaggerUi;
+    }
+
+    public String getSwaggerUiVersion() {
+        return swaggerUiVersion;
+    }
+
+    public void setSwaggerUiVersion(String swaggerUiVersion) {
+        this.swaggerUiVersion = swaggerUiVersion;
+    }
+
+    public String getSwaggerUiMavenGroupAndArtifact() {
+        return swaggerUiMavenGroupAndArtifact;
+    }
+
+    public void setSwaggerUiMavenGroupAndArtifact(
+            String swaggerUiMavenGroupAndArtifact) {
+        this.swaggerUiMavenGroupAndArtifact = swaggerUiMavenGroupAndArtifact;
+    }
+
+    @Override
+    public Map<String, String> getSwaggerUiMediaTypes() {
+        return swaggerUiMediaTypes;
+    }
+
+    public void setSwaggerUiMediaTypes(Map<String, String> swaggerUiMediaTypes) {
+        this.swaggerUiMediaTypes = swaggerUiMediaTypes;
+    }
+
+    public String getConfigLocation() {
+        return configLocation;
+    }
+
+    public void setConfigLocation(String configLocation) {
+        this.configLocation = configLocation;
+    }
+
+    public String getPropertiesLocation() {
+        return propertiesLocation;
+    }
+
+    public void setPropertiesLocation(String propertiesLocation) {
+        this.propertiesLocation = propertiesLocation;
+    }
+
+    public void setRunAsFilter(boolean runAsFilter) {
+        this.runAsFilter = runAsFilter;
+    }
+
+    public void setScanKnownConfigLocations(boolean scanKnownConfigLocations) {
+        this.scanKnownConfigLocations = scanKnownConfigLocations;
+    }
+    
+    public boolean isScanKnownConfigLocations() {
+        return scanKnownConfigLocations;
+    }
+    
+    public void setSwaggerUiConfig(final SwaggerUiConfig swaggerUiConfig) {
+        this.swaggerUiConfig = swaggerUiConfig;
+    }
+    
+    @Override
+    public SwaggerUiConfig getSwaggerUiConfig() {
+        return swaggerUiConfig;
+    }
+
+    @Override
+    public String findSwaggerUiRoot() {
+        return SwaggerUi.findSwaggerUiRoot(swaggerUiMavenGroupAndArtifact, swaggerUiVersion);
+    }
+    
+    protected Properties getUserProperties(final Map<String, Object> userDefinedOptions) {
+        final Properties properties = new Properties();
+        
+        if (userDefinedOptions != null) {
+            userDefinedOptions
+                .entrySet()
+                .stream()
+                .filter(entry -> entry.getValue() != null)
+                .forEach(entry -> properties.setProperty(entry.getKey(), entry.getValue().toString()));
+        }
+        
+        return properties;
+    }
+
+    protected void registerOpenApiResources(
+            final JAXRSServiceFactoryBean sfb,
+            final OpenAPI openApiDefinition) {
+
+        sfb.setResourceClassesFromBeans(Collections.singletonList(new OpenApiEndpoint(openApiDefinition)));
+    }
+
+    protected void registerSwaggerUiResources(JAXRSServiceFactoryBean sfb, Properties properties,
+            ServerProviderFactory factory, Bus bus) {
+        
+        final Registration swaggerUiRegistration = getSwaggerUi(bus, properties, isRunAsFilter());
+        
+        if (!isRunAsFilter()) {
+            sfb.setResourceClassesFromBeans(swaggerUiRegistration.getResources());
+        } 
+
+        factory.setUserProviders(swaggerUiRegistration.getProviders());
+    }
+
+    /**
+     * Detects the application (if present) or creates the default application (in case the scan is disabled).
+     */
+    protected Application getApplicationOrDefault(
+            final Server server,
+            final ServerProviderFactory factory,
+            final JAXRSServiceFactoryBean sfb,
+            final Bus bus) {
+
+        ApplicationInfo appInfo = null;
+        if (!isScan()) {
+            appInfo = factory.getApplicationProvider();
+            
+            if (appInfo == null) {
+                appInfo = new ApplicationInfo(
+                        new DefaultApplication(sfb.getClassResourceInfo(), resourcePackages), bus);
+                server.getEndpoint().put(Application.class.getName(), appInfo);
+            }
+        }
+        
+        return (appInfo == null) ? null : appInfo.getProvider();
+    }
+
+    /**
+     * The info will be used only if there is no @OpenAPIDefinition annotation is present.
+     */
+    private org.eclipse.microprofile.openapi.models.info.Info getInfo(final Properties properties) {
+        org.eclipse.microprofile.openapi.models.info.Info info = new InfoImpl()
+            .title(getOrFallback(getTitle(), properties, TITLE_PROPERTY))
+            .version(getOrFallback(getVersion(), properties, VERSION_PROPERTY))
+            .description(getOrFallback(getDescription(), properties, DESCRIPTION_PROPERTY))
+            .termsOfService(getOrFallback(getTermsOfServiceUrl(), properties, TERMS_URL_PROPERTY))
+            .contact(new ContactImpl()
+                .name(getOrFallback(getContactName(), properties, CONTACT_PROPERTY))
+                .email(getContactEmail())
+                .url(getContactUrl()));
+
+        String licenseName = getOrFallback(getLicense(), properties, LICENSE_PROPERTY);
+        if (licenseName != null) {
+            info = info.license(new LicenseImpl()
+                    .name(getOrFallback(getLicense(), properties, LICENSE_PROPERTY))
+                    .url(getOrFallback(getLicenseUrl(), properties, LICENSE_URL_PROPERTY)));
+        }
+        return info;
+    }
+
+    private String getOrFallback(String value, Properties properties, String property) {
+        if (value == null && properties != null) {
+            return properties.getProperty(property);
+        } else {
+            return value;
+        }
+    }
+
+    private Collection<String> scanResourcePackages(JAXRSServiceFactoryBean sfb) {
+        return sfb
+            .getClassResourceInfo()
+            .stream()
+            .map(cri -> cri.getServiceClass().getPackage().getName())
+            .collect(Collectors.toSet());
+    }
+
+}
diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerProperties.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerProperties.java
new file mode 100644
index 0000000..c4b4c2a
--- /dev/null
+++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerProperties.java
@@ -0,0 +1,69 @@
+/**
+ * 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.jaxrs.mpopenapi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+
+interface SwaggerProperties {
+    String RESOURCE_PACKAGE_PROPERTY = "resource.package";
+    String TITLE_PROPERTY = "title";
+    String VERSION_PROPERTY = "version";
+    String DESCRIPTION_PROPERTY = "description";
+    String CONTACT_PROPERTY = "contact";
+    String LICENSE_PROPERTY = "license";
+    String LICENSE_URL_PROPERTY = "license.url";
+    String TERMS_URL_PROPERTY = "terms.url";
+    String PRETTY_PRINT_PROPERTY = "pretty.print";
+    String FILTER_CLASS_PROPERTY = "filter.class";
+    
+    /**
+     * Read the Swagger-specific properties from the property file (to seamlessly
+     * support the migration from older Swagger features).
+     * @param location property file location
+     * @param bus bus instance
+     * @return the properties if available 
+     */
+    default Properties getSwaggerProperties(String location, Bus bus) {
+        InputStream is = ResourceUtils.getClasspathResourceStream(location, SwaggerProperties.class, bus);
+        Properties props = null;
+        
+        if (is != null) {
+            props = new Properties();
+            try {
+                props.load(is);
+            } catch (IOException ex) {
+                props = null;
+            } finally {
+                try {
+                    is.close();
+                } catch (IOException ignore) {
+                    // ignore
+                }
+            }
+        }
+
+        return props;
+    }
+}
diff --git a/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java
new file mode 100644
index 0000000..f796dfb
--- /dev/null
+++ b/rt/rs/description-microprofile-openapi/src/main/java/org/apache/cxf/jaxrs/mpopenapi/SwaggerUi.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jaxrs.mpopenapi;
+
+import org.apache.cxf.jaxrs.swagger.ui.SwaggerUiResolver;
+
+/**
+ * SwaggerUI resolvers implementation for OpenAPI 
+ */
+public final class SwaggerUi {
+    private static final SwaggerUiResolver HELPER;
+    
+    static {
+        HELPER = new SwaggerUiResolver(OpenApiFeature.class.getClassLoader());
+    }
+
+    private SwaggerUi() {
+    }
+
+    public static String findSwaggerUiRoot(String swaggerUiMavenGroupAndArtifact, 
+                                           String swaggerUiVersion) {
+        String root = HELPER.findSwaggerUiRootInternal(swaggerUiMavenGroupAndArtifact, 
+                                                       swaggerUiVersion);
+        if (root == null && HELPER.getClass() != SwaggerUiResolver.class) {
+            root = new SwaggerUiResolver(OpenApiFeature.class.getClassLoader())
+                .findSwaggerUiRootInternal(swaggerUiMavenGroupAndArtifact, swaggerUiVersion);
+        }
+        return root;
+    }
+}
diff --git a/rt/rs/pom.xml b/rt/rs/pom.xml
index d711c9e..b3c6214 100644
--- a/rt/rs/pom.xml
+++ b/rt/rs/pom.xml
@@ -44,6 +44,7 @@
         <module>security</module>
         <module>sse</module>
         <module>description-openapi-v3</module>
+        <module>description-microprofile-openapi</module>
         <module>description-swagger-ui</module>
         <module>microprofile-client</module>
     </modules>