Repository: cxf Updated Branches: refs/heads/3.1.x-fixes 65fe9815a -> e490f5c8f
[CXF-7316] Getting Swagger2Feature working with swagger-jaxrs 1.5.13, optional at the moment Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/e490f5c8 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/e490f5c8 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/e490f5c8 Branch: refs/heads/3.1.x-fixes Commit: e490f5c8f792a0d35829eaac392fdd1fd74a782e Parents: 65fe981 Author: Sergey Beryozkin <[email protected]> Authored: Wed May 10 10:50:42 2017 +0100 Committer: Sergey Beryozkin <[email protected]> Committed: Wed May 10 10:58:59 2017 +0100 ---------------------------------------------------------------------- .../swagger/DefaultSwagger2Serializers.java | 175 ++------------- .../swagger/Swagger2ApiListingResource.java | 47 ++++ .../cxf/jaxrs/swagger/Swagger2Customizer.java | 213 +++++++++++++++++++ .../cxf/jaxrs/swagger/Swagger2Feature.java | 37 +++- 4 files changed, 308 insertions(+), 164 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/e490f5c8/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/DefaultSwagger2Serializers.java ---------------------------------------------------------------------- diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/DefaultSwagger2Serializers.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/DefaultSwagger2Serializers.java index 18f5cda..5645a8c 100644 --- a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/DefaultSwagger2Serializers.java +++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/DefaultSwagger2Serializers.java @@ -23,211 +23,76 @@ import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.net.URL; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.cxf.jaxrs.ext.MessageContext; 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 io.swagger.jaxrs.config.BeanConfig; import io.swagger.jaxrs.listing.SwaggerSerializers; -import io.swagger.models.HttpMethod; -import io.swagger.models.Operation; -import io.swagger.models.Path; import io.swagger.models.Swagger; -import io.swagger.models.Tag; -import io.swagger.models.parameters.Parameter; public class DefaultSwagger2Serializers extends SwaggerSerializers implements Swagger2Serializers { - - protected boolean dynamicBasePath; - - protected boolean replaceTags; - - protected DocumentationProvider javadocProvider; - - protected List<ClassResourceInfo> cris; - - protected BeanConfig beanConfig; - + private Swagger2Customizer customizer = new Swagger2Customizer(); + @Override public void writeTo( - final Swagger data, + Swagger data, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap<String, Object> headers, final OutputStream out) throws IOException { - - if (dynamicBasePath) { - MessageContext ctx = createMessageContext(); - String currentBasePath = StringUtils.substringBeforeLast(ctx.getHttpServletRequest().getRequestURI(), "/"); - if (!currentBasePath.equals(beanConfig.getBasePath())) { - data.setBasePath(currentBasePath); - data.setHost(beanConfig.getHost()); - data.setInfo(beanConfig.getInfo()); - } - if (beanConfig.getSwagger() != null - && beanConfig.getSwagger().getSecurityDefinitions() != null - && data.getSecurityDefinitions() == null) { - data.setSecurityDefinitions(beanConfig.getSwagger().getSecurityDefinitions()); - } - } - - if (replaceTags || javadocProvider != null) { - Map<String, ClassResourceInfo> operations = new HashMap<>(); - Map<Pair<String, String>, OperationResourceInfo> methods = new HashMap<>(); - for (ClassResourceInfo cri : cris) { - for (OperationResourceInfo ori : cri.getMethodDispatcher().getOperationResourceInfos()) { - String normalizedPath = getNormalizedPath( - cri.getURITemplate().getValue(), ori.getURITemplate().getValue()); - - operations.put(normalizedPath, cri); - methods.put(ImmutablePair.of(ori.getHttpMethod(), normalizedPath), ori); - } - } - - if (replaceTags && data.getTags() != null) { - data.getTags().clear(); - } - for (final Map.Entry<String, Path> entry : data.getPaths().entrySet()) { - Tag tag = null; - if (replaceTags && operations.containsKey(entry.getKey())) { - ClassResourceInfo cri = operations.get(entry.getKey()); - - tag = new Tag(); - tag.setName(cri.getURITemplate().getValue().replaceAll("/", "_")); - if (javadocProvider != null) { - tag.setDescription(javadocProvider.getClassDoc(cri)); - } - - data.addTag(tag); - } - - for (Map.Entry<HttpMethod, Operation> subentry : entry.getValue().getOperationMap().entrySet()) { - if (replaceTags && tag != null) { - subentry.getValue().setTags(Collections.singletonList(tag.getName())); - } - - Pair<String, String> key = ImmutablePair.of(subentry.getKey().name(), entry.getKey()); - if (methods.containsKey(key) && javadocProvider != null) { - OperationResourceInfo ori = methods.get(key); - - subentry.getValue().setSummary(javadocProvider.getMethodDoc(ori)); - for (int i = 0; i < subentry.getValue().getParameters().size(); i++) { - subentry.getValue().getParameters().get(i). - setDescription(javadocProvider.getMethodParameterDoc(ori, i)); - } - addParameters(subentry.getValue().getParameters()); - - if (subentry.getValue().getResponses() != null - && !subentry.getValue().getResponses().isEmpty()) { - - subentry.getValue().getResponses().entrySet().iterator().next().getValue(). - setDescription(javadocProvider.getMethodResponseDoc(ori)); - } - } - } - } - } - if (replaceTags && data.getTags() != null) { - Collections.sort(data.getTags(), new Comparator<Tag>() { - - @Override - public int compare(final Tag tag1, final Tag tag2) { - return tag1.getName().compareTo(tag2.getName()); - } - }); - } - + data = customizer.customize(data); super.writeTo(data, type, genericType, annotations, mediaType, headers, out); } - private MessageContext createMessageContext() { - return JAXRSUtils.createContextValue( - JAXRSUtils.getCurrentMessage(), null, MessageContext.class); - } - - protected String getNormalizedPath(String classResourcePath, String operationResourcePath) { - StringBuilder normalizedPath = new StringBuilder(); - - String[] segments = StringUtils.split(classResourcePath + operationResourcePath, "/"); - for (String segment : segments) { - if (!StringUtils.isEmpty(segment)) { - normalizedPath.append("/").append(segment); - } - } - // Adapt to Swagger's path expression - if (normalizedPath.toString().endsWith(":.*}")) { - normalizedPath.setLength(normalizedPath.length() - 4); - normalizedPath.append('}'); - } - return StringUtils.EMPTY.equals(normalizedPath.toString()) ? "/" : normalizedPath.toString(); - } - - /** - * Allows to add parameters to the list, related to an {@link Operation} instance; the method is invoked - * for all instances available. - * - * @param parameters list of parameters defined for an {@link Operation} - * @see io.swagger.models.parameters.HeaderParameter - * @see io.swagger.models.parameters.CookieParameter - * @see io.swagger.models.parameters.PathParameter - * @see io.swagger.models.parameters.BodyParameter - * @see io.swagger.models.parameters.QueryParameter - * @see io.swagger.models.parameters.RefParameter - */ - protected void addParameters(final List<Parameter> parameters) { - // does nothing by default - } - @Override public void setDynamicBasePath(final boolean dynamicBasePath) { - this.dynamicBasePath = dynamicBasePath; + customizer.setDynamicBasePath(dynamicBasePath); } public void setReplaceTags(final boolean replaceTags) { - this.replaceTags = replaceTags; + customizer.setReplaceTags(replaceTags); } public void setJavadocProvider(final DocumentationProvider javadocProvider) { - this.javadocProvider = javadocProvider; + customizer.setJavadocProvider(javadocProvider); } @Override public void setClassResourceInfos(final List<ClassResourceInfo> classResourceInfos) { - this.cris = classResourceInfos; + customizer.setClassResourceInfos(classResourceInfos); } public void setJavaDocPath(final String javaDocPath) throws Exception { - this.javadocProvider = new JavaDocProvider(javaDocPath); + customizer.setJavadocProvider(new JavaDocProvider(javaDocPath)); } public void setJavaDocPaths(final String... javaDocPaths) throws Exception { - this.javadocProvider = new JavaDocProvider(javaDocPaths); + customizer.setJavadocProvider(new JavaDocProvider(javaDocPaths)); } public void setJavaDocURLs(final URL[] javaDocURLs) { - this.javadocProvider = new JavaDocProvider(javaDocURLs); + customizer.setJavadocProvider(new JavaDocProvider(javaDocURLs)); } @Override public void setBeanConfig(BeanConfig beanConfig) { - this.beanConfig = beanConfig; + customizer.setBeanConfig(beanConfig); + + } + + public Swagger2Customizer getCustomizer() { + return customizer; + } + public void setCustomizer(Swagger2Customizer customizer) { + this.customizer = customizer; } } http://git-wip-us.apache.org/repos/asf/cxf/blob/e490f5c8/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2ApiListingResource.java ---------------------------------------------------------------------- diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2ApiListingResource.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2ApiListingResource.java new file mode 100644 index 0000000..be3223e --- /dev/null +++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2ApiListingResource.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.swagger; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + +import io.swagger.jaxrs.listing.ApiListingResource; +import io.swagger.models.Swagger; + +public class Swagger2ApiListingResource extends ApiListingResource { + private Swagger2Customizer customizer; + public Swagger2ApiListingResource(Swagger2Customizer customizer) { + this.customizer = customizer; + } + @Override + protected Swagger process(Application app, + ServletContext servletContext, + ServletConfig sc, + HttpHeaders headers, + UriInfo uriInfo) { + Swagger s = super.process(app, servletContext, sc, headers, uriInfo); + if (customizer != null) { + s = customizer.customize(s); + } + return s; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/e490f5c8/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Customizer.java ---------------------------------------------------------------------- diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Customizer.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Customizer.java new file mode 100644 index 0000000..bbfc4b7 --- /dev/null +++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Customizer.java @@ -0,0 +1,213 @@ +/** + * 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.swagger; + +import java.net.URL; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.cxf.jaxrs.ext.MessageContext; +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 io.swagger.jaxrs.config.BeanConfig; +import io.swagger.models.HttpMethod; +import io.swagger.models.Operation; +import io.swagger.models.Path; +import io.swagger.models.Swagger; +import io.swagger.models.Tag; +import io.swagger.models.parameters.Parameter; + +public class Swagger2Customizer { + + protected boolean dynamicBasePath; + + protected boolean replaceTags; + + protected DocumentationProvider javadocProvider; + + protected List<ClassResourceInfo> cris; + + protected BeanConfig beanConfig; + + public Swagger customize(Swagger data) { + + if (dynamicBasePath) { + MessageContext ctx = createMessageContext(); + String currentBasePath = StringUtils.substringBeforeLast(ctx.getHttpServletRequest().getRequestURI(), "/"); + if (!currentBasePath.equals(beanConfig.getBasePath())) { + data.setBasePath(currentBasePath); + data.setHost(beanConfig.getHost()); + data.setInfo(beanConfig.getInfo()); + } + if (beanConfig.getSwagger() != null + && beanConfig.getSwagger().getSecurityDefinitions() != null + && data.getSecurityDefinitions() == null) { + data.setSecurityDefinitions(beanConfig.getSwagger().getSecurityDefinitions()); + } + } + + if (replaceTags || javadocProvider != null) { + Map<String, ClassResourceInfo> operations = new HashMap<>(); + Map<Pair<String, String>, OperationResourceInfo> methods = new HashMap<>(); + for (ClassResourceInfo cri : cris) { + for (OperationResourceInfo ori : cri.getMethodDispatcher().getOperationResourceInfos()) { + String normalizedPath = getNormalizedPath( + cri.getURITemplate().getValue(), ori.getURITemplate().getValue()); + + operations.put(normalizedPath, cri); + methods.put(ImmutablePair.of(ori.getHttpMethod(), normalizedPath), ori); + } + } + + if (replaceTags && data.getTags() != null) { + data.getTags().clear(); + } + for (final Map.Entry<String, Path> entry : data.getPaths().entrySet()) { + Tag tag = null; + if (replaceTags && operations.containsKey(entry.getKey())) { + ClassResourceInfo cri = operations.get(entry.getKey()); + + tag = new Tag(); + tag.setName(cri.getURITemplate().getValue().replaceAll("/", "_")); + if (javadocProvider != null) { + tag.setDescription(javadocProvider.getClassDoc(cri)); + } + + data.addTag(tag); + } + + for (Map.Entry<HttpMethod, Operation> subentry : entry.getValue().getOperationMap().entrySet()) { + if (replaceTags && tag != null) { + subentry.getValue().setTags(Collections.singletonList(tag.getName())); + } + + Pair<String, String> key = ImmutablePair.of(subentry.getKey().name(), entry.getKey()); + if (methods.containsKey(key) && javadocProvider != null) { + OperationResourceInfo ori = methods.get(key); + + subentry.getValue().setSummary(javadocProvider.getMethodDoc(ori)); + for (int i = 0; i < subentry.getValue().getParameters().size(); i++) { + subentry.getValue().getParameters().get(i). + setDescription(javadocProvider.getMethodParameterDoc(ori, i)); + } + addParameters(subentry.getValue().getParameters()); + + if (subentry.getValue().getResponses() != null + && !subentry.getValue().getResponses().isEmpty()) { + + subentry.getValue().getResponses().entrySet().iterator().next().getValue(). + setDescription(javadocProvider.getMethodResponseDoc(ori)); + } + } + } + } + } + if (replaceTags && data.getTags() != null) { + Collections.sort(data.getTags(), new Comparator<Tag>() { + + @Override + public int compare(final Tag tag1, final Tag tag2) { + return tag1.getName().compareTo(tag2.getName()); + } + }); + } + return data; + } + + private MessageContext createMessageContext() { + return JAXRSUtils.createContextValue( + JAXRSUtils.getCurrentMessage(), null, MessageContext.class); + } + + protected String getNormalizedPath(String classResourcePath, String operationResourcePath) { + StringBuilder normalizedPath = new StringBuilder(); + + String[] segments = StringUtils.split(classResourcePath + operationResourcePath, "/"); + for (String segment : segments) { + if (!StringUtils.isEmpty(segment)) { + normalizedPath.append("/").append(segment); + } + } + // Adapt to Swagger's path expression + if (normalizedPath.toString().endsWith(":.*}")) { + normalizedPath.setLength(normalizedPath.length() - 4); + normalizedPath.append('}'); + } + return StringUtils.EMPTY.equals(normalizedPath.toString()) ? "/" : normalizedPath.toString(); + } + + /** + * Allows to add parameters to the list, related to an {@link Operation} instance; the method is invoked + * for all instances available. + * + * @param parameters list of parameters defined for an {@link Operation} + * @see io.swagger.models.parameters.HeaderParameter + * @see io.swagger.models.parameters.CookieParameter + * @see io.swagger.models.parameters.PathParameter + * @see io.swagger.models.parameters.BodyParameter + * @see io.swagger.models.parameters.QueryParameter + * @see io.swagger.models.parameters.RefParameter + */ + protected void addParameters(final List<Parameter> parameters) { + // does nothing by default + } + + public void setDynamicBasePath(final boolean dynamicBasePath) { + this.dynamicBasePath = dynamicBasePath; + } + + public void setReplaceTags(final boolean replaceTags) { + this.replaceTags = replaceTags; + } + + public void setJavadocProvider(final DocumentationProvider javadocProvider) { + this.javadocProvider = javadocProvider; + } + + public void setClassResourceInfos(final List<ClassResourceInfo> classResourceInfos) { + this.cris = classResourceInfos; + } + + public void setJavaDocPath(final String javaDocPath) throws Exception { + this.javadocProvider = new JavaDocProvider(javaDocPath); + } + + public void setJavaDocPaths(final String... javaDocPaths) throws Exception { + this.javadocProvider = new JavaDocProvider(javaDocPaths); + } + + public void setJavaDocURLs(final URL[] javaDocURLs) { + this.javadocProvider = new JavaDocProvider(javaDocURLs); + } + + public void setBeanConfig(BeanConfig beanConfig) { + this.beanConfig = beanConfig; + + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/e490f5c8/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java ---------------------------------------------------------------------- diff --git a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java index 5d87e45..7fc087d 100644 --- a/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java +++ b/rt/rs/description-swagger/src/main/java/org/apache/cxf/jaxrs/swagger/Swagger2Feature.java @@ -74,6 +74,7 @@ import io.swagger.models.auth.SecuritySchemeDefinition; @Provider(value = Type.Feature, scope = Scope.Server) public class Swagger2Feature extends AbstractSwaggerFeature { + private String host; private String[] schemes; @@ -100,6 +101,8 @@ public class Swagger2Feature extends AbstractSwaggerFeature { private Map<String, SecuritySchemeDefinition> securityDefinitions; + private Swagger2Customizer customizer; + @Override protected void calculateDefaultBasePath(Server server) { dynamicBasePath = true; @@ -127,7 +130,7 @@ public class Swagger2Feature extends AbstractSwaggerFeature { } List<Object> swaggerResources = new LinkedList<>(); - ApiListingResource apiListingResource = new ApiListingResource(); + ApiListingResource apiListingResource = new Swagger2ApiListingResource(customizer); swaggerResources.add(apiListingResource); List<Object> providers = new ArrayList<>(); @@ -161,14 +164,17 @@ public class Swagger2Feature extends AbstractSwaggerFeature { } } } - - if (swagger2Serializers == null) { - swagger2Serializers = new DefaultSwagger2Serializers(); + if (customizer == null) { + if (swagger2Serializers == null) { + swagger2Serializers = new DefaultSwagger2Serializers(); + } + swagger2Serializers.setClassResourceInfos(cris); + swagger2Serializers.setDynamicBasePath(dynamicBasePath); + providers.add(swagger2Serializers); + } else { + customizer.setClassResourceInfos(cris); + customizer.setDynamicBasePath(dynamicBasePath); } - swagger2Serializers.setClassResourceInfos(cris); - swagger2Serializers.setDynamicBasePath(dynamicBasePath); - - providers.add(swagger2Serializers); providers.add(new ReaderConfigFilter()); @@ -204,6 +210,12 @@ public class Swagger2Feature extends AbstractSwaggerFeature { } swagger2Serializers.setBeanConfig(beanConfig); + + if (customizer == null) { + swagger2Serializers.setBeanConfig(beanConfig); + } else { + customizer.setBeanConfig(beanConfig); + } } public boolean isUsePathBasedConfig() { @@ -225,6 +237,14 @@ public class Swagger2Feature extends AbstractSwaggerFeature { public String[] getSchemes() { return schemes; } + + public Swagger2Customizer getCustomizer() { + return customizer; + } + + public void setCustomizer(Swagger2Customizer customizer) { + this.customizer = customizer; + } public void setSchemes(String[] schemes) { this.schemes = schemes; @@ -502,5 +522,4 @@ public class Swagger2Feature extends AbstractSwaggerFeature { return serviceClasses; } } - }
