From 21b506cba8f00613c721ae99921963d31e6757c3 Mon Sep 17 00:00:00 2001 From: daniel-shuy Date: Tue, 7 Jun 2022 23:45:55 +0800 Subject: [PATCH 1/2] Add swagger annotation delegates --- ...stDelegatingMethodParameterCustomizer.java | 494 +----------------- .../core/delegates/ArraySchemaDelegate.java | 58 ++ .../core/delegates/ParameterDelegate.java | 119 +++++ .../core/delegates/SchemaDelegate.java | 224 ++++++++ 4 files changed, 408 insertions(+), 487 deletions(-) create mode 100644 springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ArraySchemaDelegate.java create mode 100644 springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ParameterDelegate.java create mode 100644 springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/SchemaDelegate.java diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java index 6be158bf8..646655774 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java @@ -31,22 +31,17 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.v3.core.util.ObjectMapperFactory; -import io.swagger.v3.oas.annotations.ExternalDocumentation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.enums.Explode; -import io.swagger.v3.oas.annotations.enums.ParameterIn; -import io.swagger.v3.oas.annotations.enums.ParameterStyle; -import io.swagger.v3.oas.annotations.extensions.Extension; import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; -import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springdoc.core.DelegatingMethodParameter; +import org.springdoc.core.delegates.ArraySchemaDelegate; +import org.springdoc.core.delegates.ParameterDelegate; +import org.springdoc.core.delegates.SchemaDelegate; import org.springdoc.core.providers.RepositoryRestConfigurationProvider; import org.springdoc.core.providers.SpringDataWebPropertiesProvider; @@ -123,180 +118,15 @@ private Optional getNewParameterAnnotationForField(MethodParameter m try { field = methodParameter.getContainingClass().getDeclaredField(parameterName); Parameter parameter = field.getAnnotation(Parameter.class); - parameterNew = new Parameter() { - @Override - public Class annotationType() { - return parameter.annotationType(); - } - + parameterNew = new ParameterDelegate(parameter) { @Override public String name() { return getName(parameterName, parameter.name()); } - @Override - public ParameterIn in() { - return parameter.in(); - } - - @Override - public String description() { - return parameter.description(); - } - - @Override - public boolean required() { - return parameter.required(); - } - - @Override - public boolean deprecated() { - return parameter.deprecated(); - } - - @Override - public boolean allowEmptyValue() { - return parameter.allowEmptyValue(); - } - - @Override - public ParameterStyle style() { - return parameter.style(); - } - - @Override - public Explode explode() { - return parameter.explode(); - } - - @Override - public boolean allowReserved() { - return parameter.allowReserved(); - } - @Override public Schema schema() { - return new Schema() { - - @Override - public Class annotationType() { - return parameter.schema().annotationType(); - } - - @Override - public Class implementation() { - return parameter.schema().implementation(); - } - - @Override - public Class not() { - return parameter.schema().not(); - } - - @Override - public Class[] oneOf() { - return parameter.schema().oneOf(); - } - - @Override - public Class[] anyOf() { - return parameter.schema().anyOf(); - } - - @Override - public Class[] allOf() { - return parameter.schema().allOf(); - } - - @Override - public String name() { - return parameter.schema().name(); - } - - @Override - public String title() { - return parameter.schema().title(); - } - - @Override - public double multipleOf() { - return parameter.schema().multipleOf(); - } - - @Override - public String maximum() { - return parameter.schema().maximum(); - } - - @Override - public boolean exclusiveMaximum() { - return parameter.schema().exclusiveMaximum(); - } - - @Override - public String minimum() { - return parameter.schema().minimum(); - } - - @Override - public boolean exclusiveMinimum() { - return parameter.schema().exclusiveMaximum(); - } - - @Override - public int maxLength() { - return parameter.schema().maxLength(); - } - - @Override - public int minLength() { - return parameter.schema().minLength(); - } - - @Override - public String pattern() { - return parameter.schema().pattern(); - } - - @Override - public int maxProperties() { - return parameter.schema().maxProperties(); - } - - @Override - public int minProperties() { - return parameter.schema().minProperties(); - } - - @Override - public String[] requiredProperties() { - return parameter.schema().requiredProperties(); - } - - @Override - public boolean required() { - return parameter.schema().required(); - } - - @Override - public String description() { - return parameter.schema().description(); - } - - @Override - public String format() { - return parameter.schema().format(); - } - - @Override - public String ref() { - return parameter.schema().ref(); - } - - @Override - public boolean nullable() { - return parameter.schema().nullable(); - } + return new SchemaDelegate(parameter.schema()) { @Override public boolean readOnly() { @@ -308,216 +138,21 @@ public boolean writeOnly() { return AccessMode.WRITE_ONLY.equals(parameter.schema().accessMode()); } - @Override - public AccessMode accessMode() { - return parameter.schema().accessMode(); - } - - @Override - public String example() { - return parameter.schema().example(); - } - - @Override - public ExternalDocumentation externalDocs() { - return parameter.schema().externalDocs(); - } - - @Override - public boolean deprecated() { - return parameter.schema().deprecated(); - } - - @Override - public String type() { - return parameter.schema().type(); - } - - @Override - public String[] allowableValues() { - return parameter.schema().allowableValues(); - } - @Override public String defaultValue() { return getDefaultValue(parameterName, pageableDefault, parameter.schema().defaultValue()); } - - @Override - public String discriminatorProperty() { - return parameter.schema().discriminatorProperty(); - } - - @Override - public DiscriminatorMapping[] discriminatorMapping() { - return parameter.schema().discriminatorMapping(); - } - - @Override - public boolean hidden() { - return parameter.schema().hidden(); - } - - @Override - public boolean enumAsRef() { - return parameter.schema().enumAsRef(); - } - - @Override - public Class[] subTypes() { - return parameter.schema().subTypes(); - } - - @Override - public Extension[] extensions() { - return parameter.schema().extensions(); - } - - @Override - public AdditionalPropertiesValue additionalProperties() { - return parameter.schema().additionalProperties(); - } }; } @Override public ArraySchema array() { ArraySchema arraySchema = parameter.array(); - return new ArraySchema() { - @Override - public Class annotationType() { - return arraySchema.annotationType(); - } - - @Override - public Schema schema() { - return arraySchema.schema(); - } - + return new ArraySchemaDelegate(arraySchema) { @Override public Schema arraySchema() { Schema schema = arraySchema.arraySchema(); - return new Schema() { - - @Override - public Class annotationType() { - return schema.annotationType(); - } - - @Override - public Class implementation() { - return schema.implementation(); - } - - @Override - public Class not() { - return schema.not(); - } - - @Override - public Class[] oneOf() { - return schema.oneOf(); - } - - @Override - public Class[] anyOf() { - return schema.anyOf(); - } - - @Override - public Class[] allOf() { - return schema.allOf(); - } - - @Override - public String name() { - return schema.name(); - } - - @Override - public String title() { - return schema.title(); - } - - @Override - public double multipleOf() { - return schema.multipleOf(); - } - - @Override - public String maximum() { - return schema.maximum(); - } - - @Override - public boolean exclusiveMaximum() { - return schema.exclusiveMaximum(); - } - - @Override - public String minimum() { - return schema.minimum(); - } - - @Override - public boolean exclusiveMinimum() { - return schema.exclusiveMinimum(); - } - - @Override - public int maxLength() { - return schema.maxLength(); - } - - @Override - public int minLength() { - return schema.minLength(); - } - - @Override - public String pattern() { - return schema.pattern(); - } - - @Override - public int maxProperties() { - return schema.maxProperties(); - } - - @Override - public int minProperties() { - return schema.minProperties(); - } - - @Override - public String[] requiredProperties() { - return schema.requiredProperties(); - } - - @Override - public boolean required() { - return schema.required(); - } - - @Override - public String description() { - return schema.description(); - } - - @Override - public String format() { - return schema.format(); - } - - @Override - public String ref() { - return schema.ref(); - } - - @Override - public boolean nullable() { - return schema.nullable(); - } + return new SchemaDelegate(schema) { @Override public boolean readOnly() { @@ -529,129 +164,14 @@ public boolean writeOnly() { return AccessMode.WRITE_ONLY.equals(schema.accessMode()); } - @Override - public AccessMode accessMode() { - return schema.accessMode(); - } - - @Override - public String example() { - return schema.example(); - } - - @Override - public ExternalDocumentation externalDocs() { - return schema.externalDocs(); - } - - @Override - public boolean deprecated() { - return schema.deprecated(); - } - - @Override - public String type() { - return schema.type(); - } - - @Override - public String[] allowableValues() { - return schema.allowableValues(); - } - @Override public String defaultValue() { return getArrayDefaultValue(parameterName, pageableDefault, schema.defaultValue()); } - - @Override - public String discriminatorProperty() { - return schema.discriminatorProperty(); - } - - @Override - public DiscriminatorMapping[] discriminatorMapping() { - return schema.discriminatorMapping(); - } - - @Override - public boolean hidden() { - return schema.hidden(); - } - - @Override - public boolean enumAsRef() { - return schema.enumAsRef(); - } - - @Override - public Class[] subTypes() { - return schema.subTypes(); - } - - @Override - public Extension[] extensions() { - return schema.extensions(); - } - - @Override - public AdditionalPropertiesValue additionalProperties() { - return schema.additionalProperties(); - } }; } - - @Override - public int maxItems() { - return arraySchema.maxItems(); - } - - @Override - public int minItems() { - return arraySchema.minItems(); - } - - @Override - public boolean uniqueItems() { - return arraySchema.uniqueItems(); - } - - @Override - public Extension[] extensions() { - return arraySchema.extensions(); - } }; } - - @Override - public Content[] content() { - return parameter.content(); - } - - @Override - public boolean hidden() { - return parameter.hidden(); - } - - @Override - public ExampleObject[] examples() { - return parameter.examples(); - } - - @Override - public String example() { - return parameter.example(); - } - - @Override - public Extension[] extensions() { - return parameter.extensions(); - } - - @Override - public String ref() { - return parameter.ref(); - } }; return Optional.of(parameterNew); } diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ArraySchemaDelegate.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ArraySchemaDelegate.java new file mode 100644 index 000000000..0528e358a --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ArraySchemaDelegate.java @@ -0,0 +1,58 @@ +package org.springdoc.core.delegates; + +import java.lang.annotation.Annotation; + +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Utility class to delegate to another @ArraySchema annotation. + * @author daniel-shuy + */ +public class ArraySchemaDelegate implements ArraySchema { + private final ArraySchema arraySchema; + + /** + * Create a delegate to the given ArraySchema. + * @param arraySchema The ArraySchema annotation to delegate to. + */ + public ArraySchemaDelegate(ArraySchema arraySchema) { + this.arraySchema = arraySchema; + } + + @Override + public Class annotationType() { + return arraySchema.annotationType(); + } + + @Override + public Schema schema() { + return arraySchema.schema(); + } + + @Override + public Schema arraySchema() { + return arraySchema.arraySchema(); + } + + @Override + public int maxItems() { + return arraySchema.maxItems(); + } + + @Override + public int minItems() { + return arraySchema.minItems(); + } + + @Override + public boolean uniqueItems() { + return arraySchema.uniqueItems(); + } + + @Override + public Extension[] extensions() { + return arraySchema.extensions(); + } +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ParameterDelegate.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ParameterDelegate.java new file mode 100644 index 000000000..96514e689 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/ParameterDelegate.java @@ -0,0 +1,119 @@ +package org.springdoc.core.delegates; + +import java.lang.annotation.Annotation; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.Explode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.ParameterStyle; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Utility class to delegate to another @Parameter annotation. + * @author daniel-shuy + */ +public class ParameterDelegate implements Parameter { + private final Parameter parameter; + + /** + * Create a delegate to the given Parameter. + * @param parameter The Parameter annotation to delegate to. + */ + public ParameterDelegate(Parameter parameter) { + this.parameter = parameter; + } + + @Override + public Class annotationType() { + return parameter.annotationType(); + } + + @Override + public String name() { + return parameter.name(); + } + + @Override + public ParameterIn in() { + return parameter.in(); + } + + @Override + public String description() { + return parameter.description(); + } + + @Override + public boolean required() { + return parameter.required(); + } + + @Override + public boolean deprecated() { + return parameter.deprecated(); + } + + @Override + public boolean allowEmptyValue() { + return parameter.allowEmptyValue(); + } + + @Override + public ParameterStyle style() { + return parameter.style(); + } + + @Override + public Explode explode() { + return parameter.explode(); + } + + @Override + public boolean allowReserved() { + return parameter.allowReserved(); + } + + @Override + public Schema schema() { + return parameter.schema(); + } + + @Override + public ArraySchema array() { + return parameter.array(); + } + + @Override + public Content[] content() { + return parameter.content(); + } + + @Override + public boolean hidden() { + return parameter.hidden(); + } + + @Override + public ExampleObject[] examples() { + return parameter.examples(); + } + + @Override + public String example() { + return parameter.example(); + } + + @Override + public Extension[] extensions() { + return parameter.extensions(); + } + + @Override + public String ref() { + return parameter.ref(); + } +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/SchemaDelegate.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/SchemaDelegate.java new file mode 100644 index 000000000..f952eede5 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/delegates/SchemaDelegate.java @@ -0,0 +1,224 @@ +package org.springdoc.core.delegates; + +import java.lang.annotation.Annotation; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Utility class to delegate to another @Schema annotation. + * @author daniel-shuy + */ +public class SchemaDelegate implements Schema { + private final Schema schema; + + /** + * Create a delegate to the given Schema. + * @param schema The Schema annotation to delegate to. + */ + public SchemaDelegate(Schema schema) { + this.schema = schema; + } + + @Override + public Class annotationType() { + return schema.annotationType(); + } + + @Override + public Class implementation() { + return schema.implementation(); + } + + @Override + public Class not() { + return schema.not(); + } + + @Override + public Class[] oneOf() { + return schema.oneOf(); + } + + @Override + public Class[] anyOf() { + return schema.anyOf(); + } + + @Override + public Class[] allOf() { + return schema.allOf(); + } + + @Override + public String name() { + return schema.name(); + } + + @Override + public String title() { + return schema.title(); + } + + @Override + public double multipleOf() { + return schema.multipleOf(); + } + + @Override + public String maximum() { + return schema.maximum(); + } + + @Override + public boolean exclusiveMaximum() { + return schema.exclusiveMaximum(); + } + + @Override + public String minimum() { + return schema.minimum(); + } + + @Override + public boolean exclusiveMinimum() { + return schema.exclusiveMinimum(); + } + + @Override + public int maxLength() { + return schema.maxLength(); + } + + @Override + public int minLength() { + return schema.minLength(); + } + + @Override + public String pattern() { + return schema.pattern(); + } + + @Override + public int maxProperties() { + return schema.maxProperties(); + } + + @Override + public int minProperties() { + return schema.minProperties(); + } + + @Override + public String[] requiredProperties() { + return schema.requiredProperties(); + } + + @Override + public boolean required() { + return schema.required(); + } + + @Override + public String description() { + return schema.description(); + } + + @Override + public String format() { + return schema.format(); + } + + @Override + public String ref() { + return schema.ref(); + } + + @Override + public boolean nullable() { + return schema.nullable(); + } + + @Override + public boolean readOnly() { + return schema.readOnly(); + } + + @Override + public boolean writeOnly() { + return schema.writeOnly(); + } + + @Override + public AccessMode accessMode() { + return schema.accessMode(); + } + + @Override + public String example() { + return schema.example(); + } + + @Override + public ExternalDocumentation externalDocs() { + return schema.externalDocs(); + } + + @Override + public boolean deprecated() { + return schema.deprecated(); + } + + @Override + public String type() { + return schema.type(); + } + + @Override + public String[] allowableValues() { + return schema.allowableValues(); + } + + @Override + public String defaultValue() { + return schema.defaultValue(); + } + + @Override + public String discriminatorProperty() { + return schema.discriminatorProperty(); + } + + @Override + public DiscriminatorMapping[] discriminatorMapping() { + return schema.discriminatorMapping(); + } + + @Override + public boolean hidden() { + return schema.hidden(); + } + + @Override + public boolean enumAsRef() { + return schema.enumAsRef(); + } + + @Override + public Class[] subTypes() { + return schema.subTypes(); + } + + @Override + public Extension[] extensions() { + return schema.extensions(); + } + + @Override + public AdditionalPropertiesValue additionalProperties() { + return schema.additionalProperties(); + } +} From f0da77c65cb13824d36394fa57039a679c0eaccb Mon Sep 17 00:00:00 2001 From: daniel-shuy Date: Tue, 7 Jun 2022 23:52:10 +0800 Subject: [PATCH 2/2] Support Spring Data Sort and @SortDefault --- .../java/org/springdoc/core/Constants.java | 5 + .../core/SpringDocConfigProperties.java | 52 ++++ .../core/SpringDocConfiguration.java | 39 +++ .../core/converters/SortOpenAPIConverter.java | 86 ++++++ .../core/converters/models/Sort.java | 107 +++++++ ...stDelegatingMethodParameterCustomizer.java | 87 +++++- .../springdoc/api/app31/HelloController.java | 68 +++++ .../org/springdoc/api/app31/PersonDTO.java | 63 ++++ .../api/app31/SpringDocApp31Test.java | 35 +++ .../springdoc/api/app32/HelloController.java | 37 +++ .../org/springdoc/api/app32/PersonDTO.java | 63 ++++ .../api/app32/SpringDocApp32Test.java | 59 ++++ .../org/springdoc/api/app33/ExampleSort.java | 18 ++ .../api/app33/ExampleSortReplacement.java | 28 ++ .../springdoc/api/app33/HelloController.java | 17 ++ .../api/app33/SpringDocApp33Test.java | 33 +++ .../src/test/resources/results/app24.json | 8 +- .../src/test/resources/results/app27.json | 6 +- .../src/test/resources/results/app31.json | 275 ++++++++++++++++++ .../src/test/resources/results/app32.json | 78 +++++ .../src/test/resources/results/app33.json | 55 ++++ .../api/v30/app189/HelloController.java | 74 +++++ .../springdoc/api/v30/app189/PersonDTO.java | 67 +++++ .../api/v30/app189/SpringDocApp189Test.java | 34 +++ .../test/resources/results/3.0.1/app189.json | 275 ++++++++++++++++++ 25 files changed, 1649 insertions(+), 20 deletions(-) create mode 100644 springdoc-openapi-common/src/main/java/org/springdoc/core/converters/SortOpenAPIConverter.java create mode 100644 springdoc-openapi-common/src/main/java/org/springdoc/core/converters/models/Sort.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/HelloController.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/PersonDTO.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/SpringDocApp31Test.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/HelloController.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/PersonDTO.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/SpringDocApp32Test.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSort.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSortReplacement.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/HelloController.java create mode 100644 springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/SpringDocApp33Test.java create mode 100644 springdoc-openapi-data-rest/src/test/resources/results/app31.json create mode 100644 springdoc-openapi-data-rest/src/test/resources/results/app32.json create mode 100644 springdoc-openapi-data-rest/src/test/resources/results/app33.json create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/HelloController.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/PersonDTO.java create mode 100644 springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/SpringDocApp189Test.java create mode 100644 springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app189.json diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/Constants.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/Constants.java index 73b5218b6..3e6b0e172 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/Constants.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/Constants.java @@ -97,6 +97,11 @@ public final class Constants { */ public static final String SPRINGDOC_POLYMORPHIC_CONVERTER_ENABLED = "springdoc.model-converters.polymorphic-converter.enabled"; + /** + * The constant SPRINGDOC_SORT_CONVERTER_ENABLED. + */ + public static final String SPRINGDOC_SORT_CONVERTER_ENABLED = "springdoc.model-converters.sort-converter.enabled"; + /** * The constant SPRINGDOC_SCHEMA_RESOLVE_PROPERTIES. */ diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java index 1787f7bf4..4ac0c258c 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java @@ -717,6 +717,10 @@ public static class ModelConverters { */ private PolymorphicConverter polymorphicConverter = new PolymorphicConverter(); + /** + * The Sort converter. + */ + private SortConverter sortConverter = new SortConverter(); /** * Gets deprecating converter. @@ -772,6 +776,24 @@ public void setPolymorphicConverter(PolymorphicConverter polymorphicConverter) { this.polymorphicConverter = polymorphicConverter; } + /** + * Gets sort converter. + * + * @return the sort converter + */ + public SortConverter getSortConverter() { + return sortConverter; + } + + /** + * Sets sort converter. + * + * @param sortConverter the sort converter + */ + public void setSortConverter(SortConverter sortConverter) { + this.sortConverter = sortConverter; + } + /** * The type Deprecating converter. * @author bnasslashen @@ -861,6 +883,36 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } } + + /** + * The type Sort converter. + * @author daniel-shuy + */ + public static class SortConverter { + + /** + * The Enabled. + */ + private boolean enabled; + + /** + * Is enabled boolean. + * + * @return the boolean + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Sets enabled. + * + * @param enabled the enabled + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } } /** diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java index 9b780be72..f0f5b26e5 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java @@ -47,6 +47,7 @@ import org.springdoc.core.converters.PropertyCustomizingConverter; import org.springdoc.core.converters.ResponseSupportConverter; import org.springdoc.core.converters.SchemaPropertyDeprecatingConverter; +import org.springdoc.core.converters.SortOpenAPIConverter; import org.springdoc.core.customizers.ActuatorOpenApiCustomizer; import org.springdoc.core.customizers.ActuatorOperationCustomizer; import org.springdoc.core.customizers.DataRestDelegatingMethodParameterCustomizer; @@ -91,6 +92,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -107,6 +109,7 @@ import static org.springdoc.core.Constants.SPRINGDOC_SCHEMA_RESOLVE_PROPERTIES; import static org.springdoc.core.Constants.SPRINGDOC_SHOW_ACTUATOR; import static org.springdoc.core.Constants.SPRINGDOC_SHOW_SPRING_CLOUD_FUNCTIONS; +import static org.springdoc.core.Constants.SPRINGDOC_SORT_CONVERTER_ENABLED; import static org.springdoc.core.SpringDocUtils.getConfig; /** @@ -537,6 +540,42 @@ DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer(Optional } } + /** + * The type Spring doc sort configuration. + */ + @ConditionalOnClass(Sort.class) + static class SpringDocSortConfiguration { + + /** + * Sort open api converter. + * + * @param objectMapperProvider the object mapper provider + * @return the sort open api converter + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = SPRINGDOC_SORT_CONVERTER_ENABLED, matchIfMissing = true) + @Lazy(false) + SortOpenAPIConverter sortOpenAPIConverter(ObjectMapperProvider objectMapperProvider) { + getConfig().replaceParameterObjectWithClass(org.springframework.data.domain.Sort.class, org.springdoc.core.converters.models.Sort.class); + return new SortOpenAPIConverter(objectMapperProvider); + } + + /** + * Delegating method parameter customizer delegating method parameter customizer. + * + * @param optionalSpringDataWebPropertiesProvider the optional spring data web properties + * @param optionalRepositoryRestConfiguration the optional repository rest configuration + * @return the delegating method parameter customizer + */ + @Bean + @ConditionalOnMissingBean + @Lazy(false) + DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer(Optional optionalSpringDataWebPropertiesProvider, Optional optionalRepositoryRestConfiguration) { + return new DataRestDelegatingMethodParameterCustomizer(optionalSpringDataWebPropertiesProvider, optionalRepositoryRestConfiguration); + } + } + /** * The type Spring doc spring data web properties provider. */ diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/SortOpenAPIConverter.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/SortOpenAPIConverter.java new file mode 100644 index 000000000..af8888280 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/SortOpenAPIConverter.java @@ -0,0 +1,86 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2022 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.converters; + +import java.util.Iterator; + +import com.fasterxml.jackson.databind.JavaType; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.converters.models.Sort; +import org.springdoc.core.providers.ObjectMapperProvider; + +/** + * The Spring Data Sort type model converter. + * @author daniel-shuy + */ +public class SortOpenAPIConverter implements ModelConverter { + + private static final String SORT_TO_REPLACE = "org.springframework.data.domain.Sort"; + + /** + * The constant SORT. + */ + private static final AnnotatedType SORT = new AnnotatedType(Sort.class).resolveAsRef(true); + + /** + * The Spring doc object mapper. + */ + private final ObjectMapperProvider springDocObjectMapper; + + /** + * Instantiates a new Sort open api converter. + * + * @param springDocObjectMapper the spring doc object mapper + */ + public SortOpenAPIConverter(ObjectMapperProvider springDocObjectMapper) { + this.springDocObjectMapper = springDocObjectMapper; + } + + /** + * Resolve schema. + * + * @param type the type + * @param context the context + * @param chain the chain + * @return the schema + */ + @Override + public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { + JavaType javaType = springDocObjectMapper.jsonMapper().constructType(type.getType()); + if (javaType != null) { + Class cls = javaType.getRawClass(); + if (SORT_TO_REPLACE.equals(cls.getCanonicalName())) { + if (!type.isSchemaProperty()) + type = SORT; + else + type.name(cls.getSimpleName() + StringUtils.capitalize(type.getParent().getType())); + } + } + return (chain.hasNext()) ? chain.next().resolve(type, context, chain) : null; + } + +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/models/Sort.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/models/Sort.java new file mode 100644 index 000000000..70d4a2145 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/converters/models/Sort.java @@ -0,0 +1,107 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2022 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.converters.models; + +import java.util.List; +import java.util.Objects; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * The Sort type. + * @author daniel-shuy + */ +public class Sort { + + /** + * The Sort. + */ + @Parameter(description = "Sorting criteria in the format: property,(asc|desc). " + + "Default sort order is ascending. " + "Multiple sort criteria are supported." + , name = "sort" + , array = @ArraySchema(schema = @Schema(type = "string"))) + private List sort; + + /** + * Instantiates a new Sort. + * + * @param sort the sort + */ + public Sort(List sort) { + this.sort = sort; + } + + /** + * Gets sort. + * + * @return the sort + */ + public List getSort() { + return sort; + } + + /** + * Sets sort. + * + * @param sort the sort + */ + public void setSort(List sort) { + if (sort == null) { + this.sort.clear(); + } + else { + this.sort = sort; + } + } + + /** + * Add sort. + * + * @param sort the sort + */ + public void addSort(String sort) { + this.sort.add(sort); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Sort sort = (Sort) o; + return Objects.equals(this.sort, sort.sort); + } + + @Override + public int hashCode() { + return Objects.hash(sort); + } + + @Override + public String toString() { + return "Sort{" + + "sort=" + sort + + '}'; + } +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java index 646655774..45311380b 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/DataRestDelegatingMethodParameterCustomizer.java @@ -46,7 +46,10 @@ import org.springdoc.core.providers.SpringDataWebPropertiesProvider; import org.springframework.core.MethodParameter; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.SortDefault; /** * The type Data rest delegating method parameter customizer. @@ -85,14 +88,19 @@ public DataRestDelegatingMethodParameterCustomizer(Optional parameterType = originalParameter.getParameterType(); + if (pageableDefault != null || sortDefault != null || ( + (Pageable.class.isAssignableFrom(parameterType) || Sort.class.isAssignableFrom(parameterType)) + && (isSpringDataWebPropertiesPresent() || isRepositoryRestConfigurationPresent()) + )) { Field field = FieldUtils.getDeclaredField(DelegatingMethodParameter.class, "additionalParameterAnnotations", true); try { Annotation[] parameterAnnotations = (Annotation[]) field.get(methodParameter); if (ArrayUtils.isNotEmpty(parameterAnnotations)) for (int i = 0; i < parameterAnnotations.length; i++) { if (Parameter.class.equals(parameterAnnotations[i].annotationType())) { - Optional annotationForField = getNewParameterAnnotationForField(methodParameter, pageableDefault); + Optional annotationForField = getNewParameterAnnotationForField(methodParameter, pageableDefault, sortDefault); if (annotationForField.isPresent()) parameterAnnotations[i] = annotationForField.get(); } @@ -111,7 +119,7 @@ public void customize(MethodParameter originalParameter, MethodParameter methodP * @param pageableDefault the pageable default * @return the new parameter annotation for field */ - private Optional getNewParameterAnnotationForField(MethodParameter methodParameter, PageableDefault pageableDefault) { + private Optional getNewParameterAnnotationForField(MethodParameter methodParameter, PageableDefault pageableDefault, SortDefault sortDefault) { String parameterName = methodParameter.getParameterName(); Field field; Parameter parameterNew; @@ -166,7 +174,7 @@ public boolean writeOnly() { @Override public String defaultValue() { - return getArrayDefaultValue(parameterName, pageableDefault, schema.defaultValue()); + return getArrayDefaultValue(parameterName, pageableDefault, sortDefault, schema.defaultValue()); } }; } @@ -216,6 +224,7 @@ else if (isSpringDataWebPropertiesPresent()) name = originalName; break; case "direction": + case "caseSensitive": name = originalName; break; default: @@ -277,25 +286,67 @@ else if (isSpringDataWebPropertiesPresent()) * * @param parameterName the parameter name * @param pageableDefault the pageable default + * @param sortDefault the sort default * @param defaultSchemaVal the default schema val * @return the default value */ - private String getArrayDefaultValue(String parameterName, PageableDefault pageableDefault, String defaultSchemaVal) { + private String getArrayDefaultValue(String parameterName, PageableDefault pageableDefault, SortDefault sortDefault, String defaultSchemaVal) { String defaultValue = defaultSchemaVal; - if ("sort".equals(parameterName) && pageableDefault != null && ArrayUtils.isNotEmpty(pageableDefault.sort())) { - List sortValues = new ArrayList<>(); - for (String sortValue : pageableDefault.sort()) { - String sortStr = String.join(",", sortValue, pageableDefault.direction().name()); - sortValues.add(sortStr); + if ("sort".equals(parameterName)) { + DefaultSort defaultSort = getDefaultSort(pageableDefault, sortDefault); + if (defaultSort != null && ArrayUtils.isNotEmpty(defaultSort.properties)) { + List sortValues = new ArrayList<>(); + for (String sortValue : defaultSort.properties) { + String sortStr = String.join(",", sortValue, defaultSort.direction.name()); + sortValues.add(sortStr); + } + try { + defaultValue = ObjectMapperFactory.buildStrictGenericObjectMapper().writeValueAsString(sortValues); + } catch (JsonProcessingException e) { + LOGGER.warn(e.getMessage()); + } } + } + return defaultValue; + } + + /** + * Gets default sort. + * + * @param pageableDefault the pageable default + * @param sortDefault the sort default + * @return the default sort + */ + private DefaultSort getDefaultSort(PageableDefault pageableDefault, SortDefault sortDefault) { + if (sortDefault != null) { + // "sort" is aliased as "value" + String[] sortProperties = sortDefault.sort(); + Object defaultSort; try { - defaultValue = ObjectMapperFactory.buildStrictGenericObjectMapper().writeValueAsString(sortValues); + defaultSort = SortDefault.class.getMethod("sort").getDefaultValue(); + } catch (NoSuchMethodException e) { + LOGGER.warn(e.getMessage()); + defaultSort = null; + } + if (!Objects.deepEquals(sortProperties, defaultSort)) { + return new DefaultSort(sortDefault.direction(), sortProperties); } - catch (JsonProcessingException e) { + sortProperties = sortDefault.value(); + try { + defaultSort = SortDefault.class.getMethod("value").getDefaultValue(); + } catch (NoSuchMethodException e) { LOGGER.warn(e.getMessage()); + defaultSort = null; + } + if (!Objects.deepEquals(sortProperties, defaultSort)) { + return new DefaultSort(sortDefault.direction(), sortProperties); } } - return defaultValue; + // @SortDefault has higher priority than @PageableDefault + if (pageableDefault != null) { + return new DefaultSort(pageableDefault.direction(), pageableDefault.sort()); + } + return null; } /** @@ -315,4 +366,14 @@ private boolean isSpringDataWebPropertiesPresent() { private boolean isRepositoryRestConfigurationPresent() { return optionalRepositoryRestConfigurationProvider.isPresent() && optionalRepositoryRestConfigurationProvider.get().isRepositoryRestConfigurationPresent(); } + + private static class DefaultSort { + private final Sort.Direction direction; + private final String[] properties; + + DefaultSort(Sort.Direction direction, String... properties) { + this.direction = direction; + this.properties = properties; + } + } } diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/HelloController.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/HelloController.java new file mode 100644 index 000000000..7ed01a040 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/HelloController.java @@ -0,0 +1,68 @@ +/* + * + * * Copyright 2019-2020 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.app31; + +import org.springdoc.api.annotations.ParameterObject; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.web.SortDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class HelloController { + + @GetMapping(value = "/search", produces = { "application/xml", "application/json" }) + public ResponseEntity> getAllPets(@SortDefault("name") @ParameterObject Sort sort) { + return null; + } + + + @GetMapping("/test1") + public String getPatientList1(@SortDefault(sort = { "someField", "someoTHER" }, + direction = Direction.DESC) + @ParameterObject Sort sort) { + return "bla"; + } + + @GetMapping("/test2") + public String getPatientList2(@SortDefault(sort = "someField", + direction = Direction.DESC) + @ParameterObject Sort sort) { + return "bla"; + } + + @GetMapping("/test3") + public String getPatientList3(@SortDefault(sort = { "someField", "someoTHER" }, + direction = Direction.DESC) + @ParameterObject Pageable pageable) { + return "bla"; + } + + @GetMapping("/test4") + public String getPatientList4(@SortDefault(sort = "someField", + direction = Direction.DESC) + @ParameterObject Pageable pageable) { + return "bla"; + } +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/PersonDTO.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/PersonDTO.java new file mode 100644 index 000000000..203895d69 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/PersonDTO.java @@ -0,0 +1,63 @@ +/* + * + * * Copyright 2019-2020 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.app31; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema +public class PersonDTO { + private String email; + + private String firstName; + + private String lastName; + + public PersonDTO() { + } + + public PersonDTO(final String email, final String firstName, final String lastName) { + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(final String email) { + this.email = email; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(final String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(final String lastName) { + this.lastName = lastName; + } +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/SpringDocApp31Test.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/SpringDocApp31Test.java new file mode 100644 index 000000000..2002137d5 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app31/SpringDocApp31Test.java @@ -0,0 +1,35 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2020 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.app31; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import test.org.springdoc.api.AbstractSpringDocTest; + +public class SpringDocApp31Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp {} + + +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/HelloController.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/HelloController.java new file mode 100644 index 000000000..10a6ae139 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/HelloController.java @@ -0,0 +1,37 @@ +/* + * + * * Copyright 2019-2020 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.app32; + +import org.springdoc.api.annotations.ParameterObject; +import org.springframework.data.domain.Sort; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class HelloController { + + @GetMapping(value = "/search", produces = { "application/xml", "application/json" }) + public ResponseEntity> getAllPets(@ParameterObject Sort sort) { + return null; + } + +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/PersonDTO.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/PersonDTO.java new file mode 100644 index 000000000..519f89a37 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/PersonDTO.java @@ -0,0 +1,63 @@ +/* + * + * * Copyright 2019-2020 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.app32; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema +public class PersonDTO { + private String email; + + private String firstName; + + private String lastName; + + public PersonDTO() { + } + + public PersonDTO(final String email, final String firstName, final String lastName) { + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(final String email) { + this.email = email; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(final String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(final String lastName) { + this.lastName = lastName; + } +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/SpringDocApp32Test.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/SpringDocApp32Test.java new file mode 100644 index 000000000..f3ab7d925 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app32/SpringDocApp32Test.java @@ -0,0 +1,59 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2020 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.app32; + +import org.springdoc.core.customizers.DataRestDelegatingMethodParameterCustomizer; +import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer; +import org.springdoc.core.providers.RepositoryRestConfigurationProvider; +import org.springdoc.core.providers.SpringDataWebPropertiesProvider; +import org.springdoc.data.rest.SpringDocDataRestConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; +import org.springframework.test.context.TestPropertySource; +import test.org.springdoc.api.AbstractSpringDocTest; + +import java.util.Optional; + +@TestPropertySource(properties = "spring.data.web.sort.sort-parameter=sorts") +@EnableAutoConfiguration(exclude = { + RepositoryRestMvcAutoConfiguration.class, SpringDocDataRestConfiguration.class +}) +public class SpringDocApp32Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp { + // We only need to test spring-web with Sort, without the use of spring-data-rest-starter + @Bean + @ConditionalOnMissingBean + @Lazy(false) + DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer(Optional optionalSpringDataWebPropertiesProvider, Optional optionalRepositoryRestConfiguration) { + return new DataRestDelegatingMethodParameterCustomizer(optionalSpringDataWebPropertiesProvider, optionalRepositoryRestConfiguration); + } + } + +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSort.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSort.java new file mode 100644 index 000000000..d5b8d2f65 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSort.java @@ -0,0 +1,18 @@ +package test.org.springdoc.api.app33; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import org.springframework.data.domain.Sort; + +import java.util.List; + +public class ExampleSort extends Sort { + + @Parameter(description = "Anything") + @JsonProperty + private int something; + + protected ExampleSort(List orders) { + super(orders); + } +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSortReplacement.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSortReplacement.java new file mode 100644 index 000000000..fdf3341e5 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/ExampleSortReplacement.java @@ -0,0 +1,28 @@ +package test.org.springdoc.api.app33; + +import io.swagger.v3.oas.annotations.Parameter; +import org.springdoc.core.converters.models.Sort; + +import java.util.List; + +public class ExampleSortReplacement extends Sort { + + @Parameter(description = "Anything") + private int something; + + /** + * Instantiates a new Sort. + * @param sort the sort + */ + public ExampleSortReplacement(List sort) { + super(sort); + } + + public int getSomething() { + return something; + } + + public void setSomething(int something) { + this.something = something; + } +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/HelloController.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/HelloController.java new file mode 100644 index 000000000..f9725bf0f --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/HelloController.java @@ -0,0 +1,17 @@ +package test.org.springdoc.api.app33; + +import org.springdoc.api.annotations.ParameterObject; +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 HelloController { + + + @GetMapping("/items/nested") + public void showNestedItem(@ParameterObject ExampleSort exampleSort) { + } + +} diff --git a/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/SpringDocApp33Test.java b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/SpringDocApp33Test.java new file mode 100644 index 000000000..65b5c14ef --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app33/SpringDocApp33Test.java @@ -0,0 +1,33 @@ +/* + * + * * Copyright 2019-2020 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.app33; + +import org.springdoc.core.SpringDocUtils; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import test.org.springdoc.api.AbstractSpringDocTest; + +public class SpringDocApp33Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp {} + + static { + SpringDocUtils.getConfig().replaceParameterObjectWithClass(ExampleSort.class, ExampleSortReplacement.class); + } +} diff --git a/springdoc-openapi-data-rest/src/test/resources/results/app24.json b/springdoc-openapi-data-rest/src/test/resources/results/app24.json index 039e6a160..df767bc53 100644 --- a/springdoc-openapi-data-rest/src/test/resources/results/app24.json +++ b/springdoc-openapi-data-rest/src/test/resources/results/app24.json @@ -112,7 +112,7 @@ "$ref": "#/components/schemas/PageableObject" }, "sort": { - "$ref": "#/components/schemas/Sort" + "$ref": "#/components/schemas/SortObject" }, "first": { "type": "boolean" @@ -141,7 +141,7 @@ "format": "int32" }, "sort": { - "$ref": "#/components/schemas/Sort" + "$ref": "#/components/schemas/SortObject" }, "unpaged": { "type": "boolean" @@ -151,7 +151,7 @@ } } }, - "Sort": { + "SortObject": { "type": "object", "properties": { "sorted": { @@ -185,4 +185,4 @@ } } } -} \ No newline at end of file +} diff --git a/springdoc-openapi-data-rest/src/test/resources/results/app27.json b/springdoc-openapi-data-rest/src/test/resources/results/app27.json index 9639df61c..e1b282565 100644 --- a/springdoc-openapi-data-rest/src/test/resources/results/app27.json +++ b/springdoc-openapi-data-rest/src/test/resources/results/app27.json @@ -77,11 +77,11 @@ "format": "int64" }, "sort": { - "$ref": "#/components/schemas/Sort" + "$ref": "#/components/schemas/SortObject" } } }, - "Sort": { + "SortObject": { "type": "object", "properties": { "sorted": { @@ -111,4 +111,4 @@ } } } -} \ No newline at end of file +} diff --git a/springdoc-openapi-data-rest/src/test/resources/results/app31.json b/springdoc-openapi-data-rest/src/test/resources/results/app31.json new file mode 100644 index 000000000..57ed8bdba --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/resources/results/app31.json @@ -0,0 +1,275 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/test4": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList4", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Zero-based page index (0..N)", + "required": false, + "schema": { + "minimum": 0, + "type": "integer", + "default": 0 + } + }, + { + "name": "size", + "in": "query", + "description": "The size of the page to be returned", + "required": false, + "schema": { + "minimum": 1, + "type": "integer", + "default": 20 + } + }, + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/hal+json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/test3": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList3", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Zero-based page index (0..N)", + "required": false, + "schema": { + "minimum": 0, + "type": "integer", + "default": 0 + } + }, + { + "name": "size", + "in": "query", + "description": "The size of the page to be returned", + "required": false, + "schema": { + "minimum": 1, + "type": "integer", + "default": 20 + } + }, + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC", + "someoTHER,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/hal+json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/test2": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList2", + "parameters": [ + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/hal+json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/test1": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList1", + "parameters": [ + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC", + "someoTHER,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/hal+json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/search": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getAllPets", + "parameters": [ + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "name,ASC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonDTO" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonDTO" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "PersonDTO": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } + } +} diff --git a/springdoc-openapi-data-rest/src/test/resources/results/app32.json b/springdoc-openapi-data-rest/src/test/resources/results/app32.json new file mode 100644 index 000000000..be8237f8b --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/resources/results/app32.json @@ -0,0 +1,78 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/search": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getAllPets", + "parameters": [ + { + "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", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonDTO" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonDTO" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "PersonDTO": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } + } +} diff --git a/springdoc-openapi-data-rest/src/test/resources/results/app33.json b/springdoc-openapi-data-rest/src/test/resources/results/app33.json new file mode 100644 index 000000000..728c13aa5 --- /dev/null +++ b/springdoc-openapi-data-rest/src/test/resources/results/app33.json @@ -0,0 +1,55 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/api/items/nested": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "showNestedItem", + "parameters": [ + { + "name": "something", + "in": "query", + "description": "Anything", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "sort", + "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", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": {} + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/HelloController.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/HelloController.java new file mode 100644 index 000000000..018cd9dd2 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/HelloController.java @@ -0,0 +1,74 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2022 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.app189; + +import org.springdoc.api.annotations.ParameterObject; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.SortDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import test.org.springdoc.api.v30.app13.PersonDTO; + +import java.util.List; + +@RestController +public class HelloController { + + @GetMapping(value = "/search", produces = { "application/xml", "application/json" }) + public ResponseEntity> getAllPets(@SortDefault("name") @ParameterObject Sort sort) { + return null; + } + + + @GetMapping("/test1") + public String getPatientList1(@SortDefault(sort = { "someField", "someoTHER" }, + direction = Direction.DESC) + @ParameterObject Sort sort) { + return "bla"; + } + + @GetMapping("/test2") + public String getPatientList2(@SortDefault(sort = "someField", + direction = Direction.DESC) + @ParameterObject Sort sort) { + return "bla"; + } + + @GetMapping("/test3") + public String getPatientList3(@SortDefault(sort = { "someField", "someoTHER" }, + direction = Direction.DESC) + @ParameterObject Pageable pageable) { + return "bla"; + } + + @GetMapping("/test4") + public String getPatientList4(@SortDefault(sort = "someField", + direction = Direction.DESC) + @ParameterObject Pageable pageable) { + return "bla"; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/PersonDTO.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/PersonDTO.java new file mode 100644 index 000000000..bb7d09196 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/PersonDTO.java @@ -0,0 +1,67 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2022 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.app189; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema +public class PersonDTO { + private String email; + + private String firstName; + + private String lastName; + + public PersonDTO() { + } + + public PersonDTO(final String email, final String firstName, final String lastName) { + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(final String email) { + this.email = email; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(final String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(final String lastName) { + this.lastName = lastName; + } +} diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/SpringDocApp189Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/SpringDocApp189Test.java new file mode 100644 index 000000000..bbf57ce7d --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v30/app189/SpringDocApp189Test.java @@ -0,0 +1,34 @@ +/* + * + * * + * * * + * * * * Copyright 2019-2022 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.app189; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +public class SpringDocApp189Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} + + +} diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app189.json b/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app189.json new file mode 100644 index 000000000..c7c1d4e06 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/3.0.1/app189.json @@ -0,0 +1,275 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + } + ], + "paths": { + "/test4": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList4", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Zero-based page index (0..N)", + "required": false, + "schema": { + "minimum": 0, + "type": "integer", + "default": 0 + } + }, + { + "name": "size", + "in": "query", + "description": "The size of the page to be returned", + "required": false, + "schema": { + "minimum": 1, + "type": "integer", + "default": 20 + } + }, + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/test3": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList3", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Zero-based page index (0..N)", + "required": false, + "schema": { + "minimum": 0, + "type": "integer", + "default": 0 + } + }, + { + "name": "size", + "in": "query", + "description": "The size of the page to be returned", + "required": false, + "schema": { + "minimum": 1, + "type": "integer", + "default": 20 + } + }, + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC", + "someoTHER,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/test2": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList2", + "parameters": [ + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/test1": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getPatientList1", + "parameters": [ + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "someField,DESC", + "someoTHER,DESC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/search": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "getAllPets", + "parameters": [ + { + "name": "sort", + "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", + "items": { + "type": "string" + }, + "default": [ + "name,ASC" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonDTO" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonDTO" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "PersonDTO": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } + } +}