From 7a24b188ea9cce78454ca1e19ca13f034a6f20f6 Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Tue, 10 Oct 2023 22:45:35 +0300 Subject: [PATCH 1/9] Added augmentation for @FormParam default values --- .../openapi/api/models/media/SchemaImpl.java | 6 +- .../spi/AbstractParameterProcessor.java | 40 ++++- .../runtime/scanner/ParameterScanTests.java | 9 ++ .../DefaultEnumBeanParamTestResource.java | 137 ++++++++++++++++++ ...ms.local-schema-attributes-bean-param.json | 60 ++++++++ 5 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json diff --git a/core/src/main/java/io/smallrye/openapi/api/models/media/SchemaImpl.java b/core/src/main/java/io/smallrye/openapi/api/models/media/SchemaImpl.java index 83407560f..c6e618422 100644 --- a/core/src/main/java/io/smallrye/openapi/api/models/media/SchemaImpl.java +++ b/core/src/main/java/io/smallrye/openapi/api/models/media/SchemaImpl.java @@ -96,7 +96,7 @@ public static SchemaImpl copyOf(Schema other) { .map(SchemaImpl::copyOf) .collect(Collectors.toList())); - clone.properties = copy(clone.properties, () -> clone.properties.entrySet() + Supplier> sup = () -> clone.properties.entrySet() .stream() .collect(Collectors.toMap( Map.Entry::getKey, @@ -104,7 +104,9 @@ public static SchemaImpl copyOf(Schema other) { (u, v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }, - LinkedHashMap::new))); + LinkedHashMap::new)); + + clone.properties = copy(clone.properties, sup); clone.additionalPropertiesSchema = copy(clone.additionalPropertiesSchema, () -> copyOf(clone.additionalPropertiesSchema)); diff --git a/core/src/main/java/io/smallrye/openapi/runtime/scanner/spi/AbstractParameterProcessor.java b/core/src/main/java/io/smallrye/openapi/runtime/scanner/spi/AbstractParameterProcessor.java index d72d88313..36bbf90b4 100644 --- a/core/src/main/java/io/smallrye/openapi/runtime/scanner/spi/AbstractParameterProcessor.java +++ b/core/src/main/java/io/smallrye/openapi/runtime/scanner/spi/AbstractParameterProcessor.java @@ -686,7 +686,7 @@ protected void setSchemaProperties(Schema schema, } addEncoding(encodings, paramName, paramTarget); - setDefaultValue(paramSchema, getDefaultValue(paramTarget)); + paramSchema = augmentFormParamSchema(paramSchema, paramType, getDefaultValue(paramTarget)); TypeUtil.mapDeprecated(paramTarget, paramSchema::getDeprecated, paramSchema::setDeprecated); if (beanValidationScanner.isPresent()) { @@ -708,6 +708,44 @@ protected void setSchemaProperties(Schema schema, } } + /** + * Set default value for @FormParam if any. Updates param's schema either directly or, + * when a ref is present, by creating a union of the local and reference schemas + * using allOf. + * + * @param paramSchema the Parameter containing a schema for update + * @param paramType Type associated with param + */ + Schema augmentFormParamSchema(Schema paramSchema, Type paramType, Object defaultValue) { + String ref = paramSchema.getRef(); + Schema localSchema; + + if (ref != null) { + /* + * Lookup the schema `type` from components (if available) or guess the type if + * the `ref` is not available. + */ + Schema refSchema = ModelUtil.getComponent(scannerContext.getOpenApi(), ref); + + if (refSchema != null) { + localSchema = new SchemaImpl().type(refSchema.getType()); + } else { + localSchema = new SchemaImpl().type(SchemaType + .valueOf(TypeUtil.getTypeAttributes(paramType).get(SchemaConstant.PROP_TYPE).toString().toUpperCase())); + } + } else { + localSchema = paramSchema; + } + + int modCount = SchemaImpl.getModCount(localSchema); + setDefaultValue(localSchema, defaultValue); + if (localOnlySchemaModified(paramSchema, localSchema, modCount)) { + // Add new `allOf` schema, erasing `type` derived above from the local schema + return new SchemaImpl().addAllOf(paramSchema).addAllOf(localSchema.type(null)); + } + return paramSchema; + } + /** * Called by the BeanValidationScanner when a member is found to have a BV annotation * indicating the parameter is required. diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java index 625db8b71..30eb0f0b0 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java @@ -28,6 +28,7 @@ import io.smallrye.openapi.api.OpenApiConfig; import test.io.smallrye.openapi.runtime.scanner.Widget; +import test.io.smallrye.openapi.runtime.scanner.jakarta.DefaultEnumBeanParamTestResource; import test.io.smallrye.openapi.runtime.scanner.jakarta.MultipleContentTypesWithFormParamsTestResource; /** @@ -457,6 +458,14 @@ void testJakartaDefaultEnumValue() throws IOException, JSONException { test.io.smallrye.openapi.runtime.scanner.jakarta.DefaultEnumTestResource.MyEnum.class); } + @Test + void testJakartaDefaultBeanParamEnumValue() throws IOException, JSONException { + test("params.local-schema-attributes-bean-param.json", + test.io.smallrye.openapi.runtime.scanner.jakarta.DefaultEnumBeanParamTestResource.class, + DefaultEnumBeanParamTestResource.UserGroupDto.class, + DefaultEnumBeanParamTestResource.UserGroupSubtype.class); + } + @Test void testJavaxGenericTypeVariableResource() throws IOException, JSONException { test("params.generic-type-variables.json", test.io.smallrye.openapi.runtime.scanner.javax.BaseGenericResource.class, diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java new file mode 100644 index 000000000..c52134342 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java @@ -0,0 +1,137 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import java.io.InputStream; + +@Path(value = "/enum-default-bean-param") +public class DefaultEnumBeanParamTestResource { + + public static class UserGroupDto { + @FormParam("sql") + private String sql; + @FormParam("contactSourceType") + private Integer contactSourceType; + @FormParam("archivationTime") + private String archivationTime; + @FormParam("type") + private String type; + @FormParam("employerIdsText") + @DefaultValue("EMAIL_BY_SQL") + private String employerIdsText; + @FormParam("formType") + @DefaultValue("EMAIL_BY_EXTERNAL_EMAIL_SOURCES") + private UserGroupSubtype formType; + @FormParam("externalEmailSourceCode") + private String externalEmailSourceCode; + @FormParam("externalEmailPandoraDoiCode") + private String externalEmailPandoraDoiCode; + @JsonIgnore + @FormParam("file") + private InputStream inputStream; + + public UserGroupDto() { + } + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public Integer getContactSourceType() { + return contactSourceType; + } + + public void setContactSourceType(Integer contactSourceType) { + this.contactSourceType = contactSourceType; + } + + public String getArchivationTime() { + return archivationTime; + } + + public void setArchivationTime(String archivationTime) { + this.archivationTime = archivationTime; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getEmployerIdsText() { + return employerIdsText; + } + + public void setEmployerIdsText(String employerIdsText) { + this.employerIdsText = employerIdsText; + } + + public UserGroupSubtype getFormType() { + return formType; + } + + public void setFormType(UserGroupSubtype userGroupSubtype) { + this.formType = userGroupSubtype; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public String getExternalEmailSourceCode() { + return externalEmailSourceCode; + } + + public void setExternalEmailSourceCode(String externalEmailSourceCode) { + this.externalEmailSourceCode = externalEmailSourceCode; + } + + public String getExternalEmailPandoraDoiCode() { + return externalEmailPandoraDoiCode; + } + + public void setExternalEmailPandoraDoiCode(String externalEmailPandoraDoiCode) { + this.externalEmailPandoraDoiCode = externalEmailPandoraDoiCode; + } + + public boolean isFormOfType(UserGroupSubtype userGroupSubtype) { + return getFormType().equals(userGroupSubtype); + } + + } + + public enum UserGroupSubtype { + EMAIL_BY_SQL, + EMAIL_BY_EMPLOYERS, + EMAIL_BY_EXTERNAL_EMAIL_SOURCES, + SMS_BY_SQL, + PUSH_BY_SQL; + } + + + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response create(@BeanParam UserGroupDto str) { + return null; + } + +} diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json new file mode 100644 index 000000000..3961d2074 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json @@ -0,0 +1,60 @@ +{ + "openapi": "3.0.3", + "paths": { + "/enum-default-bean-param": { + "post": { + "parameters": [ + { + "name": "q0", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q1", + "in": "query", + "required": true, + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MyEnum" + }, + { + "default": "DOG", + "maxLength": 3, + "minLength": 3 + } + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "BeanEnum": { + "enum": [ + "CAT", + "DOG", + "BAR", + "FOO" + ], + "type": "string" + } + } + } +} From 567a998416cd5b10cd01a3e2c638e53281157810 Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Sat, 14 Oct 2023 21:07:52 +0300 Subject: [PATCH 2/9] Extended ExceptionMapper processor with hierarchy chains --- .../openapi/jaxrs/JaxRsAnnotationScanner.java | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java index af0d458d5..6af9cd390 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java @@ -6,7 +6,9 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Deque; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -29,6 +31,7 @@ import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.ClassType; import org.jboss.jandex.DotName; import org.jboss.jandex.MethodInfo; import org.jboss.jandex.Type; @@ -304,8 +307,7 @@ private Map> processExceptionMappers(final Ann Collection exceptionMappers = new ArrayList<>(); for (DotName dn : JaxRsConstants.EXCEPTION_MAPPER) { - exceptionMappers.addAll(context.getIndex() - .getKnownDirectImplementors(dn)); + exceptionMappers.addAll(traverseHierarchy(dn, context)); } return exceptionMappers.stream() @@ -313,16 +315,38 @@ private Map> processExceptionMappers(final Ann .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); } + private Collection traverseHierarchy(DotName root, AnnotationScannerContext context) { + FilteredIndexView index = context.getIndex(); + Map result = new LinkedHashMap<>(); + + Map knownDirectImplementors = index.getKnownDirectImplementors(root) + .stream().collect(Collectors.toMap(ClassInfo::name, Function.identity())); + result.putAll(knownDirectImplementors); + Map knownDirectSubclasses = index.getKnownDirectSubclasses(root) + .stream().collect(Collectors.toMap(ClassInfo::name, Function.identity())); + result.putAll(knownDirectSubclasses); + + for (DotName implementorName : knownDirectImplementors.keySet()) { + Collection classInfos = traverseHierarchy(implementorName, context); + classInfos.forEach(ci -> result.put(ci.name(), ci)); + } + + for (DotName subclassName : knownDirectSubclasses.keySet()) { + Collection classInfos = traverseHierarchy(subclassName, context); + classInfos.forEach(ci -> result.put(ci.name(), ci)); + } + + return result.values(); + } + private Stream>> exceptionResponseAnnotations(ClassInfo classInfo) { - Type exceptionType = classInfo.interfaceTypes() - .stream() - .filter(it -> JaxRsConstants.EXCEPTION_MAPPER.contains(it.name())) - .filter(it -> Type.Kind.PARAMETERIZED_TYPE.equals(it.kind())) - .map(Type::asParameterizedType) - .map(type -> type.arguments().get(0)) - .findAny() - .orElse(null); + Type exceptionType = classInfo.methods().stream() + .filter(m -> m.name().equals(JaxRsConstants.TO_RESPONSE_METHOD_NAME)) + // Remove bridge method, in our case E extends Throwable for ExceptionMapper + .filter(m -> !m.parameterTypes().contains(ClassType.create(Throwable.class.getCanonicalName()))) + .map(m -> m.parameterType(0)) + .findAny().orElse(null); if (exceptionType == null) { return Stream.empty(); From e90fc44c9b365287420f10d00707f7becd943700 Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Mon, 23 Oct 2023 12:08:02 +0300 Subject: [PATCH 3/9] Add Priority for exception mappers and change the way we derive generic type exception --- .../openapi/jaxrs/JaxRsAnnotationScanner.java | 61 +++++++++++-------- .../openapi/jaxrs/JaxRsConstants.java | 4 ++ .../smallrye/openapi/jaxrs/JaxRsFactory.java | 34 +++++++++++ 3 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsFactory.java diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java index 6af9cd390..4fa3f56ea 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java @@ -31,7 +31,6 @@ import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; -import org.jboss.jandex.ClassType; import org.jboss.jandex.DotName; import org.jboss.jandex.MethodInfo; import org.jboss.jandex.Type; @@ -307,15 +306,25 @@ private Map> processExceptionMappers(final Ann Collection exceptionMappers = new ArrayList<>(); for (DotName dn : JaxRsConstants.EXCEPTION_MAPPER) { - exceptionMappers.addAll(traverseHierarchy(dn, context)); + Collection hierarchyChain = obtainHierarchyChain(dn, context); + exceptionMappers.addAll(hierarchyChain); } + Map> exceptionAndMappers = groupByExceptionType(exceptionMappers); - return exceptionMappers.stream() - .flatMap(this::exceptionResponseAnnotations) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + Map> exceptionWithAnnotations = new LinkedHashMap<>(); + Comparator priorityComparator = JaxRsFactory.createPriorityComparator(); + for (Type exceptionType : exceptionAndMappers.keySet()) { + List eMappers = exceptionAndMappers.get(exceptionType); + + eMappers.sort(priorityComparator); + List annotations = exceptionWithAnnotations.computeIfAbsent(exceptionType.name(), (k) -> new ArrayList<>()); + annotations.addAll(exceptionResponseAnnotations(eMappers.get(0), exceptionType)); + } + + return exceptionWithAnnotations; } - private Collection traverseHierarchy(DotName root, AnnotationScannerContext context) { + private Collection obtainHierarchyChain(DotName root, AnnotationScannerContext context) { FilteredIndexView index = context.getIndex(); Map result = new LinkedHashMap<>(); @@ -327,31 +336,40 @@ private Collection traverseHierarchy(DotName root, AnnotationScannerC result.putAll(knownDirectSubclasses); for (DotName implementorName : knownDirectImplementors.keySet()) { - Collection classInfos = traverseHierarchy(implementorName, context); + Collection classInfos = obtainHierarchyChain(implementorName, context); classInfos.forEach(ci -> result.put(ci.name(), ci)); } for (DotName subclassName : knownDirectSubclasses.keySet()) { - Collection classInfos = traverseHierarchy(subclassName, context); + Collection classInfos = obtainHierarchyChain(subclassName, context); classInfos.forEach(ci -> result.put(ci.name(), ci)); } return result.values(); } - private Stream>> exceptionResponseAnnotations(ClassInfo classInfo) { + private Map> groupByExceptionType(Collection exceptionMappers) { + LinkedHashMap> result = new LinkedHashMap<>(); + for (ClassInfo exceptionMapper : exceptionMappers) { + Type exceptionType = exceptionMapper.methods().stream() + .filter(m -> m.name().equals(JaxRsConstants.TO_RESPONSE_METHOD_NAME)) + // Remove bridge methods, 0x00001000 is ACC_SYNTHETIC mask + .filter(m -> (m.flags() & 0x00001000) == 0) + // extract exception type, it is the only argument in contract + .map(m -> m.parameterType(0)) + .findAny().orElse(null); - Type exceptionType = classInfo.methods().stream() - .filter(m -> m.name().equals(JaxRsConstants.TO_RESPONSE_METHOD_NAME)) - // Remove bridge method, in our case E extends Throwable for ExceptionMapper - .filter(m -> !m.parameterTypes().contains(ClassType.create(Throwable.class.getCanonicalName()))) - .map(m -> m.parameterType(0)) - .findAny().orElse(null); + if (exceptionType == null) { + continue; + } - if (exceptionType == null) { - return Stream.empty(); + List classInfos = result.computeIfAbsent(exceptionType, (k) -> new ArrayList<>()); + classInfos.add(exceptionMapper); } + return result; + } + private List exceptionResponseAnnotations(ClassInfo classInfo, Type exceptionType) { Stream methodAnnotations = Stream .of(classInfo.method(JaxRsConstants.TO_RESPONSE_METHOD_NAME, exceptionType)) .filter(Objects::nonNull) @@ -360,16 +378,9 @@ private Stream>> exceptionResponseAnnota Stream classAnnotations = ResponseReader.getResponseAnnotations(classInfo).stream(); // Later annotations will eventually override earlier ones, so put class before method - List annotations = Stream - .concat(classAnnotations, methodAnnotations) + return Stream.concat(classAnnotations, methodAnnotations) .filter(ResponseReader::hasResponseCodeValue) .collect(Collectors.toList()); - - if (annotations.isEmpty()) { - return Stream.empty(); - } else { - return Stream.of(entryOf(exceptionType.name(), annotations)); - } } // Replace with Map.entry when available (Java 9+) diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsConstants.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsConstants.java index 6051a3ae8..2ca824288 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsConstants.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsConstants.java @@ -36,6 +36,9 @@ public class JaxRsConstants { static final Set EXCEPTION_MAPPER = new TreeSet<>(Arrays.asList( DotName.createSimple("javax.ws.rs.ext.ExceptionMapper"), DotName.createSimple("jakarta.ws.rs.ext.ExceptionMapper"))); + static final Set PRIORITY = new TreeSet<>(Arrays.asList( + DotName.createSimple("javax.annotation.Priority"), + DotName.createSimple("jakarta.annotation.Priority"))); static final Set QUERY_PARAM = new TreeSet<>(Arrays.asList( DotName.createSimple("javax.ws.rs.QueryParam"), DotName.createSimple("jakarta.ws.rs.QueryParam"))); @@ -104,6 +107,7 @@ public class JaxRsConstants { .collect(Collectors.toSet()); static final String TO_RESPONSE_METHOD_NAME = "toResponse"; + static final Integer PRIORITY_DEFAULT_VALUE = 5000; private static final Set methods = new LinkedHashSet<>(); static { diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsFactory.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsFactory.java new file mode 100644 index 000000000..3d2807946 --- /dev/null +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsFactory.java @@ -0,0 +1,34 @@ +package io.smallrye.openapi.jaxrs; + +import java.util.Comparator; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; + +public class JaxRsFactory { + + public static Comparator createPriorityComparator() { + return (first, second) -> { + Integer firstPriorityValue = JaxRsConstants.PRIORITY_DEFAULT_VALUE; + for (DotName dotName : JaxRsConstants.PRIORITY) { + AnnotationInstance annotation = first.annotation(dotName); + if (annotation == null) { + continue; + } + + firstPriorityValue = (Integer) annotation.value("value").value(); + } + + Integer secondPriorityValue = JaxRsConstants.PRIORITY_DEFAULT_VALUE; + for (DotName dotName : JaxRsConstants.PRIORITY) { + AnnotationInstance annotation = second.annotation(dotName); + if (annotation == null) { + continue; + } + secondPriorityValue = (Integer) annotation.value("value").value(); + } + + return firstPriorityValue.compareTo(secondPriorityValue); + }; + } +} From d46a0f6d9cf6ab00bac7fa9c1646255af903003e Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Mon, 23 Oct 2023 19:25:57 +0300 Subject: [PATCH 4/9] Configure build process with respect to hh nexus repository --- .github/project.yml | 2 +- core/pom.xml | 2 +- extension-jaxrs/pom.xml | 2 +- extension-spring/pom.xml | 2 +- extension-vertx/pom.xml | 2 +- implementation/pom.xml | 2 +- pom.xml | 42 +++++++++++++++++++++++++----------- release/pom.xml | 2 +- testsuite/data/pom.xml | 2 +- testsuite/extra/pom.xml | 2 +- testsuite/pom.xml | 2 +- testsuite/tck/pom.xml | 2 +- tools/gradle-plugin/pom.xml | 2 +- tools/maven-plugin/pom.xml | 2 +- tools/pom.xml | 2 +- ui/open-api-ui-forms/pom.xml | 2 +- ui/open-api-ui/pom.xml | 2 +- ui/pom.xml | 2 +- 18 files changed, 47 insertions(+), 29 deletions(-) diff --git a/.github/project.yml b/.github/project.yml index e6d2cb971..bb26e6a54 100644 --- a/.github/project.yml +++ b/.github/project.yml @@ -1,4 +1,4 @@ name: SmallRye OpenAPI release: current-version: 3.6.0 - next-version: 3.6.1-SNAPSHOT + next-version: 3.6.1-VB-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index b72b93aa3..c38523ad4 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-core diff --git a/extension-jaxrs/pom.xml b/extension-jaxrs/pom.xml index 7fae40e00..8c2992688 100644 --- a/extension-jaxrs/pom.xml +++ b/extension-jaxrs/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-jaxrs diff --git a/extension-spring/pom.xml b/extension-spring/pom.xml index 8d2df9995..134516eb6 100644 --- a/extension-spring/pom.xml +++ b/extension-spring/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-spring diff --git a/extension-vertx/pom.xml b/extension-vertx/pom.xml index 000aa73bb..100cda20d 100644 --- a/extension-vertx/pom.xml +++ b/extension-vertx/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-vertx diff --git a/implementation/pom.xml b/implementation/pom.xml index 4223ede44..e22ac5cf0 100644 --- a/implementation/pom.xml +++ b/implementation/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api diff --git a/pom.xml b/pom.xml index 33369e1dc..56669fd37 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT pom SmallRye: OpenAPI Parent @@ -50,13 +50,13 @@ GitHub - https://github.com/smallrye/smallrye-open-api/issues + https://github.com/vbazhmin/smallrye-open-api/issues - scm:git:git@github.com:smallrye/smallrye-open-api.git - scm:git:git@github.com:smallrye/smallrye-open-api.git - https://github.com/smallrye/smallrye-open-api/ + scm:git:git@github.com:vbazhmin/smallrye-open-api.git + scm:git:git@github.com:vbazhmin/smallrye-open-api.git + https://github.com/vbazhmin/smallrye-open-api/ HEAD @@ -71,17 +71,25 @@ tools + + + hh-snapshots + https://m2.hh.ru/content/repositories/snapshots/ + + + - ossrh - Sonatype OSSRH Snapshots - https://oss.sonatype.org/content/repositories/snapshots/ + hh-snapshots + hh public snapshots repository + https://m2.hh.ru/content/repositories/snapshots - false + false + fail - true - + true + @@ -344,6 +352,16 @@ + org.sonatype.plugins + nexus-staging-maven-plugin + true + + https://m2.hh.ru/ + hh + true + + + org.codehaus.mojo build-helper-maven-plugin diff --git a/release/pom.xml b/release/pom.xml index 46f7836a4..8ebcff697 100644 --- a/release/pom.xml +++ b/release/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-release diff --git a/testsuite/data/pom.xml b/testsuite/data/pom.xml index 2c0dbbc44..04349901a 100644 --- a/testsuite/data/pom.xml +++ b/testsuite/data/pom.xml @@ -9,7 +9,7 @@ smallrye-open-api-testsuite-data - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT SmallRye: OpenAPI Test Data diff --git a/testsuite/extra/pom.xml b/testsuite/extra/pom.xml index 39b3845a1..ef316c561 100644 --- a/testsuite/extra/pom.xml +++ b/testsuite/extra/pom.xml @@ -3,7 +3,7 @@ io.smallrye smallrye-open-api-testsuite - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT ../ diff --git a/testsuite/pom.xml b/testsuite/pom.xml index 945b43e45..d08022afa 100644 --- a/testsuite/pom.xml +++ b/testsuite/pom.xml @@ -20,7 +20,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-testsuite diff --git a/testsuite/tck/pom.xml b/testsuite/tck/pom.xml index ce9a4d12c..d8702d511 100644 --- a/testsuite/tck/pom.xml +++ b/testsuite/tck/pom.xml @@ -20,7 +20,7 @@ io.smallrye smallrye-open-api-testsuite - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-testsuite-tck diff --git a/tools/gradle-plugin/pom.xml b/tools/gradle-plugin/pom.xml index 02fd151b1..d428166ed 100644 --- a/tools/gradle-plugin/pom.xml +++ b/tools/gradle-plugin/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-open-api-tools - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-gradle-plugin pom diff --git a/tools/maven-plugin/pom.xml b/tools/maven-plugin/pom.xml index 44b34bb42..a5b7b2fd0 100644 --- a/tools/maven-plugin/pom.xml +++ b/tools/maven-plugin/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-open-api-tools - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-maven-plugin maven-plugin diff --git a/tools/pom.xml b/tools/pom.xml index 43cb3ee50..b43707888 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-tools diff --git a/ui/open-api-ui-forms/pom.xml b/ui/open-api-ui-forms/pom.xml index 40288546c..1df66a4da 100644 --- a/ui/open-api-ui-forms/pom.xml +++ b/ui/open-api-ui-forms/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-ui-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-ui-forms diff --git a/ui/open-api-ui/pom.xml b/ui/open-api-ui/pom.xml index 2452959cd..2ea6a3a9e 100644 --- a/ui/open-api-ui/pom.xml +++ b/ui/open-api-ui/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-ui-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-ui diff --git a/ui/pom.xml b/ui/pom.xml index 1b4013bf5..d6e480b0e 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-open-api-parent - 3.6.1-SNAPSHOT + 3.6.1-VB-SNAPSHOT smallrye-open-api-ui-parent From 6a93027a5789631467f9b6b467fb71063e183b9e Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Tue, 24 Oct 2023 15:25:17 +0300 Subject: [PATCH 5/9] Cleanup test for Enum default value and generation of allOf --- .../runtime/scanner/ParameterScanTests.java | 13 +- ...amEnumDefaultValueForEndpointResource.java | 37 +++++ .../DefaultEnumBeanParamTestResource.java | 137 ------------------ .../runtime/scanner/jakarta/PetEnum.java | 5 + ...param-enum-default-value-for-endpoint.json | 47 ++++++ ...ms.local-schema-attributes-bean-param.json | 60 -------- 6 files changed, 96 insertions(+), 203 deletions(-) create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamEnumDefaultValueForEndpointResource.java delete mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PetEnum.java create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-enum-default-value-for-endpoint.json delete mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java index 30eb0f0b0..14e772c8d 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java @@ -28,8 +28,9 @@ import io.smallrye.openapi.api.OpenApiConfig; import test.io.smallrye.openapi.runtime.scanner.Widget; -import test.io.smallrye.openapi.runtime.scanner.jakarta.DefaultEnumBeanParamTestResource; +import test.io.smallrye.openapi.runtime.scanner.jakarta.BeanParamEnumDefaultValueForEndpointResource; import test.io.smallrye.openapi.runtime.scanner.jakarta.MultipleContentTypesWithFormParamsTestResource; +import test.io.smallrye.openapi.runtime.scanner.jakarta.PetEnum; /** * @author Michael Edgar {@literal } @@ -459,11 +460,11 @@ void testJakartaDefaultEnumValue() throws IOException, JSONException { } @Test - void testJakartaDefaultBeanParamEnumValue() throws IOException, JSONException { - test("params.local-schema-attributes-bean-param.json", - test.io.smallrye.openapi.runtime.scanner.jakarta.DefaultEnumBeanParamTestResource.class, - DefaultEnumBeanParamTestResource.UserGroupDto.class, - DefaultEnumBeanParamTestResource.UserGroupSubtype.class); + void testJakartaBeanParamEnumDefaultValueForEndpoint() throws IOException, JSONException { + test("params.local-schema-attributes-bean-param-enum-default-value-for-endpoint.json", + BeanParamEnumDefaultValueForEndpointResource.class, + BeanParamEnumDefaultValueForEndpointResource.SimpleBeanParam.class, + PetEnum.class); } @Test diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamEnumDefaultValueForEndpointResource.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamEnumDefaultValueForEndpointResource.java new file mode 100644 index 000000000..a24d72f66 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamEnumDefaultValueForEndpointResource.java @@ -0,0 +1,37 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +@Path(value = "/bean-param-enum-default-value-for-endpoint") +public class BeanParamEnumDefaultValueForEndpointResource { + + public static class SimpleBeanParam { + @FormParam("petEnum") + @DefaultValue("LIZARD") + private PetEnum petEnum; + + public SimpleBeanParam() { + } + + public PetEnum getPetEnum() { + return petEnum; + } + + public void setPetEnum(PetEnum petEnum) { + this.petEnum = petEnum; + } + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response create(@BeanParam SimpleBeanParam beanParam) { + return Response.ok(beanParam.getPetEnum().name()).build(); + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java deleted file mode 100644 index c52134342..000000000 --- a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/DefaultEnumBeanParamTestResource.java +++ /dev/null @@ -1,137 +0,0 @@ -package test.io.smallrye.openapi.runtime.scanner.jakarta; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.FormParam; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import java.io.InputStream; - -@Path(value = "/enum-default-bean-param") -public class DefaultEnumBeanParamTestResource { - - public static class UserGroupDto { - @FormParam("sql") - private String sql; - @FormParam("contactSourceType") - private Integer contactSourceType; - @FormParam("archivationTime") - private String archivationTime; - @FormParam("type") - private String type; - @FormParam("employerIdsText") - @DefaultValue("EMAIL_BY_SQL") - private String employerIdsText; - @FormParam("formType") - @DefaultValue("EMAIL_BY_EXTERNAL_EMAIL_SOURCES") - private UserGroupSubtype formType; - @FormParam("externalEmailSourceCode") - private String externalEmailSourceCode; - @FormParam("externalEmailPandoraDoiCode") - private String externalEmailPandoraDoiCode; - @JsonIgnore - @FormParam("file") - private InputStream inputStream; - - public UserGroupDto() { - } - - public String getSql() { - return sql; - } - - public void setSql(String sql) { - this.sql = sql; - } - - public Integer getContactSourceType() { - return contactSourceType; - } - - public void setContactSourceType(Integer contactSourceType) { - this.contactSourceType = contactSourceType; - } - - public String getArchivationTime() { - return archivationTime; - } - - public void setArchivationTime(String archivationTime) { - this.archivationTime = archivationTime; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getEmployerIdsText() { - return employerIdsText; - } - - public void setEmployerIdsText(String employerIdsText) { - this.employerIdsText = employerIdsText; - } - - public UserGroupSubtype getFormType() { - return formType; - } - - public void setFormType(UserGroupSubtype userGroupSubtype) { - this.formType = userGroupSubtype; - } - - public InputStream getInputStream() { - return inputStream; - } - - public void setInputStream(InputStream inputStream) { - this.inputStream = inputStream; - } - - public String getExternalEmailSourceCode() { - return externalEmailSourceCode; - } - - public void setExternalEmailSourceCode(String externalEmailSourceCode) { - this.externalEmailSourceCode = externalEmailSourceCode; - } - - public String getExternalEmailPandoraDoiCode() { - return externalEmailPandoraDoiCode; - } - - public void setExternalEmailPandoraDoiCode(String externalEmailPandoraDoiCode) { - this.externalEmailPandoraDoiCode = externalEmailPandoraDoiCode; - } - - public boolean isFormOfType(UserGroupSubtype userGroupSubtype) { - return getFormType().equals(userGroupSubtype); - } - - } - - public enum UserGroupSubtype { - EMAIL_BY_SQL, - EMAIL_BY_EMPLOYERS, - EMAIL_BY_EXTERNAL_EMAIL_SOURCES, - SMS_BY_SQL, - PUSH_BY_SQL; - } - - - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - public Response create(@BeanParam UserGroupDto str) { - return null; - } - -} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PetEnum.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PetEnum.java new file mode 100644 index 000000000..e560dc5d7 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PetEnum.java @@ -0,0 +1,5 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +public enum PetEnum { + LIZARD, DOG, CAT; +} diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-enum-default-value-for-endpoint.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-enum-default-value-for-endpoint.json new file mode 100644 index 000000000..afb409fd9 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-enum-default-value-for-endpoint.json @@ -0,0 +1,47 @@ +{ + "openapi": "3.0.3", + "paths": { + "/bean-param-enum-default-value-for-endpoint": { + "post": { + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "petEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/PetEnum" + }, + { + "default": "LIZARD" + } + ] + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "PetEnum": { + "enum": [ + "LIZARD", + "DOG", + "CAT" + ], + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json deleted file mode 100644 index 3961d2074..000000000 --- a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "openapi": "3.0.3", - "paths": { - "/enum-default-bean-param": { - "post": { - "parameters": [ - { - "name": "q0", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "q1", - "in": "query", - "required": true, - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/MyEnum" - }, - { - "default": "DOG", - "maxLength": 3, - "minLength": 3 - } - ] - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "BeanEnum": { - "enum": [ - "CAT", - "DOG", - "BAR", - "FOO" - ], - "type": "string" - } - } - } -} From d86d5bf5dcb2eb16a12b0d5b4d11b1e6b9f9794a Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Tue, 24 Oct 2023 16:06:22 +0300 Subject: [PATCH 6/9] Add test for ExceptionMapper annotation overrides with respect to inheritance chain --- .../scanner/ExceptionMapperScanTests.java | 11 ++++++ .../scanner/jakarta/ChildExceptionMapper.java | 19 ++++++++++ .../jakarta/ParentExceptionMapper.java | 20 ++++++++++ ...-overridden-by-exception-mapper-child.json | 38 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ChildExceptionMapper.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ParentExceptionMapper.java create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-parent-overridden-by-exception-mapper-child.json diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java index b61a6a947..c88987f38 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java @@ -7,6 +7,8 @@ import org.jboss.jandex.Index; import org.json.JSONException; import org.junit.jupiter.api.Test; +import test.io.smallrye.openapi.runtime.scanner.jakarta.ChildExceptionMapper; +import test.io.smallrye.openapi.runtime.scanner.jakarta.ParentExceptionMapper; class ExceptionMapperScanTests extends IndexScannerTestBase { @@ -60,4 +62,13 @@ void testJakartaExceptionMapperMultipleResponse() throws IOException, JSONExcept test.io.smallrye.openapi.runtime.scanner.jakarta.TestResource.class, test.io.smallrye.openapi.runtime.scanner.jakarta.ExceptionHandler3.class); } + + @Test + void testJakartaChildExceptionMapperOverridesParentExceptionMapper() throws IOException, JSONException { + test("responses.exception-mapper-parent-overridden-by-exception-mapper-child.json", + test.io.smallrye.openapi.runtime.scanner.jakarta.TestResource.class, + ParentExceptionMapper.class, + ChildExceptionMapper.class + ); + } } diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ChildExceptionMapper.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ChildExceptionMapper.java new file mode 100644 index 000000000..16a43bef6 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ChildExceptionMapper.java @@ -0,0 +1,19 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; + +@APIResponse( + responseCode = "500", + description = "Child Exception Mapper Internal Server Error" +) +@Priority(1) +public class ChildExceptionMapper extends ParentExceptionMapper { + + @Override + public Response toResponse(WebApplicationException exception) { + return super.toResponse(exception); + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ParentExceptionMapper.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ParentExceptionMapper.java new file mode 100644 index 000000000..158876542 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/ParentExceptionMapper.java @@ -0,0 +1,20 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; + + +@APIResponse( + responseCode = "500", + description = "Parent Exception Mapper Internal Server Error" +) +@Priority(2) +public class ParentExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(WebApplicationException exception) { + return null; + } +} diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-parent-overridden-by-exception-mapper-child.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-parent-overridden-by-exception-mapper-child.json new file mode 100644 index 000000000..a639e35b7 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-parent-overridden-by-exception-mapper-child.json @@ -0,0 +1,38 @@ +{ + "openapi": "3.0.3", + "paths": { + "/resources": { + "get": { + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + }, + "post": { + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Child Exception Mapper Internal Server Error" + } + } + } + } + } +} \ No newline at end of file From 50dbc02590c4cd23da898110fc579ed2e9df1b62 Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Tue, 24 Oct 2023 16:12:56 +0300 Subject: [PATCH 7/9] Add test for ExceptionMapper priority overrides --- .../scanner/ExceptionMapperScanTests.java | 11 ++++++ .../jakarta/PriorityOneExceptionMapper.java | 19 ++++++++++ .../jakarta/PriorityTwoExceptionMapper.java | 19 ++++++++++ ....exception-mapper-priority-overridden.json | 38 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityOneExceptionMapper.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityTwoExceptionMapper.java create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-priority-overridden.json diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java index c88987f38..f9d03e7eb 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ExceptionMapperScanTests.java @@ -9,6 +9,8 @@ import org.junit.jupiter.api.Test; import test.io.smallrye.openapi.runtime.scanner.jakarta.ChildExceptionMapper; import test.io.smallrye.openapi.runtime.scanner.jakarta.ParentExceptionMapper; +import test.io.smallrye.openapi.runtime.scanner.jakarta.PriorityOneExceptionMapper; +import test.io.smallrye.openapi.runtime.scanner.jakarta.PriorityTwoExceptionMapper; class ExceptionMapperScanTests extends IndexScannerTestBase { @@ -71,4 +73,13 @@ void testJakartaChildExceptionMapperOverridesParentExceptionMapper() throws IOEx ChildExceptionMapper.class ); } + + @Test + void testJakartaPriorityOverrideExceptionMapper() throws IOException, JSONException { + test("responses.exception-mapper-priority-overridden.json", + test.io.smallrye.openapi.runtime.scanner.jakarta.TestResource.class, + PriorityOneExceptionMapper.class, + PriorityTwoExceptionMapper.class + ); + } } diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityOneExceptionMapper.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityOneExceptionMapper.java new file mode 100644 index 000000000..9600979f1 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityOneExceptionMapper.java @@ -0,0 +1,19 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; + +@Priority(1) +@APIResponse( + responseCode = "500", + description = "Priority 1 Internal Server Error" +) +public class PriorityOneExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(WebApplicationException exception) { + return null; + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityTwoExceptionMapper.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityTwoExceptionMapper.java new file mode 100644 index 000000000..80f412782 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/PriorityTwoExceptionMapper.java @@ -0,0 +1,19 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; + +@Priority(2) +@APIResponse( + responseCode = "500", + description = "Priority 2 Internal Server Error" +) +public class PriorityTwoExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(WebApplicationException exception) { + return null; + } +} diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-priority-overridden.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-priority-overridden.json new file mode 100644 index 000000000..425242ee4 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/responses.exception-mapper-priority-overridden.json @@ -0,0 +1,38 @@ +{ + "openapi": "3.0.3", + "paths": { + "/resources": { + "get": { + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + }, + "post": { + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Priority 1 Internal Server Error" + } + } + } + } + } +} \ No newline at end of file From 8ae5676e556b8cef89e602d42d3fba91a056cf52 Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Mon, 6 Nov 2023 21:55:31 +0300 Subject: [PATCH 8/9] Add jersey annotations and types support for generation --- .../openapi/jaxrs/JaxRsAnnotationScanner.java | 3 +- .../openapi/jaxrs/JaxRsParameter.java | 7 +++ .../jaxrs/JaxRsParameterProcessor.java | 61 +++++++++++++++---- .../openapi/jaxrs/JerseyConstants.java | 52 ++++++++++++++++ 4 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JerseyConstants.java diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java index 4fa3f56ea..8b826fdb9 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsAnnotationScanner.java @@ -106,7 +106,8 @@ public boolean isMultipartOutput(Type returnType) { @Override public boolean isMultipartInput(Type inputType) { - return RestEasyConstants.MULTIPART_INPUTS.contains(inputType.name()); + DotName name = inputType.name(); + return JerseyConstants.MULTIPART_INPUTS.contains(name) || RestEasyConstants.MULTIPART_INPUTS.contains(name); } @Override diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameter.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameter.java index 48d0b56a7..d8c44c401 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameter.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameter.java @@ -24,6 +24,9 @@ public enum JaxRsParameter { COOKIE_PARAM(JaxRsConstants.COOKIE_PARAM, Parameter.In.COOKIE, null, Parameter.Style.FORM), BEAN_PARAM(JaxRsConstants.BEAN_PARAM, null, null, null), + // Support Jersey annotations directly + JERSEY_MULTIPART_FORM(JerseyConstants.FORM_DATA_PARAM, null, Parameter.Style.FORM, Parameter.Style.FORM), + // Support RESTEasy annotations directly RESTEASY_PATH_PARAM(RestEasyConstants.PATH_PARAM, Parameter.In.PATH, null, Parameter.Style.SIMPLE), // Apply to the last-matched @Path of the structure injecting the MatrixParam @@ -80,4 +83,8 @@ public static boolean isParameter(DotName annotationName) { return forName(annotationName) != null; } + public static boolean isJerseyParameter(DotName annotationName) { + return annotationName.toString().startsWith(JerseyConstants.JERSEY_PACKAGE); + } + } diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameterProcessor.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameterProcessor.java index 40d3488ea..c78f0664a 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameterProcessor.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JaxRsParameterProcessor.java @@ -1,13 +1,23 @@ package io.smallrye.openapi.jaxrs; +import io.smallrye.openapi.api.models.media.EncodingImpl; +import io.smallrye.openapi.runtime.io.parameter.ParameterConstant; +import io.smallrye.openapi.runtime.scanner.AnnotationScannerExtension; +import io.smallrye.openapi.runtime.scanner.ResourceParameters; +import io.smallrye.openapi.runtime.scanner.dataobject.TypeResolver; +import io.smallrye.openapi.runtime.scanner.spi.AbstractParameterProcessor; +import io.smallrye.openapi.runtime.scanner.spi.AnnotationScannerContext; +import io.smallrye.openapi.runtime.scanner.spi.FrameworkParameter; +import io.smallrye.openapi.runtime.util.Annotations; +import io.smallrye.openapi.runtime.util.TypeUtil; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.regex.Pattern; - import org.eclipse.microprofile.openapi.models.media.Encoding; import org.eclipse.microprofile.openapi.models.parameters.Parameter; import org.eclipse.microprofile.openapi.models.parameters.Parameter.In; @@ -20,17 +30,6 @@ import org.jboss.jandex.MethodParameterInfo; import org.jboss.jandex.Type; -import io.smallrye.openapi.api.models.media.EncodingImpl; -import io.smallrye.openapi.runtime.io.parameter.ParameterConstant; -import io.smallrye.openapi.runtime.scanner.AnnotationScannerExtension; -import io.smallrye.openapi.runtime.scanner.ResourceParameters; -import io.smallrye.openapi.runtime.scanner.dataobject.TypeResolver; -import io.smallrye.openapi.runtime.scanner.spi.AbstractParameterProcessor; -import io.smallrye.openapi.runtime.scanner.spi.AnnotationScannerContext; -import io.smallrye.openapi.runtime.scanner.spi.FrameworkParameter; -import io.smallrye.openapi.runtime.util.Annotations; -import io.smallrye.openapi.runtime.util.TypeUtil; - /** * Note, javax.ws.rs.PathParam PathParam targets of javax.ws.rs.core.PathSegment PathSegment are not currently supported. * @@ -169,12 +168,48 @@ protected void readAnnotatedType(AnnotationInstance annotation, AnnotationInstan } else { FrameworkParameter frameworkParam = JaxRsParameter.forName(name); - if (frameworkParam != null) { + if (frameworkParam == null) { + return; + } + + boolean isJerseyParameter = frameworkParam.getNames().stream().anyMatch(JaxRsParameter::isJerseyParameter); + if (isJerseyParameter) { + readJerseyParameter(annotation, frameworkParam, overriddenParametersOnly); + } else { readJaxRsParameter(annotation, frameworkParam, beanParamAnnotation, overriddenParametersOnly); } } } + private void readJerseyParameter(AnnotationInstance annotation, FrameworkParameter frameworkParam, boolean overriddenParametersOnly) { + AnnotationTarget target = annotation.target(); + Type targetType = getType(target); + + if (frameworkParam.style == Style.FORM) { + String paramName = paramName(annotation); + if (isJerseyMultipart(targetType) && formParams.containsKey(paramName)) { + return; + } + // Store the @FormDataParam for later processing + formParams.put(paramName, annotation); + readFrameworkParameter(annotation, frameworkParam, overriddenParametersOnly); + } + } + + private boolean isJerseyMultipart(Type type) { + Set names = new HashSet<>(); + + if (type.kind() == Type.Kind.CLASS) { + names.add(type.asClassType().name()); + } else if (type.kind() == Type.Kind.ARRAY) { + names.add(type.asArrayType().elementType().name()); + } else if (type.kind() == Type.Kind.PARAMETERIZED_TYPE) { + type.asParameterizedType().arguments().stream().map(Type::name).forEach(names::add); + } + + return names.stream().anyMatch(JerseyConstants.MULTIPART_INPUTS::contains); + } + private void readJaxRsParameter(AnnotationInstance annotation, FrameworkParameter frameworkParam, AnnotationInstance beanParamAnnotation, diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JerseyConstants.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JerseyConstants.java new file mode 100644 index 000000000..74487e041 --- /dev/null +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/JerseyConstants.java @@ -0,0 +1,52 @@ +package io.smallrye.openapi.jaxrs; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.jboss.jandex.DotName; + +public class JerseyConstants { + + public static final String JERSEY_PACKAGE = "org.glassfish.jersey"; + + // Jersey multipart annotations + public static final DotName FORM_DATA_PARAM = DotName + .createSimple("org.glassfish.jersey.media.multipart.FormDataParam"); + + // Jersey multipart headers + public static final DotName CONTENT_DISPOSITION = DotName + .createSimple("org.glassfish.jersey.media.multipart.ContentDisposition"); + public static final DotName FORM_DATA_CONTENT_DISPOSITION = DotName + .createSimple("org.glassfish.jersey.media.multipart.FormDataContentDisposition"); + + // Jersey multipart input types + public static final DotName BODY_PART = DotName + .createSimple("org.glassfish.jersey.media.multipart.BodyPart"); + public static final DotName FORM_DATA_BODY_PART = DotName + .createSimple("org.glassfish.jersey.media.multipart.FormDataBodyPart"); + public static final DotName FILE_DATA_BODY_PART = DotName + .createSimple("org.glassfish.jersey.media.multipart.FileDataBodyPart"); + public static final DotName STREAM_DATA_BODY_PART = DotName + .createSimple("org.glassfish.jersey.media.multipart.StreamDataBodyPart"); + + public static final DotName MULTI_PART = DotName + .createSimple("org.glassfish.jersey.media.multipart.MultiPart"); + public static final DotName FORM_DATA_MULTI_PART = DotName + .createSimple("org.glassfish.jersey.media.multipart.FormDataMultiPart"); + + public static final Set MULTIPART_INPUTS = Collections.unmodifiableSet( + new HashSet<>( + Arrays.asList( + CONTENT_DISPOSITION, + FORM_DATA_CONTENT_DISPOSITION, + BODY_PART, + FORM_DATA_BODY_PART, + FILE_DATA_BODY_PART, + STREAM_DATA_BODY_PART, + MULTI_PART, + FORM_DATA_MULTI_PART + ) + ) + ); +} From e4fda4739fd6735210804f392dc9b754025009c9 Mon Sep 17 00:00:00 2001 From: Vladimir Bazhmin Date: Mon, 6 Nov 2023 22:43:50 +0300 Subject: [PATCH 9/9] Add tests for jersey multipart types --- extension-jaxrs/pom.xml | 6 +++ .../runtime/scanner/ParameterScanTests.java | 8 ++++ .../runtime/scanner/RequestBodyScanTests.java | 40 ++++++++++++++++ .../jakarta/BeanParamJerseyResource.java | 46 +++++++++++++++++++ .../jakarta/JerseyFileDataBodyPart.java | 21 +++++++++ .../jakarta/JerseyFormDataBodyPart.java | 22 +++++++++ .../JerseyFormDataContentDisposition.java | 25 ++++++++++ .../jakarta/JerseyFormDataMultipart.java | 21 +++++++++ .../jakarta/JerseyStreamDataBodyPart.java | 27 +++++++++++ .../params.jersey-file-data-body-part.json | 35 ++++++++++++++ .../params.jersey-form-data-body-part.json | 36 +++++++++++++++ ....jersey-form-data-content-disposition.json | 36 +++++++++++++++ .../params.jersey-form-data-multipart.json | 35 ++++++++++++++ .../params.jersey-stream-data-body-part.json | 35 ++++++++++++++ ...l-schema-attributes-bean-param-jersey.json | 39 ++++++++++++++++ pom.xml | 1 + 16 files changed, 433 insertions(+) create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamJerseyResource.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFileDataBodyPart.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataBodyPart.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataContentDisposition.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataMultipart.java create mode 100644 extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyStreamDataBodyPart.java create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-file-data-body-part.json create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-body-part.json create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-content-disposition.json create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-multipart.json create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-stream-data-body-part.json create mode 100644 extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-jersey.json diff --git a/extension-jaxrs/pom.xml b/extension-jaxrs/pom.xml index 8c2992688..ec51ce8b2 100644 --- a/extension-jaxrs/pom.xml +++ b/extension-jaxrs/pom.xml @@ -57,6 +57,12 @@ resteasy-multipart-provider test + + org.glassfish.jersey.media + jersey-media-multipart + ${version.jersey.media} + test + io.quarkus.resteasy.reactive resteasy-reactive-common diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java index 14e772c8d..ded636116 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ParameterScanTests.java @@ -29,6 +29,7 @@ import io.smallrye.openapi.api.OpenApiConfig; import test.io.smallrye.openapi.runtime.scanner.Widget; import test.io.smallrye.openapi.runtime.scanner.jakarta.BeanParamEnumDefaultValueForEndpointResource; +import test.io.smallrye.openapi.runtime.scanner.jakarta.BeanParamJerseyResource; import test.io.smallrye.openapi.runtime.scanner.jakarta.MultipleContentTypesWithFormParamsTestResource; import test.io.smallrye.openapi.runtime.scanner.jakarta.PetEnum; @@ -459,6 +460,13 @@ void testJakartaDefaultEnumValue() throws IOException, JSONException { test.io.smallrye.openapi.runtime.scanner.jakarta.DefaultEnumTestResource.MyEnum.class); } + @Test + void testJakartaBeanParamJersey() throws IOException, JSONException { + test("params.local-schema-attributes-bean-param-jersey.json", + BeanParamJerseyResource.class, + BeanParamJerseyResource.JerseyBean.class); + } + @Test void testJakartaBeanParamEnumDefaultValueForEndpoint() throws IOException, JSONException { test("params.local-schema-attributes-bean-param-enum-default-value-for-endpoint.json", diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/RequestBodyScanTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/RequestBodyScanTests.java index 27ff7c6f3..73feaf68f 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/RequestBodyScanTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/RequestBodyScanTests.java @@ -8,6 +8,11 @@ import org.jboss.jandex.Index; import org.json.JSONException; import org.junit.jupiter.api.Test; +import test.io.smallrye.openapi.runtime.scanner.jakarta.JerseyFileDataBodyPart; +import test.io.smallrye.openapi.runtime.scanner.jakarta.JerseyFormDataBodyPart; +import test.io.smallrye.openapi.runtime.scanner.jakarta.JerseyFormDataContentDisposition; +import test.io.smallrye.openapi.runtime.scanner.jakarta.JerseyFormDataMultipart; +import test.io.smallrye.openapi.runtime.scanner.jakarta.JerseyStreamDataBodyPart; class RequestBodyScanTests extends IndexScannerTestBase { @@ -104,4 +109,39 @@ public void addBar(@jakarta.validation.constraints.NotEmpty String foo) { } test("params.request-body-constraints.json", Resource.class); } + + @Test + void testJakartaJerseyFormDataMultiPart() throws IOException, JSONException { + test("params.jersey-form-data-multipart.json", + JerseyFormDataMultipart.class + ); + } + + @Test + void testJakartaJerseyFormDataBodyPart() throws IOException, JSONException { + test("params.jersey-form-data-body-part.json", + JerseyFormDataBodyPart.class + ); + } + + @Test + void testJakartaJerseyFileDataBodyPart() throws IOException, JSONException { + test("params.jersey-file-data-body-part.json", + JerseyFileDataBodyPart.class + ); + } + + @Test + void testJakartaJerseyStreamDataBodyPart() throws IOException, JSONException { + test("params.jersey-stream-data-body-part.json", + JerseyStreamDataBodyPart.class + ); + } + + @Test + void testJakartaJerseyFormDataContentDisposition() throws IOException, JSONException { + test("params.jersey-form-data-content-disposition.json", + JerseyFormDataContentDisposition.class + ); + } } diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamJerseyResource.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamJerseyResource.java new file mode 100644 index 000000000..647bc8c2c --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/BeanParamJerseyResource.java @@ -0,0 +1,46 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.media.multipart.FormDataParam; + +@Path("/bean-param-jersey") +@Produces(MediaType.APPLICATION_JSON) +public class BeanParamJerseyResource { + + public static class JerseyBean { + + @FormDataParam("primitiveString") + String string; + + @FormDataParam("primitiveInteger") + Integer integer; + + public String getString() { + return string; + } + + public void setString(String string) { + this.string = string; + } + + public Integer getInteger() { + return integer; + } + + public void setInteger(Integer integer) { + this.integer = integer; + } + } + + @POST + @Consumes("multipart/form-data") + public String receiveMultipart(@BeanParam JerseyBean jerseyBean) throws WebApplicationException { + return "OK"; + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFileDataBodyPart.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFileDataBodyPart.java new file mode 100644 index 000000000..2ebba39f1 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFileDataBodyPart.java @@ -0,0 +1,21 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; + +@Path(value = "/jersey-file-data-body-part") +@Produces(MediaType.TEXT_PLAIN) +public class JerseyFileDataBodyPart { + + @POST + @Consumes("multipart/form-data") + public String receiveFile(@FormDataParam("file") FileDataBodyPart fileDataBodyPart) throws WebApplicationException { + return "OK"; + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataBodyPart.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataBodyPart.java new file mode 100644 index 000000000..d67af3afb --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataBodyPart.java @@ -0,0 +1,22 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import java.util.Collection; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.glassfish.jersey.media.multipart.FormDataParam; + +@Path(value = "/jersey-form-data-body-part") +@Produces(MediaType.TEXT_PLAIN) +public class JerseyFormDataBodyPart { + + @POST + @Consumes("multipart/form-data") + public String receiveBodyParts(@FormDataParam("collectionOfBodyParts") Collection bodyParts) throws WebApplicationException { + return "OK"; + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataContentDisposition.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataContentDisposition.java new file mode 100644 index 000000000..12bafba4b --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataContentDisposition.java @@ -0,0 +1,25 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import java.io.InputStream; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataParam; + +@Path(value = "/jersey-form-data-content-disposition") +@Produces(MediaType.TEXT_PLAIN) +public class JerseyFormDataContentDisposition { + + @POST + @Consumes("multipart/form-data") + public String receiveFileAndContentDisposition( + @FormDataParam("file") InputStream file, + @FormDataParam("file") FormDataContentDisposition fileContentDispositionHeader + ) throws WebApplicationException { + return "OK"; + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataMultipart.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataMultipart.java new file mode 100644 index 000000000..4e3ae30c3 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyFormDataMultipart.java @@ -0,0 +1,21 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.FormDataParam; + +@Path(value = "/jersey-form-data-multi-part") +@Produces(MediaType.TEXT_PLAIN) +public class JerseyFormDataMultipart { + + @POST + @Consumes("multipart/form-data") + public String receiveMultipart(@FormDataParam("multipartView") FormDataMultiPart multipartView) throws WebApplicationException { + return "OK"; + } +} diff --git a/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyStreamDataBodyPart.java b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyStreamDataBodyPart.java new file mode 100644 index 000000000..517fe22b6 --- /dev/null +++ b/extension-jaxrs/src/test/java/test/io/smallrye/openapi/runtime/scanner/jakarta/JerseyStreamDataBodyPart.java @@ -0,0 +1,27 @@ +package test.io.smallrye.openapi.runtime.scanner.jakarta; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import java.io.InputStream; +import java.util.Collection; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; +import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart; + +@Path(value = "/jersey-stream-data-body-part") +@Produces(MediaType.TEXT_PLAIN) +public class JerseyStreamDataBodyPart { + + @POST + @Consumes("multipart/form-data") + public String receiveFileStream(@FormDataParam("file") StreamDataBodyPart streamDataBodyPart) throws WebApplicationException { + return "OK"; + } +} diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-file-data-body-part.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-file-data-body-part.json new file mode 100644 index 000000000..058ca1aa7 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-file-data-body-part.json @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.3", + "paths": { + "/jersey-file-data-body-part": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "object" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-body-part.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-body-part.json new file mode 100644 index 000000000..b43fc4e21 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-body-part.json @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.3", + "paths": { + "/jersey-form-data-body-part": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "collectionOfBodyParts": { + "type": "array", + "items": {} + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-content-disposition.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-content-disposition.json new file mode 100644 index 000000000..ffa731288 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-content-disposition.json @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.3", + "paths": { + "/jersey-form-data-content-disposition": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "format": "binary", + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-multipart.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-multipart.json new file mode 100644 index 000000000..e6d6666f3 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-form-data-multipart.json @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.3", + "paths": { + "/jersey-form-data-multi-part": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "multipartView": { + "type": "object" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-stream-data-body-part.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-stream-data-body-part.json new file mode 100644 index 000000000..1c61d7078 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.jersey-stream-data-body-part.json @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.3", + "paths": { + "/jersey-stream-data-body-part": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "object" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-jersey.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-jersey.json new file mode 100644 index 000000000..1d46cddd5 --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.local-schema-attributes-bean-param-jersey.json @@ -0,0 +1,39 @@ +{ + "openapi": "3.0.3", + "paths": { + "/bean-param-jersey": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "primitiveString": { + "type": "string" + }, + "primitiveInteger": { + "format": "int32", + "type": "integer" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 56669fd37..686153463 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,7 @@ 7.7.1 2.0.0.Final 11.0.16 + 3.1.3 6.2.3.Final