diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/filter/SpecFilter.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/filter/SpecFilter.java index 5ca25e108f..846675db9b 100755 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/filter/SpecFilter.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/filter/SpecFilter.java @@ -53,8 +53,7 @@ public OpenAPI filter(OpenAPI openAPI, OpenAPISpecFilter filter, Map(openAPI.getTags())); - final Set allowedTags = new HashSet<>(); - final Set filteredTags = new HashSet<>(); + final TagFilter tagFilter = new TagFilter(); Paths clonedPaths = new Paths(); if (filteredOpenAPI.getPaths() != null) { @@ -62,7 +61,7 @@ public OpenAPI filter(OpenAPI openAPI, OpenAPISpecFilter filter, Map tags = clone.getTags(); - if (tags != null && !filteredTags.isEmpty()) { - tags.removeIf(tag -> filteredTags.contains(tag.getName())); - if (clone.getTags().isEmpty()) { - clone.setTags(null); - } - } + filterTopLevelTags(clone, tagFilter); if (filteredOpenAPI.getWebhooks() != null) { for (String resourcePath : filteredOpenAPI.getWebhooks().keySet()) { PathItem pathItem = filteredOpenAPI.getWebhooks().get(resourcePath); PathItem filteredPathItem = filterPathItem(filter, pathItem, resourcePath, params, cookies, headers); - PathItem clonedPathItem = cloneFilteredPathItem(filter,filteredPathItem, resourcePath, params, cookies, headers, allowedTags, filteredTags); + PathItem clonedPathItem = cloneFilteredPathItem(filter, filteredPathItem, resourcePath, params, cookies, headers, tagFilter); if (clonedPathItem != null) { if (!clonedPathItem.readOperations().isEmpty()) { @@ -271,7 +262,7 @@ protected Map filterComponentsSchema(OpenAPISpecFilter filter, M try { // TODO solve this, and generally handle clone and passing references Schema clonedModel; - if (filter.isOpenAPI31Filter()) { + if (filter.isOpenAPI31Filter()) { clonedModel = Json31.mapper().readValue(Json31.pretty(definition), Schema.class); } else { clonedModel = Json.mapper().readValue(Json.pretty(definition), Schema.class); @@ -282,10 +273,10 @@ protected Map filterComponentsSchema(OpenAPISpecFilter filter, M if (!clonedProperties.isEmpty()) { clonedModel.setProperties(clonedProperties); } - if(clonedModel.getPatternProperties() != null) { + if (clonedModel.getPatternProperties() != null) { clonedModel.getPatternProperties().clear(); } - if(!clonedPatternProperties.isEmpty()) { + if (!clonedPatternProperties.isEmpty()) { clonedModel.setPatternProperties(clonedPatternProperties); } clonedComponentsSchema.put(key, clonedModel); @@ -307,7 +298,7 @@ private void addSchemaRef(Schema schema, Set referencedDefinitions) { return; } if (schema.getDiscriminator() != null && schema.getDiscriminator().getMapping() != null) { - for (Map.Entry mapping: schema.getDiscriminator().getMapping().entrySet()) { + for (Map.Entry mapping : schema.getDiscriminator().getMapping().entrySet()) { referencedDefinitions.add(mapping.getValue()); } } @@ -320,7 +311,7 @@ private void addSchemaRef(Schema schema, Set referencedDefinitions) { } if (schema.getAdditionalProperties() instanceof Schema) { - addSchemaRef((Schema)schema.getAdditionalProperties(), referencedDefinitions); + addSchemaRef((Schema) schema.getAdditionalProperties(), referencedDefinitions); } if (schema.getPatternProperties() != null) { @@ -334,8 +325,7 @@ private void addSchemaRef(Schema schema, Set referencedDefinitions) { addSchemaRef(schema.getPropertyNames(), referencedDefinitions); } - if (schema instanceof ArraySchema && - ((ArraySchema) schema).getItems() != null) { + if (schema instanceof ArraySchema && ((ArraySchema) schema).getItems() != null) { addSchemaRef(((ArraySchema) schema).getItems(), referencedDefinitions); } else if (schema.getTypes() != null && schema.getTypes().contains("array") && schema.getItems() != null) { addSchemaRef(schema.getItems(), referencedDefinitions); @@ -413,7 +403,7 @@ private void addApiResponseSchemaRef(ApiResponse response, Set reference } private void addRequestBodySchemaRef(RequestBody requestBody, Set referencedDefinitions) { - addContentSchemaRef(requestBody.getContent(), referencedDefinitions); + addContentSchemaRef(requestBody.getContent(), referencedDefinitions); } private void addParameterSchemaRef(Parameter parameter, Set referencedDefinitions) { @@ -426,46 +416,46 @@ private void addHeaderSchemaRef(Header header, Set referencedDefinitions addContentSchemaRef(header.getContent(), referencedDefinitions); } - private void addCallbackSchemaRef(Callback callback, Set referencedDefinitions){ + private void addCallbackSchemaRef(Callback callback, Set referencedDefinitions) { for (PathItem callbackPathItem : callback.values()) { addPathItemSchemaRef(callbackPathItem, referencedDefinitions); } } - private void addComponentsSchemaRef(Components components, Set referencedDefinitions){ + private void addComponentsSchemaRef(Components components, Set referencedDefinitions) { - if (components.getResponses() != null){ + if (components.getResponses() != null) { for (String resourcePath : components.getResponses().keySet()) { ApiResponse apiResponse = components.getResponses().get(resourcePath); addApiResponseSchemaRef(apiResponse, referencedDefinitions); } } - if (components.getRequestBodies() != null){ + if (components.getRequestBodies() != null) { for (String requestBody : components.getRequestBodies().keySet()) { RequestBody requestBody1 = components.getRequestBodies().get(requestBody); addRequestBodySchemaRef(requestBody1, referencedDefinitions); } } - if (components.getParameters() != null){ + if (components.getParameters() != null) { for (String parameter : components.getParameters().keySet()) { Parameter resourceParam = components.getParameters().get(parameter); addParameterSchemaRef(resourceParam, referencedDefinitions); } } - if (components.getHeaders() != null){ + if (components.getHeaders() != null) { for (String header : components.getHeaders().keySet()) { Header resourceHeader = components.getHeaders().get(header); addHeaderSchemaRef(resourceHeader, referencedDefinitions); } } - if (components.getCallbacks() != null){ - for (String callback : components.getCallbacks().keySet()){ + if (components.getCallbacks() != null) { + for (String callback : components.getCallbacks().keySet()) { Callback resourceCallback = components.getCallbacks().get(callback); addCallbackSchemaRef(resourceCallback, referencedDefinitions); } } - if (components.getPathItems() != null){ - for (String resourcePath : components.getPathItems().keySet()){ + if (components.getPathItems() != null) { + for (String resourcePath : components.getPathItems().keySet()) { PathItem pathItem = components.getPathItems().get(resourcePath); addPathItemSchemaRef(pathItem, referencedDefinitions); } @@ -484,13 +474,13 @@ protected OpenAPI removeBrokenReferenceDefinitions(OpenAPI openApi) { addPathItemSchemaRef(pathItem, referencedDefinitions); } } - if (openApi.getWebhooks() != null){ + if (openApi.getWebhooks() != null) { for (String resourcePath : openApi.getWebhooks().keySet()) { PathItem pathItem = openApi.getWebhooks().get(resourcePath); addPathItemSchemaRef(pathItem, referencedDefinitions); } } - if (openApi.getComponents() != null){ + if (openApi.getComponents() != null) { Components components = openApi.getComponents(); addComponentsSchemaRef(components, referencedDefinitions); } @@ -530,7 +520,13 @@ protected void locateReferencedDefinitions(String ref, Set nestedReferen } } - private PathItem cloneFilteredPathItem(OpenAPISpecFilter filter, PathItem filteredPathItem, String resourcePath, Map> params, Map cookies, Map> headers, Set allowedTags, Set filteredTags) { + private PathItem cloneFilteredPathItem(OpenAPISpecFilter filter, + PathItem filteredPathItem, + String resourcePath, + Map> params, + Map cookies, + Map> headers, + TagFilter tagFilter) { if (filteredPathItem == null) { return null; } @@ -556,15 +552,48 @@ private PathItem cloneFilteredPathItem(OpenAPISpecFilter filter, PathItem filter op = filterOperation(filter, op, resourcePath, key.toString(), params, cookies, headers); clonedPathItem.operation(key, op); if (op == null) { - filteredTags.addAll(opTagsBeforeFilter); + tagFilter.getFilteredTags().addAll(opTagsBeforeFilter); } else { if (op.getTags() != null) { opTagsBeforeFilter.removeAll(op.getTags()); - allowedTags.addAll(op.getTags()); + tagFilter.getAllowedTags().addAll(op.getTags()); } - filteredTags.addAll(opTagsBeforeFilter); + tagFilter.getFilteredTags().addAll(opTagsBeforeFilter); } } return clonedPathItem; } + + /** + * Removes top level tags that are not used in any operation. + * + * @param openAPI the OpenAPI object to filter + * @param tagFilter the TagFilter object containing allowed and filtered tags + */ + private void filterTopLevelTags(OpenAPI openAPI, TagFilter tagFilter) { + tagFilter.getFilteredTags().removeAll(tagFilter.getAllowedTags()); + + final List tags = openAPI.getTags(); + if (tags != null && !tagFilter.getFilteredTags().isEmpty()) { + tags.removeIf(tag -> tagFilter.getFilteredTags().contains(tag.getName())); + if (openAPI.getTags().isEmpty()) { + openAPI.setTags(null); + } + } + } + + private static class TagFilter { + + public Set getAllowedTags() { + return allowedTags; + } + + public Set getFilteredTags() { + return filteredTags; + } + + private final Set allowedTags = new HashSet<>(); + private final Set filteredTags = new HashSet<>(); + + } }