Skip to content

Commit 1fd4ce0

Browse files
committed
Add tag auto generation by controller class name or/and package name
1 parent ff300c7 commit 1fd4ce0

File tree

24 files changed

+1225
-187
lines changed

24 files changed

+1225
-187
lines changed

Diff for: build-logic/src/main/groovy/io/micronaut/build/internal/openapi/OpenApiGeneratorTask.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.nio.file.Files;
2020
import java.util.ArrayList;
21+
import java.util.Locale;
2122
import java.util.Map;
2223

2324
import javax.inject.Inject;
@@ -147,7 +148,7 @@ public void execute() throws IOException {
147148
args.add(String.join(",", getOutputKinds().get()));
148149
args.add(getParameterMappings().get().toString());
149150
args.add(getResponseBodyMappings().get().toString());
150-
args.add(lang.toUpperCase());
151+
args.add(lang.toUpperCase(Locale.ENGLISH));
151152
args.add(Boolean.toString(generatedAnnotation));
152153
args.add(Boolean.toString(getKsp().get()));
153154
args.add(Boolean.toString(getClientPath().get()));

Diff for: openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautJavaCodegen.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2098,7 +2098,7 @@ protected void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars,
20982098
if (argPos >= 0) {
20992099
value = value.substring(argPos + 1, value.indexOf(')'));
21002100
}
2101-
var upperValue = value.toUpperCase();
2101+
var upperValue = value.toUpperCase(Locale.ENGLISH);
21022102
if (upperValue.endsWith("F")
21032103
|| upperValue.endsWith("L")
21042104
|| upperValue.endsWith("D")) {

Diff for: openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2155,7 +2155,7 @@ protected void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars,
21552155
if (argPos >= 0) {
21562156
value = value.substring(argPos + 1, value.indexOf(')'));
21572157
}
2158-
var upperValue = value.toUpperCase();
2158+
var upperValue = value.toUpperCase(Locale.ENGLISH);
21592159
if (upperValue.endsWith("F")
21602160
|| upperValue.endsWith("L")
21612161
|| upperValue.endsWith("D")) {

Diff for: openapi-generator/src/main/java/io/micronaut/openapi/generator/Utils.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Collections;
3030
import java.util.HashSet;
3131
import java.util.List;
32+
import java.util.Locale;
3233
import java.util.Map;
3334
import java.util.Set;
3435

@@ -425,7 +426,7 @@ public static void addStrValueToEnum(List<Object> enumVars, boolean isNumeric) {
425426
if (argPos >= 0) {
426427
value = value.substring(argPos + 1, value.indexOf(')'));
427428
}
428-
var upperValue = value.toUpperCase();
429+
var upperValue = value.toUpperCase(Locale.ENGLISH);
429430
if (upperValue.endsWith("F")
430431
|| upperValue.endsWith("L")
431432
|| upperValue.endsWith("D")) {

Diff for: openapi/src/main/java/io/micronaut/openapi/visitor/AbstractOpenApiEndpointVisitor.java

+5-73
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
import io.swagger.v3.oas.annotations.enums.ParameterStyle;
7575
import io.swagger.v3.oas.annotations.extensions.Extension;
7676
import io.swagger.v3.oas.annotations.media.ExampleObject;
77-
import io.swagger.v3.oas.annotations.tags.Tags;
7877
import io.swagger.v3.oas.models.Components;
7978
import io.swagger.v3.oas.models.ExternalDocumentation;
8079
import io.swagger.v3.oas.models.OpenAPI;
@@ -103,7 +102,6 @@
103102
import java.util.ArrayList;
104103
import java.util.Collection;
105104
import java.util.Collections;
106-
import java.util.Comparator;
107105
import java.util.HashMap;
108106
import java.util.HashSet;
109107
import java.util.LinkedHashMap;
@@ -190,6 +188,8 @@
190188
import static io.micronaut.openapi.visitor.StringUtil.DOLLAR;
191189
import static io.micronaut.openapi.visitor.StringUtil.OPEN_BRACE;
192190
import static io.micronaut.openapi.visitor.StringUtil.THREE_DOTS;
191+
import static io.micronaut.openapi.visitor.TagUtils.generationTags;
192+
import static io.micronaut.openapi.visitor.TagUtils.readTags;
193193
import static io.micronaut.openapi.visitor.Utils.DEFAULT_MEDIA_TYPES;
194194
import static io.micronaut.openapi.visitor.Utils.getMediaType;
195195
import static io.micronaut.openapi.visitor.Utils.resolveWebhooks;
@@ -283,6 +283,9 @@ private void processTags(ClassElement element, VisitorContext context) {
283283
}
284284
}
285285
}
286+
if (CollectionUtils.isEmpty(classTags)) {
287+
classTags = generationTags(element, context);
288+
}
286289
}
287290

288291
private void processExternalDocs(ClassElement element, VisitorContext context) {
@@ -1982,13 +1985,6 @@ private Map<String, Callback> initCallbacks(Operation swaggerOperation) {
19821985
return callbacks;
19831986
}
19841987

1985-
private void addTagIfNotPresent(String tag, Operation swaggerOperation) {
1986-
List<String> tags = swaggerOperation.getTags();
1987-
if (tags == null || !tags.contains(tag)) {
1988-
swaggerOperation.addTagsItem(tag);
1989-
}
1990-
}
1991-
19921988
private void processMicronautVersionAndGroup(Operation swaggerOperation, String url,
19931989
HttpMethod httpMethod,
19941990
List<MediaType> consumesMediaTypes,
@@ -2141,70 +2137,6 @@ private void addVersionParameters(Operation swaggerOperation, List<String> names
21412137
}
21422138
}
21432139

2144-
private void readTags(MethodElement element, VisitorContext context, Operation swaggerOperation, List<Tag> classTags, OpenAPI openAPI) {
2145-
element.getAnnotationValuesByType(io.swagger.v3.oas.annotations.tags.Tag.class)
2146-
.forEach(av -> av.stringValue(PROP_NAME)
2147-
.ifPresent(swaggerOperation::addTagsItem));
2148-
2149-
var copyTags = openAPI.getTags() != null ? new ArrayList<>(openAPI.getTags()) : null;
2150-
var operationTags = processOpenApiAnnotation(element, context, io.swagger.v3.oas.annotations.tags.Tag.class, Tag.class, copyTags);
2151-
// find not simple tags (tags with description or other information), such fields need to be described at the openAPI level.
2152-
List<Tag> complexTags = null;
2153-
if (CollectionUtils.isNotEmpty(operationTags)) {
2154-
complexTags = new ArrayList<>();
2155-
for (Tag operationTag : operationTags) {
2156-
if (StringUtils.hasText(operationTag.getDescription())
2157-
|| CollectionUtils.isNotEmpty(operationTag.getExtensions())
2158-
|| operationTag.getExternalDocs() != null) {
2159-
complexTags.add(operationTag);
2160-
}
2161-
}
2162-
}
2163-
if (CollectionUtils.isNotEmpty(complexTags)) {
2164-
if (CollectionUtils.isEmpty(openAPI.getTags())) {
2165-
openAPI.setTags(complexTags);
2166-
} else {
2167-
for (Tag complexTag : complexTags) {
2168-
// skip all existed tags
2169-
boolean alreadyExists = false;
2170-
for (Tag apiTag : openAPI.getTags()) {
2171-
if (apiTag.getName().equals(complexTag.getName())) {
2172-
alreadyExists = true;
2173-
break;
2174-
}
2175-
}
2176-
if (!alreadyExists) {
2177-
openAPI.getTags().add(complexTag);
2178-
}
2179-
}
2180-
}
2181-
}
2182-
2183-
// only way to get inherited tags
2184-
element.getValues(Tags.class, AnnotationValue.class)
2185-
.forEach((k, v) -> v.stringValue(PROP_NAME).ifPresent(name -> addTagIfNotPresent((String) name, swaggerOperation)));
2186-
2187-
classTags.forEach(tag -> addTagIfNotPresent(tag.getName(), swaggerOperation));
2188-
if (CollectionUtils.isNotEmpty(swaggerOperation.getTags())) {
2189-
swaggerOperation.getTags().sort(Comparator.naturalOrder());
2190-
}
2191-
}
2192-
2193-
private List<Tag> readTags(ClassElement element, VisitorContext context) {
2194-
return readTags(element.getAnnotationValuesByType(io.swagger.v3.oas.annotations.tags.Tag.class), context);
2195-
}
2196-
2197-
final List<Tag> readTags(List<AnnotationValue<io.swagger.v3.oas.annotations.tags.Tag>> tagAnns, VisitorContext context) {
2198-
var tags = new ArrayList<Tag>();
2199-
for (var tagAnn : tagAnns) {
2200-
var tag = toValue(tagAnn.getAnnotationName(), tagAnn.getValues(), context, Tag.class, null);
2201-
if (tag != null) {
2202-
tags.add(tag);
2203-
}
2204-
}
2205-
return tags;
2206-
}
2207-
22082140
private Content buildContent(Element definingElement, ClassElement type, List<MediaType> mediaTypes, OpenAPI openAPI, VisitorContext context, @Nullable ClassElement jsonViewClass) {
22092141
var content = new Content();
22102142
for (var mediaType : mediaTypes) {

Diff for: openapi/src/main/java/io/micronaut/openapi/visitor/AbstractOpenApiVisitor.java

-60
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import io.micronaut.core.annotation.AnnotationValue;
1919
import io.micronaut.core.annotation.Internal;
20-
import io.micronaut.core.util.CollectionUtils;
2120
import io.micronaut.http.uri.UriMatchTemplate;
2221
import io.micronaut.inject.ast.ClassElement;
2322
import io.micronaut.inject.ast.Element;
@@ -28,21 +27,15 @@
2827
import io.swagger.v3.oas.models.PathItem;
2928
import io.swagger.v3.oas.models.Paths;
3029
import io.swagger.v3.oas.models.security.SecurityRequirement;
31-
import io.swagger.v3.oas.models.tags.Tag;
3230

33-
import java.lang.annotation.Annotation;
3431
import java.util.ArrayList;
35-
import java.util.Collections;
3632
import java.util.HashMap;
3733
import java.util.List;
3834
import java.util.Map;
3935
import java.util.concurrent.locks.Lock;
4036
import java.util.concurrent.locks.ReentrantLock;
4137

4238
import static io.micronaut.openapi.visitor.InternalExt.MICRONAUT_OP_POSTFIX;
43-
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_NAME;
44-
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_SCOPES;
45-
import static io.micronaut.openapi.visitor.SchemaDefinitionUtils.toValue;
4639
import static io.micronaut.openapi.visitor.UrlUtils.buildUrls;
4740
import static io.micronaut.openapi.visitor.UrlUtils.parsePathSegments;
4841

@@ -154,57 +147,4 @@ protected void processSecuritySchemes(ClassElement element, VisitorContext conte
154147
final OpenAPI openApi = Utils.resolveOpenApi(context);
155148
ConvertUtils.addSecuritySchemes(openApi, values, context);
156149
}
157-
158-
/**
159-
* Converts annotation to model.
160-
*
161-
* @param <T> The model type.
162-
* @param <A> The annotation type.
163-
* @param element The element to process.
164-
* @param context The context.
165-
* @param annotationType The annotation type.
166-
* @param modelType The model type.
167-
* @param tagList The initial list of models.
168-
*
169-
* @return A list of model objects.
170-
*/
171-
protected <T, A extends Annotation> List<T> processOpenApiAnnotation(Element element, VisitorContext context, Class<A> annotationType, Class<T> modelType, List<T> tagList) {
172-
List<AnnotationValue<A>> annotations = element.getAnnotationValuesByType(annotationType);
173-
if (CollectionUtils.isEmpty(tagList)) {
174-
tagList = new ArrayList<>();
175-
}
176-
if (CollectionUtils.isEmpty(annotations)) {
177-
return tagList;
178-
}
179-
for (AnnotationValue<A> tag : annotations) {
180-
Map<CharSequence, Object> values;
181-
var tagValues = tag.getValues();
182-
if (tag.getAnnotationName().equals(io.swagger.v3.oas.annotations.security.SecurityRequirement.class.getName())
183-
&& !tagValues.isEmpty()) {
184-
Object name = tagValues.get(PROP_NAME);
185-
Object scopes = tagValues.computeIfAbsent(PROP_SCOPES, (key) -> new ArrayList<String>());
186-
values = Collections.singletonMap((CharSequence) name, scopes);
187-
} else {
188-
values = tagValues;
189-
}
190-
T tagObj = toValue(tag.getAnnotationName(), values, context, modelType, null);
191-
if (tagObj != null) {
192-
// skip all existed tags
193-
boolean alreadyExists = false;
194-
if (CollectionUtils.isNotEmpty(tagList) && tag.getAnnotationName().equals(io.swagger.v3.oas.annotations.tags.Tag.class.getName())) {
195-
var newTagName = ((Tag) tagObj).getName();
196-
for (T existedTag : tagList) {
197-
if (((Tag) existedTag).getName().equals(newTagName)) {
198-
alreadyExists = true;
199-
break;
200-
}
201-
}
202-
}
203-
if (!alreadyExists) {
204-
tagList.add(tagObj);
205-
}
206-
}
207-
}
208-
return tagList;
209-
}
210150
}

0 commit comments

Comments
 (0)