diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41ba6e3c9..81c356a35 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [2.8.5] - 2025-02-16
+
+### Added
+- #2696 - Do not require JsonSubType annotation for sealed classes
+- #2898 - add needed runtime reflection hints for native image
+- #2891 - Refactor trimIndent Method
+
+### Changed
+- Upgrade swagger-ui to v5.18.3
+
+### Fixed
+- #2902 - Schema replaced by String when using @ApiResponse with RepresentationModel (Hateoas links)
+- #2876 - Restentpoints with same name get mix up
+- #2895 - Only filter out actuator endpoints with double asterisks.
+- #2894 - respect @JsonUnwrapped & @Schema on props not fields only
+- #2881 - fix defaultValue when using @PageableDefault together with one-indexed-parameters
+- #2888 - Provide a better consistency for parameters and responses order.
+
## [2.8.4] - 2025-01-25
### Added
diff --git a/README.md b/README.md
index 180f3d560..5b3618093 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,9 @@ This project is sponsored by
+
+
+
# Table of Contents
diff --git a/pom.xml b/pom.xml
index 5f72a3e70..dcda74974 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
org.springdoc
springdoc-openapi
- 2.8.4
+ 2.8.5
pom
Spring openapi documentation
Spring openapi documentation
@@ -35,7 +35,7 @@
scm:git:git@github.com:springdoc/springdoc-openapi.git
scm:git:git@github.com:springdoc/springdoc-openapi.git
- v2.8.4
+ v2.8.5
@@ -61,7 +61,7 @@
2.5.3
1.6.8
2.2.28
- 5.18.2
+ 5.18.3
1.13.1
0.9.1
0.15.0
diff --git a/springdoc-openapi-starter-common/pom.xml b/springdoc-openapi-starter-common/pom.xml
index b3bdef137..93483b2ac 100644
--- a/springdoc-openapi-starter-common/pom.xml
+++ b/springdoc-openapi-starter-common/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi
- 2.8.4
+ 2.8.5
springdoc-openapi-starter-common
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java
index 7c97a5e4c..948a0e667 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java
@@ -661,8 +661,7 @@ protected void calculatePath(HandlerMethod handlerMethod, RouterOperation router
}
PathItem pathItemObject = buildPathItem(requestMethod, operation, operationPath, paths);
- if (!StringUtils.contains(operationPath, "**"))
- paths.addPathItem(operationPath, pathItemObject);
+ paths.addPathItem(operationPath, pathItemObject);
}
}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java
index 4c39763c9..58c7ad34d 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java
@@ -126,6 +126,7 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.DeferredResult;
+import static org.springdoc.core.utils.Constants.GLOBAL_OPEN_API_CUSTOMIZER;
import static org.springdoc.core.utils.Constants.SPRINGDOC_DEPRECATING_CONVERTER_ENABLED;
import static org.springdoc.core.utils.Constants.SPRINGDOC_ENABLED;
import static org.springdoc.core.utils.Constants.SPRINGDOC_POLYMORPHIC_CONVERTER_ENABLED;
@@ -423,7 +424,7 @@ SpringDocProviders springDocProviders(Optional actuatorProvide
Optional repositoryRestResourceProvider, Optional routerFunctionProvider,
Optional springWebProvider,
ObjectMapperProvider objectMapperProvider) {
- objectMapperProvider.jsonMapper().registerModule(new SpringDocRequiredModule());
+ objectMapperProvider.jsonMapper().registerModules(new SpringDocRequiredModule(), new SpringDocSealedClassModule());
return new SpringDocProviders(actuatorProvider, springCloudFunctionProvider, springSecurityOAuth2Provider, repositoryRestResourceProvider, routerFunctionProvider, springWebProvider, objectMapperProvider);
}
@@ -654,7 +655,7 @@ ParameterObjectNamingStrategyCustomizer parameterObjectNamingStrategyCustomizer(
* @return the global open api customizer
*/
@Bean
- @ConditionalOnMissingBean
+ @ConditionalOnMissingBean(name = GLOBAL_OPEN_API_CUSTOMIZER)
@Lazy(false)
GlobalOpenApiCustomizer globalOpenApiCustomizer() {
return new OperationIdCustomizer();
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java
index 5c35852ba..17fb5c28a 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java
@@ -101,8 +101,8 @@ CollectionModelContentConverter collectionModelContentConverter(HateoasHalProvid
* @return the open api customizer
* @see org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider) org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize(Links, JsonGenerator, SerializerProvider)
*/
- @Bean(Constants.LINKS_SCHEMA_CUSTOMISER)
- @ConditionalOnMissingBean(name = Constants.LINKS_SCHEMA_CUSTOMISER)
+ @Bean(Constants.LINKS_SCHEMA_CUSTOMIZER)
+ @ConditionalOnMissingBean(name = Constants.LINKS_SCHEMA_CUSTOMIZER)
@Lazy(false)
GlobalOpenApiCustomizer linksSchemaCustomizer(HateoasHalProvider halProvider, SpringDocConfigProperties springDocConfigProperties) {
if (!halProvider.isHalEnabled()) {
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSealedClassModule.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSealedClassModule.java
new file mode 100644
index 000000000..d0b27ad81
--- /dev/null
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocSealedClassModule.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * *
+ * * *
+ * * * * Copyright 2025 the original author or authors.
+ * * * *
+ * * * * Licensed 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
+ * * * *
+ * * * * https://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.springdoc.core.configuration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.introspect.Annotated;
+import com.fasterxml.jackson.databind.jsontype.NamedType;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import io.swagger.v3.core.jackson.SwaggerAnnotationIntrospector;
+
+/**
+ * The type Spring doc sealed class module.
+ *
+ * @author sahil-ramagiri
+ */
+public class SpringDocSealedClassModule extends SimpleModule {
+
+ @Override
+ public void setupModule(SetupContext context) {
+ context.insertAnnotationIntrospector(new RespectSealedClassAnnotationIntrospector());
+ }
+
+ /**
+ * The type sealed class annotation introspector.
+ */
+ private static class RespectSealedClassAnnotationIntrospector extends SwaggerAnnotationIntrospector {
+
+ @Override
+ public List findSubtypes(Annotated annotated) {
+ ArrayList subTypes = new ArrayList<>();
+
+ if (annotated.getAnnotated() instanceof Class> clazz
+ && clazz.isSealed()
+ && !clazz.getPackage().getName().startsWith("java")
+ ) {
+ Class>[] permittedSubClasses = clazz.getPermittedSubclasses();
+ if (permittedSubClasses.length > 0) {
+ Arrays.stream(permittedSubClasses).map(NamedType::new).forEach(subTypes::add);
+ }
+ }
+
+ return subTypes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/hints/SpringDocHints.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/hints/SpringDocHints.java
index 37e457135..dad4e1b11 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/hints/SpringDocHints.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/hints/SpringDocHints.java
@@ -113,6 +113,7 @@ public class SpringDocHints implements RuntimeHintsRegistrar {
io.swagger.v3.oas.models.media.Schema.class,
io.swagger.v3.oas.models.media.Content.class,
io.swagger.v3.oas.models.media.ArraySchema.class,
+ io.swagger.v3.oas.models.media.JsonSchema.class,
io.swagger.v3.oas.models.responses.ApiResponse.class,
io.swagger.v3.oas.models.responses.ApiResponses.class,
io.swagger.v3.oas.models.ExternalDocumentation.class,
@@ -122,6 +123,7 @@ public class SpringDocHints implements RuntimeHintsRegistrar {
io.swagger.v3.oas.models.Operation.class,
io.swagger.v3.oas.models.headers.Header.class,
ModelConverter.class,
+ io.swagger.v3.core.converter.ModelConverterContextImpl.class,
ModelConverters.class,
SpecFilter.class,
MediaType.class,
@@ -166,6 +168,7 @@ public class SpringDocHints implements RuntimeHintsRegistrar {
MediaTypeMixin.class,
//oas 3.1
Schema31Mixin.class,
+ Schema31Mixin.TypeSerializer.class,
Components31Mixin.class,
OpenAPI31Mixin.class,
Discriminator31Mixin.class,
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/HateoasLinksConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/HateoasLinksConverter.java
index 7fbfa420b..bcde9140c 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/HateoasLinksConverter.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/HateoasLinksConverter.java
@@ -28,6 +28,7 @@
import java.util.Iterator;
+import java.util.Optional;
import com.fasterxml.jackson.databind.JavaType;
import io.swagger.v3.core.converter.ModelConverter;
@@ -43,7 +44,7 @@
/**
* The type Hateoas links converter.
- *
+ *
* @author bnasslahsen
*/
public class HateoasLinksConverter implements ModelConverter {
@@ -70,19 +71,30 @@ public Schema> resolve(
) {
JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType());
if (javaType != null && RepresentationModel.class.isAssignableFrom(javaType.getRawClass())) {
- Schema> schema = chain.next().resolve(type, context, chain);
- String schemaName = schema.get$ref().substring(Components.COMPONENTS_SCHEMAS_REF.length());
- Schema original = context.getDefinedModels().get(schemaName);
- Object links = original.getProperties().get("_links");
- if(links instanceof JsonSchema jsonSchema) {
- jsonSchema.set$ref(AnnotationsUtils.COMPONENTS_REF + "Links");
- jsonSchema.setType(null);
- jsonSchema.setItems(null);
- jsonSchema.setTypes(null);
- } else if (links instanceof ArraySchema arraySchema){
- arraySchema.set$ref(AnnotationsUtils.COMPONENTS_REF + "Links");
+ Schema> schema = chain.next().resolve(type, context, chain);
+ if (schema != null) {
+ String schemaName = Optional.ofNullable(schema.get$ref())
+ .filter(ref -> ref.startsWith(Components.COMPONENTS_SCHEMAS_REF))
+ .map(ref -> ref.substring(Components.COMPONENTS_SCHEMAS_REF.length()))
+ .orElse(schema.getName());
+ if(schemaName != null) {
+ Schema original = context.getDefinedModels().get(schemaName);
+ if (original == null || original.getProperties() == null) {
+ return schema;
+ }
+ Object links = original.getProperties().get("_links");
+ if (links instanceof JsonSchema jsonSchema) {
+ jsonSchema.set$ref(AnnotationsUtils.COMPONENTS_REF + "Links");
+ jsonSchema.setType(null);
+ jsonSchema.setItems(null);
+ jsonSchema.setTypes(null);
+ }
+ else if (links instanceof ArraySchema arraySchema) {
+ arraySchema.set$ref(AnnotationsUtils.COMPONENTS_REF + "Links");
+ }
}
- return schema;
+ }
+ return schema;
}
return chain.hasNext() ? chain.next().resolve(type, context, chain) : null;
}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java
index 8cdbd65a6..9a940d349 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PolymorphicModelConverter.java
@@ -37,7 +37,9 @@
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverterContext;
@@ -120,17 +122,28 @@ else if (resolvedSchema.getProperties().containsKey(javaType.getRawClass().getSi
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) {
JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType());
if (javaType != null) {
- for (Field field : FieldUtils.getAllFields(javaType.getRawClass())) {
- if (field.isAnnotationPresent(JsonUnwrapped.class)) {
+ BeanDescription javaTypeIntrospection = springDocObjectMapper.jsonMapper().getDeserializationConfig().introspect(javaType);
+ for (BeanPropertyDefinition property : javaTypeIntrospection.findProperties()) {
+ boolean isUnwrapped = (property.getField() != null && property.getField().hasAnnotation(JsonUnwrapped.class)) ||
+ (property.getGetter() != null && property.getGetter().hasAnnotation(JsonUnwrapped.class));
+
+ if (isUnwrapped) {
if (!TypeNameResolver.std.getUseFqn())
PARENT_TYPES_TO_IGNORE.add(javaType.getRawClass().getSimpleName());
else
PARENT_TYPES_TO_IGNORE.add(javaType.getRawClass().getName());
}
- else if (field.isAnnotationPresent(io.swagger.v3.oas.annotations.media.Schema.class)) {
- io.swagger.v3.oas.annotations.media.Schema declaredSchema = field.getDeclaredAnnotation(io.swagger.v3.oas.annotations.media.Schema.class);
- if (ArrayUtils.isNotEmpty(declaredSchema.oneOf()) || ArrayUtils.isNotEmpty(declaredSchema.allOf())) {
- TYPES_TO_SKIP.add(field.getType().getSimpleName());
+ else {
+ io.swagger.v3.oas.annotations.media.Schema declaredSchema = null;
+ if (property.getField() != null) {
+ declaredSchema = property.getField().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class);
+ } else if (property.getGetter() != null) {
+ declaredSchema = property.getGetter().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class);
+ }
+
+ if (declaredSchema != null &&
+ (ArrayUtils.isNotEmpty(declaredSchema.oneOf()) || ArrayUtils.isNotEmpty(declaredSchema.allOf()))) {
+ TYPES_TO_SKIP.add(property.getPrimaryType().getRawClass().getSimpleName());
}
}
}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java
index 8a8ef92dc..1db18a182 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java
@@ -64,6 +64,9 @@
/**
* The type Data rest delegating method parameter customizer.
+ *
+ * @author bnasslahsen
+ * @author pheyken
*/
public class DataRestDelegatingMethodParameterCustomizer implements DelegatingMethodParameterCustomizer {
@@ -1131,8 +1134,13 @@ else if (isSpringDataWebPropertiesPresent())
defaultValue = defaultSchemaVal;
break;
case "page":
- if (pageableDefault != null)
- defaultValue = String.valueOf(pageableDefault.page());
+ if (pageableDefault != null) {
+ if (isSpringDataWebPropertiesPresent() && optionalSpringDataWebPropertiesProvider.get().getSpringDataWebProperties().getPageable().isOneIndexedParameters()) {
+ defaultValue = String.valueOf(pageableDefault.page() + 1);
+ } else {
+ defaultValue = String.valueOf(pageableDefault.page());
+ }
+ }
else if (isSpringDataWebPropertiesPresent() && optionalSpringDataWebPropertiesProvider.get().getSpringDataWebProperties().getPageable().isOneIndexedParameters())
defaultValue = "1";
else
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/QuerydslPredicateOperationCustomizer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/QuerydslPredicateOperationCustomizer.java
index dd6fc4e4d..7f86ea597 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/QuerydslPredicateOperationCustomizer.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/QuerydslPredicateOperationCustomizer.java
@@ -32,6 +32,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -112,7 +113,7 @@ public Operation customize(Operation operation, HandlerMethod handlerMethod) {
QuerydslBindings bindings = extractQdslBindings(predicate);
- Set fieldsToAdd = Arrays.stream(predicate.root().getDeclaredFields()).filter(field -> !Modifier.isStatic(field.getModifiers())).map(Field::getName).collect(Collectors.toSet());
+ Set fieldsToAdd = Arrays.stream(predicate.root().getDeclaredFields()).filter(field -> !Modifier.isStatic(field.getModifiers())).map(Field::getName).collect(Collectors.toCollection(LinkedHashSet::new));
Map pathSpecMap = getPathSpec(bindings, "pathSpecs");
//remove blacklisted fields
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/SpringDocCustomizers.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/SpringDocCustomizers.java
index 577cf39ed..8acc651c7 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/SpringDocCustomizers.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/SpringDocCustomizers.java
@@ -39,7 +39,7 @@
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.CollectionUtils;
-import static org.springdoc.core.utils.Constants.LINKS_SCHEMA_CUSTOMISER;
+import static org.springdoc.core.utils.Constants.LINKS_SCHEMA_CUSTOMIZER;
/**
* The type Spring doc customizers.
@@ -223,7 +223,7 @@ public Optional> getGlobalOpenApiMethodFilters()
public void afterPropertiesSet() {
//add the default customizers
Map existingOpenApiCustomizers = context.getBeansOfType(OpenApiCustomizer.class);
- if (!CollectionUtils.isEmpty(existingOpenApiCustomizers) && existingOpenApiCustomizers.containsKey(LINKS_SCHEMA_CUSTOMISER))
- this.openApiCustomizers.ifPresent(openApiCustomizersList -> openApiCustomizersList.add(existingOpenApiCustomizers.get(LINKS_SCHEMA_CUSTOMISER)));
+ if (!CollectionUtils.isEmpty(existingOpenApiCustomizers) && existingOpenApiCustomizers.containsKey(LINKS_SCHEMA_CUSTOMIZER))
+ this.openApiCustomizers.ifPresent(openApiCustomizersList -> openApiCustomizersList.add(existingOpenApiCustomizers.get(LINKS_SCHEMA_CUSTOMIZER)));
}
}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRouterOperationService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRouterOperationService.java
index bd640ad95..41660655b 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRouterOperationService.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/data/DataRestRouterOperationService.java
@@ -28,6 +28,7 @@
import java.util.Arrays;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -178,7 +179,7 @@ private void buildRouterOperationList(List routerOperationList,
if (andCheck(resourceMetadata != null, !controllerType.equals(ControllerType.SEARCH))) {
HttpMethods httpMethodsItem = resourceMetadata.getSupportedHttpMethods().getMethodsFor(ResourceType.ITEM);
requestMethodsItem = requestMethods.stream().filter(requestMethod -> httpMethodsItem.contains(HttpMethod.valueOf(requestMethod.toString())))
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
buildRouterOperation(routerOperationList, resourceMetadata, dataRestRepository, openAPI, path,
subPath, controllerType, methodResourceMapping, requestMappingInfo, handlerMethod, requestMethodsItem, ResourceType.ITEM);
@@ -186,7 +187,7 @@ private void buildRouterOperationList(List routerOperationList,
if (!ControllerType.PROPERTY.equals(controllerType)) {
HttpMethods httpMethodsCollection = resourceMetadata.getSupportedHttpMethods().getMethodsFor(ResourceType.COLLECTION);
requestMethodsCollection = requestMethods.stream().filter(requestMethod -> httpMethodsCollection.contains(HttpMethod.valueOf(requestMethod.toString())))
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
buildRouterOperation(routerOperationList, resourceMetadata, dataRestRepository, openAPI, path,
subPath, controllerType, methodResourceMapping, requestMappingInfo, handlerMethod, requestMethodsCollection, ResourceType.COLLECTION);
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java
index 1d51a5b4e..643c2d9fd 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/extractor/MethodParameterPojoExtractor.java
@@ -40,6 +40,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -361,7 +362,7 @@ private static boolean isNullable(Annotation[] fieldAnnotations) {
Collection annotationSimpleNames = Arrays.stream(fieldAnnotations)
.map(Annotation::annotationType)
.map(Class::getSimpleName)
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
return !hasNotNullAnnotation(annotationSimpleNames);
}
}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigProperties.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigProperties.java
index b2e21e843..d4158bcc3 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigProperties.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SwaggerUiConfigProperties.java
@@ -27,6 +27,7 @@
package org.springdoc.core.properties;
import java.io.IOException;
+import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
@@ -239,7 +240,7 @@ public void setSyntaxHighlight(SyntaxHighlight syntaxHighlight) {
* @return the set
*/
public Set cloneUrls() {
- return this.urls.stream().map(swaggerUrl -> new SwaggerUrl(swaggerUrl.getName(), swaggerUrl.getUrl(), swaggerUrl.getDisplayName())).collect(Collectors.toSet());
+ return this.urls.stream().map(swaggerUrl -> new SwaggerUrl(swaggerUrl.getName(), swaggerUrl.getUrl(), swaggerUrl.getDisplayName())).collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java
index ea41fee6f..f26f4a90b 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/GenericResponseService.java
@@ -36,6 +36,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -489,12 +490,12 @@ public Set getApiResponses(
Set apiResponsesDoc = AnnotatedElementUtils
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.responses.ApiResponses.class);
Set responses = apiResponsesDoc.stream()
- .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
+ .flatMap(x -> Stream.of(x.value())).collect(Collectors.toCollection(LinkedHashSet::new));
Set apiResponsesDocDeclaringClass = AnnotatedElementUtils
.findAllMergedAnnotations(declaringClass, io.swagger.v3.oas.annotations.responses.ApiResponses.class);
responses.addAll(
- apiResponsesDocDeclaringClass.stream().flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet()));
+ apiResponsesDocDeclaringClass.stream().flatMap(x -> Stream.of(x.value())).collect(Collectors.toCollection(LinkedHashSet::new)));
Set apiResponseDoc = AnnotatedElementUtils
.findMergedRepeatableAnnotations(method, io.swagger.v3.oas.annotations.responses.ApiResponse.class);
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java
index 596e61395..1d382c7db 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java
@@ -33,6 +33,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -336,7 +337,7 @@ public Operation buildTags(HandlerMethod handlerMethod, Operation operation, Ope
if (!CollectionUtils.isEmpty(tagsStr))
tagsStr = tagsStr.stream()
.map(str -> propertyResolverUtils.resolve(str, locale))
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
if (springdocTags.containsKey(handlerMethod)) {
io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod);
@@ -407,10 +408,10 @@ private void buildTagsFromMethod(Method method, Set tagsSet = AnnotatedElementUtils
.findAllMergedAnnotations(method, Tags.class);
Set methodTags = tagsSet.stream()
- .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
+ .flatMap(x -> Stream.of(x.value())).collect(Collectors.toCollection(LinkedHashSet::new));
methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, Tag.class));
if (!CollectionUtils.isEmpty(methodTags)) {
- tagsStr.addAll(methodTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toSet()));
+ tagsStr.addAll(methodTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toCollection(LinkedHashSet::new)));
List allTags = new ArrayList<>(methodTags);
addTags(allTags, tags, locale);
}
@@ -450,10 +451,10 @@ public void buildTagsFromClass(Class> beanType, Set tagsSet = AnnotatedElementUtils
.findAllMergedAnnotations(beanType, Tags.class);
Set classTags = tagsSet.stream()
- .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
+ .flatMap(x -> Stream.of(x.value())).collect(Collectors.toCollection(LinkedHashSet::new));
classTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(beanType, Tag.class));
if (!CollectionUtils.isEmpty(classTags)) {
- tagsStr.addAll(classTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toSet()));
+ tagsStr.addAll(classTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toCollection(LinkedHashSet::new)));
allTags.addAll(classTags);
addTags(allTags, tags, locale);
}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java
index 20f9124ab..9453a832d 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java
@@ -407,7 +407,12 @@ public final class Constants {
/**
* The constant LINKS_SCHEMA_CUSTOMISER.
*/
- public static final String LINKS_SCHEMA_CUSTOMISER = "linksSchemaCustomizer";
+ public static final String LINKS_SCHEMA_CUSTOMIZER = "linksSchemaCustomizer";
+
+ /**
+ * The constant GLOBAL_OPEN_API_CUSTOMIZER.
+ */
+ public static final String GLOBAL_OPEN_API_CUSTOMIZER = "globalOpenApiCustomizer";
/**
* The constant SPRINGDOC_SORT_CONVERTER_ENABLED.
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java
index 3178f1f6f..a98d7a5e3 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/PropertyResolverUtils.java
@@ -32,7 +32,8 @@
import java.util.Map;
import io.swagger.v3.oas.models.SpecVersion;
-import org.apache.commons.lang3.StringUtils;
+import java.util.stream.Collectors;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.properties.SpringDocConfigProperties;
@@ -114,23 +115,24 @@ public String resolve(String parameterProperty, Locale locale) {
* Returns a string where all leading indentation has been removed from each line.
* It detects the smallest common indentation of all the lines in the input string,
* and removes it.
+ * If the input text is {@code null}, the method returns {@code null}.
*
- * @param text The original string with possible leading indentation.
- * @return The string with leading indentation removed from each line.
+ * @param text The original string with possible leading indentation.
+ * @return The string with the smallest common leading indentation removed from each line,
+ * or {@code null} if the input text is {@code null}.
*/
public String trimIndent(String text) {
+ if (text == null) {
+ return null;
+ }
+ final String newLine = "\n";
+ String[] lines = text.split("\\r?\\n");
+ int minIndent = resolveMinIndent(lines);
try {
- if (text == null) {
- return null;
- }
- final String newLine = "\n";
- String[] lines = text.split(newLine);
- int minIndent = resolveMinIndent(lines);
return Arrays.stream(lines)
- .map(line -> line.substring(Math.min(line.length(), minIndent)))
- .reduce((a, b) -> a + newLine + b)
- .orElse(StringUtils.EMPTY);
- } catch (Exception ex){
+ .map(line -> line.substring(Math.min(line.length(), minIndent)))
+ .collect(Collectors.joining(newLine));
+ } catch (Exception ex) {
LOGGER.warn(ex.getMessage());
return text;
}
@@ -239,4 +241,4 @@ public Map resolveExtensions(Locale locale, Map
else
return extensions;
}
-}
\ No newline at end of file
+}
diff --git a/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java b/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java
index 91e3029bb..35bd6c2f3 100644
--- a/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java
+++ b/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java
@@ -12,7 +12,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
-import static org.springdoc.core.utils.Constants.LINKS_SCHEMA_CUSTOMISER;
+import static org.springdoc.core.utils.Constants.LINKS_SCHEMA_CUSTOMIZER;
class SpringDocHateoasConfigurationTest {
@@ -33,8 +33,8 @@ void linksSchemaCustomizerShouldBeRegistered() {
.run(context -> {
assertThat(context).getBeanNames(GlobalOpenApiCustomizer.class)
.hasSize(2)
- .contains(LINKS_SCHEMA_CUSTOMISER);
- assertThat(context.getBean(LINKS_SCHEMA_CUSTOMISER)).isExactlyInstanceOf(OpenApiHateoasLinksCustomizer.class);
+ .contains(LINKS_SCHEMA_CUSTOMIZER);
+ assertThat(context.getBean(LINKS_SCHEMA_CUSTOMIZER)).isExactlyInstanceOf(OpenApiHateoasLinksCustomizer.class);
});
}
@@ -56,7 +56,7 @@ void linksSchemaCustomizerShouldBeRegisteredWithMultipleGlobalOpenApiCustomizer(
.run(context -> {
assertThat(context).getBeanNames(GlobalOpenApiCustomizer.class)
.hasSize(2)
- .containsExactlyInAnyOrder(LINKS_SCHEMA_CUSTOMISER, "globalOpenApiCustomizer");
+ .containsExactlyInAnyOrder(LINKS_SCHEMA_CUSTOMIZER, "globalOpenApiCustomizer");
});
}
@@ -74,12 +74,12 @@ void linksSchemaCustomizerShouldNotBeRegisteredIfBeanWithSameNameAlreadyExists()
SpringDocConfigProperties.class,
SpringDocHateoasConfiguration.class
))
- .withBean(LINKS_SCHEMA_CUSTOMISER, GlobalOpenApiCustomizer.class, () -> mock(GlobalOpenApiCustomizer.class))
+ .withBean(LINKS_SCHEMA_CUSTOMIZER, GlobalOpenApiCustomizer.class, () -> mock(GlobalOpenApiCustomizer.class))
.run(context -> {
assertThat(context).getBeanNames(GlobalOpenApiCustomizer.class)
- .hasSize(1)
- .containsExactly(LINKS_SCHEMA_CUSTOMISER);
- assertThat(context.getBean(LINKS_SCHEMA_CUSTOMISER)).isNotExactlyInstanceOf(OpenApiHateoasLinksCustomizer.class);
+ .hasSize(2)
+ .contains(LINKS_SCHEMA_CUSTOMIZER);
+ assertThat(context.getBean(LINKS_SCHEMA_CUSTOMIZER)).isNotExactlyInstanceOf(OpenApiHateoasLinksCustomizer.class);
});
}
}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webflux-api/pom.xml b/springdoc-openapi-starter-webflux-api/pom.xml
index 4f18fd6b7..51ce89e9a 100644
--- a/springdoc-openapi-starter-webflux-api/pom.xml
+++ b/springdoc-openapi-starter-webflux-api/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi
- 2.8.4
+ 2.8.5
springdoc-openapi-starter-webflux-api
diff --git a/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/core/providers/SpringWebFluxProvider.java b/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/core/providers/SpringWebFluxProvider.java
index 2c2bd5bd1..2c5e92cd9 100644
--- a/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/core/providers/SpringWebFluxProvider.java
+++ b/springdoc-openapi-starter-webflux-api/src/main/java/org/springdoc/webflux/core/providers/SpringWebFluxProvider.java
@@ -27,6 +27,7 @@
import java.util.Collection;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -84,7 +85,7 @@ public Set getActivePatterns(Object requestMapping) {
RequestMappingInfo requestMappingInfo = (RequestMappingInfo) requestMapping;
PatternsRequestCondition patternsRequestCondition = requestMappingInfo.getPatternsCondition();
return patternsRequestCondition.getPatterns().stream()
- .map(PathPattern::getPatternString).collect(Collectors.toSet());
+ .map(PathPattern::getPatternString).collect(Collectors.toCollection(LinkedHashSet::new));
}
diff --git a/springdoc-openapi-starter-webflux-ui/pom.xml b/springdoc-openapi-starter-webflux-ui/pom.xml
index ac8dd0c40..76c31fc67 100644
--- a/springdoc-openapi-starter-webflux-ui/pom.xml
+++ b/springdoc-openapi-starter-webflux-ui/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi
- 2.8.4
+ 2.8.5
springdoc-openapi-starter-webflux-ui
diff --git a/springdoc-openapi-starter-webmvc-api/pom.xml b/springdoc-openapi-starter-webmvc-api/pom.xml
index 503d44926..8c868d9b2 100644
--- a/springdoc-openapi-starter-webmvc-api/pom.xml
+++ b/springdoc-openapi-starter-webmvc-api/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi
- 2.8.4
+ 2.8.5
springdoc-openapi-starter-webmvc-api
diff --git a/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java b/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java
index a1fcf1e16..c4557a5be 100644
--- a/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java
+++ b/springdoc-openapi-starter-webmvc-api/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java
@@ -167,6 +167,11 @@ protected void getPaths(Map restControllers, Locale locale, Open
Optional actuatorProviderOptional = springDocProviders.getActuatorProvider();
if (actuatorProviderOptional.isPresent() && springDocConfigProperties.isShowActuator()) {
Map actuatorMap = actuatorProviderOptional.get().getMethods();
+ List globMatchActuators = actuatorMap.keySet().stream()
+ .filter(requestMappingInfo -> requestMappingInfo.getPatternValues().stream()
+ .anyMatch(patternValues -> patternValues.contains("**")))
+ .toList();
+ globMatchActuators.forEach(actuatorMap::remove);
this.openAPIService.addTag(new HashSet<>(actuatorMap.values()), getTag());
map.putAll(actuatorMap);
}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app233/SpringDocApp233Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app233/SpringDocApp233Test.java
index 4480482d1..582cc60ca 100644
--- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app233/SpringDocApp233Test.java
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app233/SpringDocApp233Test.java
@@ -27,6 +27,7 @@
package test.org.springdoc.api.v30.app233;
import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -167,7 +168,7 @@ private void verifySwaggerFieldRequirementsMatchJavaValidation(Collection field.getObjectName() + "." + field.getField())
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
assertThat(errorFields).containsExactlyElementsOf(expectedErrorFields);
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/RootModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/RootModel.java
new file mode 100644
index 000000000..cf2bd6039
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/RootModel.java
@@ -0,0 +1,27 @@
+package test.org.springdoc.api.v30.app239;
+
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+public class RootModel {
+
+ private Integer rootProperty;
+
+ private UnwrappedModel unwrappedModel;
+
+ public Integer getRootProperty() {
+ return rootProperty;
+ }
+
+ public void setRootProperty(Integer rootProperty) {
+ this.rootProperty = rootProperty;
+ }
+
+ @JsonUnwrapped
+ public UnwrappedModel getUnwrappedModel() {
+ return unwrappedModel;
+ }
+
+ public void setUnwrappedModel(UnwrappedModel unwrappedModel) {
+ this.unwrappedModel = unwrappedModel;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/SpringDocApp239Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/SpringDocApp239Test.java
new file mode 100644
index 000000000..122f279a5
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/SpringDocApp239Test.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2019-2024 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v30.app239;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import test.org.springdoc.api.v30.AbstractSpringDocV30Test;
+
+public class SpringDocApp239Test extends AbstractSpringDocV30Test {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/TestController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/TestController.java
new file mode 100644
index 000000000..a3f084691
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/TestController.java
@@ -0,0 +1,15 @@
+package test.org.springdoc.api.v30.app239;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api")
+public class TestController {
+
+ @GetMapping
+ public RootModel getRootModel() {
+ return new RootModel();
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/UnwrappedModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/UnwrappedModel.java
new file mode 100644
index 000000000..9ac5c2a48
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app239/UnwrappedModel.java
@@ -0,0 +1,14 @@
+package test.org.springdoc.api.v30.app239;
+
+public class UnwrappedModel {
+
+ private Integer unwrappedProperty;
+
+ public Integer getUnwrappedProperty() {
+ return unwrappedProperty;
+ }
+
+ public void setUnwrappedProperty(Integer unwrappedProperty) {
+ this.unwrappedProperty = unwrappedProperty;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/AbstractParent.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/AbstractParent.java
new file mode 100644
index 000000000..63634eea2
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/AbstractParent.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2025 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v30.app240;
+
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+@JsonTypeInfo(use = Id.NAME, property = "type")
+public abstract sealed class AbstractParent {
+ private int id;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
+
+final class ChildOfAbstract1 extends AbstractParent {
+ private String abstrachChild1Param;
+
+ public String getAbstrachChild1Param() {
+ return abstrachChild1Param;
+ }
+
+ public void setAbstrachChild1Param(String abstrachChild1Param) {
+ this.abstrachChild1Param = abstrachChild1Param;
+ }
+}
+
+final class ChildOfAbstract2 extends AbstractParent {
+ private String abstractChild2Param;
+
+ public String getAbstractChild2Param() {
+ return abstractChild2Param;
+ }
+
+ public void setAbstractChild2Param(String abstractChild2Param) {
+ this.abstractChild2Param = abstractChild2Param;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/ConcreteParent.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/ConcreteParent.java
new file mode 100644
index 000000000..b0064dc13
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/ConcreteParent.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2025 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v30.app240;
+
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+@JsonTypeInfo(use = Id.NAME, property = "type")
+public sealed class ConcreteParent {
+ private int id;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
+
+final class ChildOfConcrete1 extends ConcreteParent {
+ private String concreteChild1Param;
+
+ public String getConcreteChild1Param() {
+ return concreteChild1Param;
+ }
+
+ public void setConcreteChild1Param(String concreteChild1Param) {
+ this.concreteChild1Param = concreteChild1Param;
+ }
+}
+
+final class ChildOfConcrete2 extends ConcreteParent {
+ private String concreteChild2Param;
+
+ public String getConcreteChild2Param() {
+ return concreteChild2Param;
+ }
+
+ public void setConcreteChild2Param(String concreteChild2Param) {
+ this.concreteChild2Param = concreteChild2Param;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/Controller.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/Controller.java
new file mode 100644
index 000000000..eb1ef7dd2
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/Controller.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2025 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v30.app240;
+
+import java.util.List;
+
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("class-hierarchy")
+public class Controller {
+ @PostMapping("abstract-parent")
+ public Response abstractParent(@RequestBody AbstractParent payload) {
+ return null;
+ }
+
+ @PostMapping("concrete-parent")
+ public Response concreteParent(@RequestBody ConcreteParent payload) {
+ return null;
+ }
+}
+
+class Response {
+ AbstractParent abstractParent;
+
+ List concreteParents;
+
+ public AbstractParent getAbstractParent() {
+ return abstractParent;
+ }
+
+ public void setAbstractParent(AbstractParent abstractParent) {
+ this.abstractParent = abstractParent;
+ }
+
+ public List getConcreteParents() {
+ return concreteParents;
+ }
+
+ public void setConcreteParents(List concreteParents) {
+ this.concreteParents = concreteParents;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/SpringDocApp240Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/SpringDocApp240Test.java
new file mode 100644
index 000000000..ff01415fb
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app240/SpringDocApp240Test.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2019-2024 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v30.app240;
+
+import test.org.springdoc.api.v30.AbstractSpringDocV30Test;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+public class SpringDocApp240Test extends AbstractSpringDocV30Test {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app241/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app241/HelloController.java
new file mode 100644
index 000000000..213093d74
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app241/HelloController.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v30.app241;
+
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+
+ @PostMapping("/parent")
+ public void parentEndpoint(@RequestBody Superclass parent) {
+
+ }
+
+}
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type")
+sealed class Superclass permits IntermediateClass {
+
+ public Superclass() {}
+}
+
+@Schema(name = IntermediateClass.SCHEMA_NAME)
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type")
+sealed class IntermediateClass extends Superclass permits FirstChildClass, SecondChildClass {
+
+ public static final String SCHEMA_NAME = "IntermediateClass";
+}
+
+@Schema(name = FirstChildClass.SCHEMA_NAME)
+final class FirstChildClass extends IntermediateClass {
+
+ public static final String SCHEMA_NAME = "Image";
+}
+
+@Schema(name = SecondChildClass.SCHEMA_NAME)
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type")
+sealed class SecondChildClass extends IntermediateClass {
+
+ public static final String SCHEMA_NAME = "Mail";
+}
+
+@Schema(name = ThirdChildClass.SCHEMA_NAME)
+final class ThirdChildClass extends SecondChildClass {
+
+ public static final String SCHEMA_NAME = "Home";
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app241/SpringDocApp241Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app241/SpringDocApp241Test.java
new file mode 100644
index 000000000..6798b5535
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app241/SpringDocApp241Test.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2019-2024 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v30.app241;
+
+import test.org.springdoc.api.v30.AbstractSpringDocV30Test;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+public class SpringDocApp241Test extends AbstractSpringDocV30Test {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app224/RootModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app224/RootModel.java
index 0df928bc6..8e4c9ce6a 100644
--- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app224/RootModel.java
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app224/RootModel.java
@@ -6,7 +6,6 @@ public class RootModel {
private Integer rootProperty;
- @JsonUnwrapped
private UnwrappedModel unwrappedModel;
public Integer getRootProperty() {
@@ -17,6 +16,7 @@ public void setRootProperty(Integer rootProperty) {
this.rootProperty = rootProperty;
}
+ @JsonUnwrapped
public UnwrappedModel getUnwrappedModel() {
return unwrappedModel;
}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app233/SpringDocApp233Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app233/SpringDocApp233Test.java
index 1636f52a4..21ca8c25e 100644
--- a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app233/SpringDocApp233Test.java
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app233/SpringDocApp233Test.java
@@ -27,6 +27,7 @@
package test.org.springdoc.api.v31.app233;
import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -167,7 +168,7 @@ private void verifySwaggerFieldRequirementsMatchJavaValidation(Collection field.getObjectName() + "." + field.getField())
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
assertThat(errorFields).containsExactlyElementsOf(expectedErrorFields);
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/RootModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/RootModel.java
new file mode 100644
index 000000000..ea8b4261f
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/RootModel.java
@@ -0,0 +1,27 @@
+package test.org.springdoc.api.v31.app239;
+
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+public class RootModel {
+
+ private Integer rootProperty;
+
+ @JsonUnwrapped
+ private UnwrappedModel unwrappedModel;
+
+ public Integer getRootProperty() {
+ return rootProperty;
+ }
+
+ public void setRootProperty(Integer rootProperty) {
+ this.rootProperty = rootProperty;
+ }
+
+ public UnwrappedModel getUnwrappedModel() {
+ return unwrappedModel;
+ }
+
+ public void setUnwrappedModel(UnwrappedModel unwrappedModel) {
+ this.unwrappedModel = unwrappedModel;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/SpringDocApp239Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/SpringDocApp239Test.java
new file mode 100644
index 000000000..efa593ebc
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/SpringDocApp239Test.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * * Copyright 2019-2024 the original author or authors.
+ * * * * *
+ * * * * * Licensed 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
+ * * * * *
+ * * * * * https://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 test.org.springdoc.api.v31.app239;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import test.org.springdoc.api.v31.AbstractSpringDocTest;
+
+public class SpringDocApp239Test extends AbstractSpringDocTest {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/TestController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/TestController.java
new file mode 100644
index 000000000..623fbaefa
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/TestController.java
@@ -0,0 +1,15 @@
+package test.org.springdoc.api.v31.app239;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api")
+public class TestController {
+
+ @GetMapping
+ public RootModel getRootModel() {
+ return new RootModel();
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/UnwrappedModel.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/UnwrappedModel.java
new file mode 100644
index 000000000..ab4776f64
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app239/UnwrappedModel.java
@@ -0,0 +1,14 @@
+package test.org.springdoc.api.v31.app239;
+
+public class UnwrappedModel {
+
+ private Integer unwrappedProperty;
+
+ public Integer getUnwrappedProperty() {
+ return unwrappedProperty;
+ }
+
+ public void setUnwrappedProperty(Integer unwrappedProperty) {
+ this.unwrappedProperty = unwrappedProperty;
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app240/SpringDocApp240Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app240/SpringDocApp240Test.java
new file mode 100644
index 000000000..39e9ac2c4
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app240/SpringDocApp240Test.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v31.app240;
+
+import test.org.springdoc.api.v31.AbstractSpringDocTest;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+public class SpringDocApp240Test extends AbstractSpringDocTest {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {
+
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app240/WildcardController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app240/WildcardController.java
new file mode 100644
index 000000000..34c01dfb8
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app240/WildcardController.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v31.app240;
+
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.servlet.http.HttpServletRequest;
+
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class WildcardController {
+ @PostMapping("/**")
+ @Operation(summary = "My Wildcard Operation")
+ public String getItem(HttpServletRequest request) {
+ return request.getPathInfo();
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/DemoRestController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/DemoRestController.java
new file mode 100644
index 000000000..edbc59b8f
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/DemoRestController.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v31.app241;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import io.swagger.v3.oas.annotations.Parameter;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/demo")
+public class DemoRestController {
+
+ @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+ public Set getDemo(
+ @Parameter(required = false, description = "Very important description.")
+ @RequestParam(name = "darstellung", required = false) final Optional darstellung) {
+ return new HashSet<>();
+ }
+
+ @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> setDemo(@RequestBody final String str) {
+ return ResponseEntity.noContent().build();
+ }
+
+ @GetMapping(value = "/{vvpId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public String getDemo(@PathVariable("vvpId") final Long vvpId) {
+ return "Test";
+ }
+
+ @PatchMapping("/{vvpId}")
+ public ResponseEntity> patchDemo(@PathVariable("vvpId") final Long idVerfahren,
+ @RequestBody() final String jsonPatch,
+ final Optional statusKinderAendern) {
+ return ResponseEntity.noContent().build();
+ }
+
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/OpenApiConfig.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/OpenApiConfig.java
new file mode 100644
index 000000000..9cc00301d
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/OpenApiConfig.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v31.app241;
+
+import org.springdoc.core.customizers.OpenApiCustomizer;
+import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpRequest;
+
+@Configuration
+public class OpenApiConfig {
+
+ @Bean
+ public OpenApiCustomizer openApiCustomiser() {
+ return openApi -> {
+
+ };
+ }
+
+ @Bean
+ ServerBaseUrlCustomizer serverBaseUrlCustomizer() {
+ return new ServerBaseUrlCustomizer() {
+
+ @Override
+ public String customize(final String serverBaseUrl,
+ final HttpRequest request) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ };
+ }
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/SpringDocApp241Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/SpringDocApp241Test.java
new file mode 100644
index 000000000..d4027b764
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v31/app241/SpringDocApp241Test.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v31.app241;
+
+import test.org.springdoc.api.v31.AbstractSpringDocTest;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.test.context.TestPropertySource;
+
+@TestPropertySource(properties = "springdoc.api-docs.resolve-schema-properties=true" )
+public class SpringDocApp241Test extends AbstractSpringDocTest {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app126.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app126.json
index 3bea48404..397f519eb 100644
--- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app126.json
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app126.json
@@ -20,12 +20,6 @@
"description": "Get all currencies",
"operationId": "getAllCurrencies",
"responses": {
- "401": {
- "$ref": "#/components/responses/http401NoToken"
- },
- "403": {
- "$ref": "#/components/responses/http403"
- },
"200": {
"description": "All currencies returned",
"content": {
@@ -38,6 +32,12 @@
}
}
}
+ },
+ "401": {
+ "$ref": "#/components/responses/http401BadToken"
+ },
+ "403": {
+ "$ref": "#/components/responses/http403"
}
}
}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app239.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app239.json
new file mode 100644
index 000000000..d83020e50
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app239.json
@@ -0,0 +1,52 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/api": {
+ "get": {
+ "tags": [
+ "test-controller"
+ ],
+ "operationId": "getRootModel",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/RootModel"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "RootModel": {
+ "type": "object",
+ "properties": {
+ "rootProperty": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "unwrappedProperty": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app240.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app240.json
new file mode 100644
index 000000000..1f5dfa891
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app240.json
@@ -0,0 +1,227 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/class-hierarchy/concrete-parent": {
+ "post": {
+ "tags": [
+ "controller"
+ ],
+ "operationId": "concreteParent",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/ConcreteParent"
+ },
+ {
+ "$ref": "#/components/schemas/ChildOfConcrete1"
+ },
+ {
+ "$ref": "#/components/schemas/ChildOfConcrete2"
+ }
+ ]
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/Response"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/class-hierarchy/abstract-parent": {
+ "post": {
+ "tags": [
+ "controller"
+ ],
+ "operationId": "abstractParent",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/ChildOfAbstract1"
+ },
+ {
+ "$ref": "#/components/schemas/ChildOfAbstract2"
+ }
+ ]
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/Response"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ChildOfConcrete1": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/ConcreteParent"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "concreteChild1Param": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ },
+ "ChildOfConcrete2": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/ConcreteParent"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "concreteChild2Param": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ },
+ "ConcreteParent": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "discriminator": {
+ "propertyName": "type"
+ }
+ },
+ "AbstractParent": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "discriminator": {
+ "propertyName": "type"
+ }
+ },
+ "ChildOfAbstract1": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/AbstractParent"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "abstrachChild1Param": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ },
+ "ChildOfAbstract2": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/AbstractParent"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "abstractChild2Param": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ },
+ "Response": {
+ "type": "object",
+ "properties": {
+ "abstractParent": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/ChildOfAbstract1"
+ },
+ {
+ "$ref": "#/components/schemas/ChildOfAbstract2"
+ }
+ ]
+ },
+ "concreteParents": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/ConcreteParent"
+ },
+ {
+ "$ref": "#/components/schemas/ChildOfConcrete1"
+ },
+ {
+ "$ref": "#/components/schemas/ChildOfConcrete2"
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app241.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app241.json
new file mode 100644
index 000000000..b5dc7bdc7
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app241.json
@@ -0,0 +1,132 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/parent": {
+ "post": {
+ "tags": [
+ "hello-controller"
+ ],
+ "operationId": "parentEndpoint",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/Superclass"
+ },
+ {
+ "$ref": "#/components/schemas/IntermediateClass"
+ },
+ {
+ "$ref": "#/components/schemas/Image"
+ },
+ {
+ "$ref": "#/components/schemas/Mail"
+ },
+ {
+ "$ref": "#/components/schemas/Home"
+ }
+ ]
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Home": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/Mail"
+ }
+ ]
+ },
+ "Image": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/IntermediateClass"
+ }
+ ]
+ },
+ "IntermediateClass": {
+ "required": [
+ "@type"
+ ],
+ "type": "object",
+ "discriminator": {
+ "propertyName": "@type"
+ },
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/Superclass"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "@type": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ },
+ "Mail": {
+ "required": [
+ "@type"
+ ],
+ "type": "object",
+ "discriminator": {
+ "propertyName": "@type"
+ },
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/IntermediateClass"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "@type": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ },
+ "Superclass": {
+ "required": [
+ "@type"
+ ],
+ "type": "object",
+ "properties": {
+ "@type": {
+ "type": "string"
+ }
+ },
+ "discriminator": {
+ "propertyName": "@type"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app126.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app126.json
index a20e02a5f..be22bf20b 100644
--- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app126.json
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app126.json
@@ -20,12 +20,6 @@
"description": "Get all currencies",
"operationId": "getAllCurrencies",
"responses": {
- "401": {
- "$ref": "#/components/responses/http401NoToken"
- },
- "403": {
- "$ref": "#/components/responses/http403"
- },
"200": {
"description": "All currencies returned",
"content": {
@@ -38,6 +32,12 @@
}
}
}
+ },
+ "401": {
+ "$ref": "#/components/responses/http401BadToken"
+ },
+ "403": {
+ "$ref": "#/components/responses/http403"
}
}
}
@@ -62,15 +62,15 @@
"type": "object"
}
},
- "status": {
- "type": "integer",
- "format": "int32"
- },
"title": {
"type": "string"
},
"detail": {
"type": "string"
+ },
+ "status": {
+ "type": "integer",
+ "format": "int32"
}
}
}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app239.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app239.json
new file mode 100644
index 000000000..0ef50ddff
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app239.json
@@ -0,0 +1,52 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/api": {
+ "get": {
+ "tags": [
+ "test-controller"
+ ],
+ "operationId": "getRootModel",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/RootModel"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "RootModel": {
+ "type": "object",
+ "properties": {
+ "rootProperty": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "unwrappedProperty": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app240.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app240.json
new file mode 100644
index 000000000..751bee35c
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app240.json
@@ -0,0 +1,37 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/**": {
+ "post": {
+ "tags": [
+ "wildcard-controller"
+ ],
+ "summary": "My Wildcard Operation",
+ "operationId": "getItem",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {}
+}
\ No newline at end of file
diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app241.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app241.json
new file mode 100644
index 000000000..0a9af7bf9
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.1.0/app241.json
@@ -0,0 +1,151 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "paths": {
+ "/demo": {
+ "get": {
+ "tags": [
+ "demo-rest-controller"
+ ],
+ "operationId": "getDemo",
+ "parameters": [
+ {
+ "name": "darstellung",
+ "in": "query",
+ "description": "Very important description.",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "demo-rest-controller"
+ ],
+ "operationId": "setDemo",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/demo/{vvpId}": {
+ "get": {
+ "tags": [
+ "demo-rest-controller"
+ ],
+ "operationId": "getDemo_1",
+ "parameters": [
+ {
+ "name": "vvpId",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "demo-rest-controller"
+ ],
+ "operationId": "patchDemo",
+ "parameters": [
+ {
+ "name": "vvpId",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "statusKinderAendern",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {}
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/pom.xml b/springdoc-openapi-starter-webmvc-ui/pom.xml
index f16b12bfa..a02c5f0e4 100644
--- a/springdoc-openapi-starter-webmvc-ui/pom.xml
+++ b/springdoc-openapi-starter-webmvc-ui/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi
- 2.8.4
+ 2.8.5
springdoc-openapi-starter-webmvc-ui
diff --git a/springdoc-openapi-tests/pom.xml b/springdoc-openapi-tests/pom.xml
index 5ffc3b88e..9c8e6964b 100644
--- a/springdoc-openapi-tests/pom.xml
+++ b/springdoc-openapi-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi
org.springdoc
- 2.8.4
+ 2.8.5
pom
4.0.0
diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml
index 2634306e0..aec25732c 100644
--- a/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
diff --git a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml
index 8d35755c7..c7eaa8f48 100644
--- a/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml
index 58dbf51bd..689cce0c5 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
springdoc-openapi-data-rest-tests
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/java/test/org/springdoc/api/v31/app14/HelloController.java b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/java/test/org/springdoc/api/v31/app14/HelloController.java
index 743ad62f6..282a794d0 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/java/test/org/springdoc/api/v31/app14/HelloController.java
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/java/test/org/springdoc/api/v31/app14/HelloController.java
@@ -21,7 +21,7 @@
* * * *
* * *
* *
- *
+ *
*/
package test.org.springdoc.api.v31.app14;
@@ -31,6 +31,8 @@
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -43,4 +45,11 @@ public ResponseEntity> getAllPets(@ParameterObject Pageable page
return null;
}
+ @GetMapping("/test1")
+ public String getPatientList1(@PageableDefault(size = 100, sort = { "someField", "someoTHER" },
+ direction = Sort.Direction.DESC)
+ @ParameterObject Pageable pageable) {
+ return "bla";
+ }
+
}
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json
index 33090dcc5..30ceb9d64 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json
@@ -27,14 +27,14 @@
}
},
{
- "name": "name",
+ "name": "email",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "email",
+ "name": "name",
"in": "query",
"schema": {
"type": "string"
@@ -90,6 +90,12 @@
"type": "integer",
"format": "int64"
},
+ "first": {
+ "type": "boolean"
+ },
+ "last": {
+ "type": "boolean"
+ },
"size": {
"type": "integer",
"format": "int32"
@@ -107,15 +113,9 @@
"sort": {
"$ref": "#/components/schemas/SortObject"
},
- "last": {
- "type": "boolean"
- },
"pageable": {
"$ref": "#/components/schemas/PageableObject"
},
- "first": {
- "type": "boolean"
- },
"numberOfElements": {
"type": "integer",
"format": "int32"
@@ -135,6 +135,12 @@
"sort": {
"$ref": "#/components/schemas/SortObject"
},
+ "unpaged": {
+ "type": "boolean"
+ },
+ "paged": {
+ "type": "boolean"
+ },
"pageNumber": {
"type": "integer",
"format": "int32"
@@ -142,12 +148,6 @@
"pageSize": {
"type": "integer",
"format": "int32"
- },
- "paged": {
- "type": "boolean"
- },
- "unpaged": {
- "type": "boolean"
}
}
},
@@ -157,10 +157,10 @@
"empty": {
"type": "boolean"
},
- "sorted": {
+ "unsorted": {
"type": "boolean"
},
- "unsorted": {
+ "sorted": {
"type": "boolean"
}
}
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app30.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app30.json
index 2cf234399..a1c4cc176 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app30.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app30.json
@@ -19,14 +19,14 @@
"operationId": "testQueryDslAndSpringDoc",
"parameters": [
{
- "name": "name",
+ "name": "email",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "email",
+ "name": "name",
"in": "query",
"schema": {
"type": "string"
@@ -70,4 +70,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app5.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app5.json
index 899554e82..932647c22 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app5.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app5.json
@@ -34,10 +34,11 @@
}
},
{
- "name": "code",
+ "name": "id",
"in": "query",
"schema": {
- "type": "string"
+ "type": "integer",
+ "format": "int64"
}
},
{
@@ -48,36 +49,35 @@
}
},
{
- "name": "postCode",
+ "name": "shortName",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "id",
+ "name": "status",
"in": "query",
"schema": {
- "type": "integer",
- "format": "int64"
+ "type": "string",
+ "enum": [
+ "ACTIVE",
+ "INACTIVE"
+ ]
}
},
{
- "name": "shortName",
+ "name": "code",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "status",
+ "name": "postCode",
"in": "query",
"schema": {
- "type": "string",
- "enum": [
- "ACTIVE",
- "INACTIVE"
- ]
+ "type": "string"
}
}
],
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app14.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app14.json
index a2e119230..471b990a2 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app14.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app14.json
@@ -11,6 +11,66 @@
}
],
"paths": {
+ "/test1": {
+ "get": {
+ "tags": [
+ "hello-controller"
+ ],
+ "operationId": "getPatientList1",
+ "parameters": [
+ {
+ "name": "prefix_pages",
+ "in": "query",
+ "description": "One-based page index (1..N)",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "default": 1,
+ "minimum": 0
+ }
+ },
+ {
+ "name": "prefix_sizes",
+ "in": "query",
+ "description": "The size of the page to be returned",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "default": 100,
+ "minimum": 1
+ }
+ },
+ {
+ "name": "sorts",
+ "in": "query",
+ "description": "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.",
+ "required": false,
+ "schema": {
+ "type": "array",
+ "default": [
+ "someField,DESC",
+ "someoTHER,DESC"
+ ],
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/search": {
"get": {
"tags": [
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json
index 76b3a324f..1a901539e 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json
@@ -27,14 +27,14 @@
}
},
{
- "name": "name",
+ "name": "email",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "email",
+ "name": "name",
"in": "query",
"schema": {
"type": "string"
@@ -62,14 +62,14 @@
"type": "object",
"properties": {
"page": {
- "minimum": 0,
"type": "integer",
- "format": "int32"
+ "format": "int32",
+ "minimum": 0
},
"size": {
- "minimum": 1,
"type": "integer",
- "format": "int32"
+ "format": "int32",
+ "minimum": 1
},
"sort": {
"type": "array",
@@ -90,6 +90,12 @@
"type": "integer",
"format": "int64"
},
+ "first": {
+ "type": "boolean"
+ },
+ "last": {
+ "type": "boolean"
+ },
"size": {
"type": "integer",
"format": "int32"
@@ -107,15 +113,9 @@
"sort": {
"$ref": "#/components/schemas/SortObject"
},
- "last": {
- "type": "boolean"
- },
"pageable": {
"$ref": "#/components/schemas/PageableObject"
},
- "first": {
- "type": "boolean"
- },
"numberOfElements": {
"type": "integer",
"format": "int32"
@@ -135,6 +135,12 @@
"sort": {
"$ref": "#/components/schemas/SortObject"
},
+ "unpaged": {
+ "type": "boolean"
+ },
+ "paged": {
+ "type": "boolean"
+ },
"pageNumber": {
"type": "integer",
"format": "int32"
@@ -142,12 +148,6 @@
"pageSize": {
"type": "integer",
"format": "int32"
- },
- "paged": {
- "type": "boolean"
- },
- "unpaged": {
- "type": "boolean"
}
}
},
@@ -157,10 +157,10 @@
"empty": {
"type": "boolean"
},
- "sorted": {
+ "unsorted": {
"type": "boolean"
},
- "unsorted": {
+ "sorted": {
"type": "boolean"
}
}
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app30.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app30.json
index bbb90bbe9..62757da1a 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app30.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app30.json
@@ -19,14 +19,14 @@
"operationId": "testQueryDslAndSpringDoc",
"parameters": [
{
- "name": "name",
+ "name": "email",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "email",
+ "name": "name",
"in": "query",
"schema": {
"type": "string"
@@ -70,4 +70,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app5.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app5.json
index e46116a9f..fe52268d8 100644
--- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app5.json
+++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app5.json
@@ -34,10 +34,11 @@
}
},
{
- "name": "code",
+ "name": "id",
"in": "query",
"schema": {
- "type": "string"
+ "type": "integer",
+ "format": "int64"
}
},
{
@@ -48,36 +49,35 @@
}
},
{
- "name": "postCode",
+ "name": "shortName",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "id",
+ "name": "status",
"in": "query",
"schema": {
- "type": "integer",
- "format": "int64"
+ "type": "string",
+ "enum": [
+ "ACTIVE",
+ "INACTIVE"
+ ]
}
},
{
- "name": "shortName",
+ "name": "code",
"in": "query",
"schema": {
"type": "string"
}
},
{
- "name": "status",
+ "name": "postCode",
"in": "query",
"schema": {
- "type": "string",
- "enum": [
- "ACTIVE",
- "INACTIVE"
- ]
+ "type": "string"
}
}
],
diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml
index ae7b361d1..6c0f31049 100644
--- a/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-function-webflux-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
diff --git a/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml
index f956be798..a6d1f9e82 100644
--- a/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-function-webmvc-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
diff --git a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml
index 5597b2d91..cc71b2f05 100644
--- a/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-groovy-tests/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi-tests
- 2.8.4
+ 2.8.5
springdoc-openapi-groovy-tests
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml
index 5b6002f6c..b8c863bd4 100644
--- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
springdoc-openapi-hateoas-tests
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/SpringDocApp11Test.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/SpringDocApp11Test.java
new file mode 100644
index 000000000..3e619a272
--- /dev/null
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/SpringDocApp11Test.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * *
+ * * *
+ * * * *
+ * * * * *
+ * * * * * * Copyright 2019-2025 the original author or authors.
+ * * * * * *
+ * * * * * * Licensed 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
+ * * * * * *
+ * * * * * * https://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 test.org.springdoc.api.v31.app11;
+
+import test.org.springdoc.api.v31.AbstractSpringDocTest;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+public class SpringDocApp11Test extends AbstractSpringDocTest {
+
+ @SpringBootApplication
+ static class SpringDocTestApp {
+ }
+
+}
\ No newline at end of file
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/configuration/WebMvcConfiguration.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/configuration/WebMvcConfiguration.java
new file mode 100644
index 000000000..032eeeac7
--- /dev/null
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/configuration/WebMvcConfiguration.java
@@ -0,0 +1,25 @@
+package test.org.springdoc.api.v31.app11.configuration;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+@Configuration
+public class WebMvcConfiguration {
+
+ @Bean
+ MappingJackson2HttpMessageConverter getMappingJacksonHttpMessageConverter() {
+ MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
+ converter.setSupportedMediaTypes(List.of(MediaType.APPLICATION_JSON));
+ converter.setObjectMapper(new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL)
+ );
+
+ return converter;
+ }
+}
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/controllers/BasicController.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/controllers/BasicController.java
new file mode 100644
index 000000000..7f6586f05
--- /dev/null
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/controllers/BasicController.java
@@ -0,0 +1,41 @@
+package test.org.springdoc.api.v31.app11.controllers;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import test.org.springdoc.api.v31.app11.model.Cat;
+
+import org.springframework.hateoas.MediaTypes;
+import org.springframework.hateoas.RepresentationModel;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(path = "/")
+public class BasicController {
+
+ @GetMapping("/cat")
+ @ResponseStatus(HttpStatus.OK)
+ @Operation(summary = "get", description = "Provides an animal.")
+ public String get(Cat cat) {
+ return cat != null ? cat.getName() : "";
+ }
+
+ @GetMapping("/test")
+ @ResponseStatus(HttpStatus.OK)
+ @Operation(summary = "get", description = "Provides a response.")
+ @ApiResponse(content = @Content(mediaType = MediaTypes.HAL_JSON_VALUE,
+ schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Response.class)),
+ responseCode = "200")
+ public Response get() {
+ return new Response("value");
+ }
+
+ // dummy
+ public static class Response extends RepresentationModel {
+ public Response(String v) {}
+ }
+}
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/controllers/CustomOpenApiWebMvcResource.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/controllers/CustomOpenApiWebMvcResource.java
new file mode 100644
index 000000000..f88930430
--- /dev/null
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/controllers/CustomOpenApiWebMvcResource.java
@@ -0,0 +1,27 @@
+package test.org.springdoc.api.v31.app11.controllers;
+
+import org.springdoc.core.customizers.SpringDocCustomizers;
+import org.springdoc.core.properties.SpringDocConfigProperties;
+import org.springdoc.core.providers.SpringDocProviders;
+import org.springdoc.core.service.AbstractRequestService;
+import org.springdoc.core.service.GenericResponseService;
+import org.springdoc.core.service.OpenAPIService;
+import org.springdoc.core.service.OperationService;
+import org.springdoc.webmvc.api.OpenApiWebMvcResource;
+
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class CustomOpenApiWebMvcResource extends OpenApiWebMvcResource {
+
+ public CustomOpenApiWebMvcResource(ObjectFactory openAPIBuilderObjectFactory,
+ AbstractRequestService requestBuilder,
+ GenericResponseService responseBuilder,
+ OperationService operationParser,
+ SpringDocConfigProperties springDocConfigProperties,
+ SpringDocProviders springDocProviders,
+ SpringDocCustomizers springDocCustomizers) {
+ super(openAPIBuilderObjectFactory, requestBuilder, responseBuilder, operationParser, springDocConfigProperties, springDocProviders, springDocCustomizers);
+ }
+}
\ No newline at end of file
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/model/Cat.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/model/Cat.java
new file mode 100644
index 000000000..95595b01a
--- /dev/null
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app11/model/Cat.java
@@ -0,0 +1,24 @@
+package test.org.springdoc.api.v31.app11.model;
+
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "Represents a Cat class.")
+public class Cat {
+
+ @JsonUnwrapped
+ @Schema(description = "The name.", nullable = true)
+ private String name;
+
+ public Cat(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app11.json b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app11.json
new file mode 100644
index 000000000..a40b8cb0b
--- /dev/null
+++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app11.json
@@ -0,0 +1,126 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/test": {
+ "get": {
+ "tags": [
+ "basic-controller"
+ ],
+ "summary": "get",
+ "description": "Provides a response.",
+ "operationId": "get",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/hal+json": {
+ "schema": {
+ "$ref": "#/components/schemas/Response"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/cat": {
+ "get": {
+ "tags": [
+ "basic-controller"
+ ],
+ "summary": "get",
+ "description": "Provides an animal.",
+ "operationId": "get_1",
+ "parameters": [
+ {
+ "name": "cat",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/Cat"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Response": {
+ "type": "object",
+ "properties": {
+ "_links": {
+ "$ref": "#/components/schemas/Links"
+ }
+ }
+ },
+ "Cat": {
+ "type": "object",
+ "description": "Represents a Cat class.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name."
+ }
+ }
+ },
+ "Link": {
+ "type": "object",
+ "properties": {
+ "href": {
+ "type": "string"
+ },
+ "hreflang": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "deprecation": {
+ "type": "string"
+ },
+ "profile": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "templated": {
+ "type": "boolean"
+ }
+ }
+ },
+ "Links": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/components/schemas/Link"
+ }
+ }
+ }
+ }
+}
diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml
index a89128c99..127082932 100644
--- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/pom.xml
@@ -2,7 +2,7 @@
org.springdoc
springdoc-openapi-tests
- 2.8.4
+ 2.8.5
4.0.0
diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.0.1/app126.json b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.0.1/app126.json
index 47ce6c5a7..ff6b88de5 100644
--- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.0.1/app126.json
+++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.0.1/app126.json
@@ -26,12 +26,6 @@
"description": "Get all currencies",
"operationId": "getAllCurrencies",
"responses": {
- "401": {
- "$ref": "#/components/responses/http401NoToken"
- },
- "403": {
- "$ref": "#/components/responses/http403"
- },
"200": {
"description": "All currencies returned",
"content": {
@@ -44,6 +38,12 @@
}
}
}
+ },
+ "401": {
+ "$ref": "#/components/responses/http401BadToken"
+ },
+ "403": {
+ "$ref": "#/components/responses/http403"
}
}
}
@@ -71,6 +71,11 @@
},
"description": "Optional, additional attributes of the problem. Implementations can choose to ignore this in favor of concrete,\n typed fields."
},
+ "status": {
+ "type": "integer",
+ "description": "The HTTP status code generated by the origin server for this\n occurrence of the problem.",
+ "format": "int32"
+ },
"title": {
"type": "string",
"description": "A short, human-readable summary of the problem type. It SHOULD NOT\n change from occurrence to occurrence of the problem, except for\n purposes of localisation."
@@ -78,11 +83,6 @@
"detail": {
"type": "string",
"description": "A human readable explanation specific to this occurrence of the problem."
- },
- "status": {
- "type": "integer",
- "description": "The HTTP status code generated by the origin server for this\n occurrence of the problem.",
- "format": "int32"
}
},
"description": "The interface Problem."
diff --git a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.1.0/app126.json b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.1.0/app126.json
index 074f383aa..57be66520 100644
--- a/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.1.0/app126.json
+++ b/springdoc-openapi-tests/springdoc-openapi-javadoc-tests/src/test/resources/results/3.1.0/app126.json
@@ -26,12 +26,6 @@
"description": "Get all currencies",
"operationId": "getAllCurrencies",
"responses": {
- "401": {
- "$ref": "#/components/responses/http401NoToken"
- },
- "403": {
- "$ref": "#/components/responses/http403"
- },
"200": {
"description": "All currencies returned",
"content": {
@@ -44,6 +38,12 @@
}
}
}
+ },
+ "401": {
+ "$ref": "#/components/responses/http401BadToken"
+ },
+ "403": {
+ "$ref": "#/components/responses/http403"
}
}
}
@@ -53,16 +53,17 @@
"schemas": {
"Problem": {
"type": "object",
+ "description": "The interface Problem.",
"properties": {
"instance": {
"type": "string",
- "description": "An absolute URI that identifies the specific occurrence of the problem.\n It may or may not yield further information if dereferenced.",
- "format": "uri"
+ "format": "uri",
+ "description": "An absolute URI that identifies the specific occurrence of the problem.\n It may or may not yield further information if dereferenced."
},
"type": {
"type": "string",
- "description": "An absolute URI that identifies the problem type. When dereferenced,\n it SHOULD provide human-readable documentation for the problem type\n (e.g., using HTML). When this member is not present, its value is\n assumed to be \"about:blank\".",
- "format": "uri"
+ "format": "uri",
+ "description": "An absolute URI that identifies the problem type. When dereferenced,\n it SHOULD provide human-readable documentation for the problem type\n (e.g., using HTML). When this member is not present, its value is\n assumed to be \"about:blank\"."
},
"parameters": {
"type": "object",
@@ -71,6 +72,11 @@
},
"description": "Optional, additional attributes of the problem. Implementations can choose to ignore this in favor of concrete,\n typed fields."
},
+ "status": {
+ "type": "integer",
+ "format": "int32",
+ "description": "The HTTP status code generated by the origin server for this\n occurrence of the problem."
+ },
"title": {
"type": "string",
"description": "A short, human-readable summary of the problem type. It SHOULD NOT\n change from occurrence to occurrence of the problem, except for\n purposes of localisation."
@@ -78,14 +84,8 @@
"detail": {
"type": "string",
"description": "A human readable explanation specific to this occurrence of the problem."
- },
- "status": {
- "type": "integer",
- "description": "The HTTP status code generated by the origin server for this\n occurrence of the problem.",
- "format": "int32"
}
- },
- "description": "The interface Problem."
+ }
}
},
"responses": {
diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml
index 3b25490e3..a6b7c7394 100644
--- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webflux-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
springdoc-openapi-kotlin-webflux-tests
diff --git a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml
index 621449351..6083259e1 100644
--- a/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-kotlin-webmvc-tests/pom.xml
@@ -2,7 +2,7 @@
springdoc-openapi-tests
org.springdoc
- 2.8.4
+ 2.8.5
4.0.0
springdoc-openapi-kotlin-webmvc-tests
diff --git a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml
index 20a2f52a0..30183265d 100644
--- a/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml
+++ b/springdoc-openapi-tests/springdoc-openapi-security-tests/pom.xml
@@ -3,7 +3,7 @@
org.springdoc
springdoc-openapi-tests
- 2.8.4
+ 2.8.5
springdoc-openapi-security-tests