Skip to content

Commit 5be04c7

Browse files
[issues#976] Fix api.qute condition to include jakarta constraint annotations to all endpoint parameters (#978) (#980)
* [issues#964] Fix beanValidationCore.qute condition to include the jakarta.validation.Valid annotation * [issues#976] Fix api.qute condition to include constraint annotations to all endpoint params Co-authored-by: Juan Piero Santisteban Quiroz <[email protected]>
1 parent 70faf66 commit 5be04c7

File tree

6 files changed

+126
-6
lines changed

6 files changed

+126
-6
lines changed

client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/template/QuteTemplatingEngineAdapter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class QuteTemplatingEngineAdapter extends AbstractTemplatingEngineAdapter
1919
"additionalModelTypeAnnotations.qute",
2020
"beanValidation.qute",
2121
"beanValidationCore.qute",
22+
"beanValidationInlineCore.qute",
2223
"beanValidationHeaderParams.qute",
2324
"bodyParams.qute",
2425
"enumClass.qute",

client/deployment/src/main/resources/templates/libraries/microprofile/api.qute

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ public interface {classname} {
135135
@org.jboss.resteasy.annotations.providers.multipart.MultipartForm {op.operationIdCamelCase}MultipartForm multipartForm{#if op.hasPathParams},{/if}
136136
{/if}
137137
{#if use-bean-validation}
138-
{#for p in op.pathParams}@jakarta.validation.Valid {#include pathParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasQueryParams},{/if}
139-
{#for p in op.queryParams}@jakarta.validation.Valid {#include queryParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasCookieParams},{/if}
140-
{#for p in op.cookieParams}@jakarta.validation.Valid {#include cookieParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasHeaderParams},{/if}
141-
{#for p in op.headerParams}@jakarta.validation.Valid {#include headerParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasBodyParam},
142-
{#for p in op.bodyParams}@jakarta.validation.Valid {#include bodyParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{/if}
138+
{#for p in op.pathParams}{#include beanValidationInlineCore.qute param=p/}{#include pathParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasQueryParams},{/if}
139+
{#for p in op.queryParams}{#include beanValidationInlineCore.qute param=p/}{#include queryParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasCookieParams},{/if}
140+
{#for p in op.cookieParams}{#include beanValidationInlineCore.qute param=p/}{#include cookieParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasHeaderParams},{/if}
141+
{#for p in op.headerParams}{#include beanValidationInlineCore.qute param=p/}{#include headerParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasBodyParam},
142+
{#for p in op.bodyParams}{#include beanValidationInlineCore.qute param=p/}{#include bodyParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{/if}
143143
{#else}
144144
{#for p in op.pathParams}{#include pathParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasQueryParams},{/if}
145145
{#for p in op.queryParams}{#include queryParams.qute param=p/}{#if p_hasNext}, {/if}{/for}{#if op.hasCookieParams},{/if}
@@ -149,7 +149,7 @@ public interface {classname} {
149149
{/if}
150150
{#else}
151151
{#for p in op.allParams}
152-
{#if use-bean-validation}@jakarta.validation.Valid {/if}{!
152+
{#if use-bean-validation}{#include beanValidationInlineCore.qute param=p/}{/if}{!
153153
!}{#include pathParams.qute param=p/}{#include queryParams.qute param=p/}{#include bodyParams.qute param=p/}{#include headerParams.qute param=p/}{#include cookieParams.qute param=p/}{#if p_hasNext}, {/if}
154154
{/for}{/if}
155155
);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{#if p.required}@jakarta.validation.constraints.NotNull {/if}{#if p.pattern}@jakarta.validation.constraints.Pattern(regexp = "{p.pattern}") {/if}{#if p.minLength || p.minItems}@jakarta.validation.constraints.Size(min = {p.minLength}{p.minItems}) {/if}{#if p.maxLength || p.maxItems}@jakarta.validation.constraints.Size(max = {p.maxLength}{p.maxItems}) {/if}{#if p.isInteger}{#if p.minimum}@jakarta.validation.constraints.Min({p.minimum}) {/if}{#if p.maximum}@jakarta.validation.constraints.Max({p.maximum}) {/if}{/if}{#if p.isLong}{#if p.minimum}@jakarta.validation.constraints.Min({p.minimum}L) {/if}{#if p.maximum}@jakarta.validation.constraints.Max({p.maximum}L) {/if}{/if}{#if !p.isInteger && !p.isLong}{#if p.minimum}@jakarta.validation.constraints.DecimalMin("{p.minimum}") {/if}{#if p.maximum}@jakarta.validation.constraints.DecimalMax("{p.maximum}") {/if}{/if}{#if use-bean-validation}@jakarta.validation.Valid {/if}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: Test API
5+
version: "1.0"
6+
paths:
7+
/{pathParam}:
8+
post:
9+
tags:
10+
- ValidatedEndpointIssue976
11+
operationId: test
12+
parameters:
13+
- name: queryParam
14+
in: query
15+
schema:
16+
$ref: '#/components/schemas/ValidatedObjectIssue976'
17+
- name: pathParam
18+
in: path
19+
description: pathParam description
20+
required: true
21+
schema:
22+
type: string
23+
maxLength: 14
24+
minLength: 14
25+
pattern: '^[0-9]{14}$'
26+
example: '19318085994179'
27+
- name: headerParam
28+
in: header
29+
description: 'Header description'
30+
required: false
31+
schema:
32+
maxLength: 32
33+
minLength: 32
34+
pattern: '^[a-z0-9]{32}$'
35+
type: string
36+
example: 3cfdad6e03c24d0ab7112dce75cdba35
37+
- name: cookieParam
38+
in: cookie
39+
required: true
40+
schema:
41+
type: string
42+
minLength: 10
43+
requestBody:
44+
content:
45+
application/json:
46+
schema:
47+
$ref: '#/components/schemas/ValidatedObjectIssue976'
48+
responses:
49+
"200":
50+
description: OK
51+
content:
52+
text/plain:
53+
schema:
54+
type: string
55+
components:
56+
schemas:
57+
ValidatedObjectIssue976:
58+
type: object
59+
description: Some object to be validated
60+
required:
61+
- id
62+
- name
63+
- secondName
64+
- size
65+
properties:
66+
id:
67+
type: integer
68+
minimum: 1
69+
maximum: 100
70+
name:
71+
type: string
72+
pattern: "[a-zA-Z]*"
73+
minLength: 1
74+
maxLength: 10
75+
secondName:
76+
type: string
77+
size:
78+
type: number
79+
minimum: 1.0
80+
maximum: 10.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
quarkus.openapi-generator.codegen.spec.bean_validation_true_yaml.use-bean-validation = true
2+
quarkus.openapi-generator.codegen.spec.issue_976_yaml.use-bean-validation = true
23
quarkus.openapi-generator.codegen.spec.bean_validation_false_yaml.use-bean-validation = false
34
quarkus.keycloak.devservices.enabled=false

client/integration-tests/bean-validation/src/test/java/io/quarkiverse/openapi/generator/it/BeanValidationTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.lang.annotation.Annotation;
66
import java.lang.reflect.Field;
77
import java.lang.reflect.Method;
8+
import java.lang.reflect.Parameter;
89
import java.util.Arrays;
910
import java.util.stream.Stream;
1011

@@ -16,12 +17,15 @@
1617
import jakarta.validation.constraints.NotNull;
1718
import jakarta.validation.constraints.Pattern;
1819
import jakarta.validation.constraints.Size;
20+
import jakarta.ws.rs.HeaderParam;
21+
import jakarta.ws.rs.PathParam;
1922

2023
import org.junit.jupiter.api.Test;
2124
import org.openapi.quarkus.bean_validation_false_yaml.api.UnvalidatedEndpointApi;
2225
import org.openapi.quarkus.bean_validation_false_yaml.model.UnvalidatedObject;
2326
import org.openapi.quarkus.bean_validation_true_yaml.api.ValidatedEndpointApi;
2427
import org.openapi.quarkus.bean_validation_true_yaml.model.ValidatedObject;
28+
import org.openapi.quarkus.issue_976_yaml.api.ValidatedEndpointIssue976Api;
2529

2630
import io.quarkus.test.junit.QuarkusTest;
2731

@@ -99,4 +103,37 @@ void testValidationAnnotationsAreSkippedModel() throws Exception {
99103
assertThat(size.isAnnotationPresent(DecimalMin.class)).isFalse();
100104
assertThat(size.isAnnotationPresent(DecimalMax.class)).isFalse();
101105
}
106+
107+
@Test
108+
void testValidationAnnotationsAreInPlaceApiIssue976() {
109+
Method method = ValidatedEndpointIssue976Api.class.getMethods()[0];
110+
Annotation[][] annotationsPerParameter = method.getParameterAnnotations();
111+
112+
Parameter pathParam = Arrays.stream(method.getParameters())
113+
.filter(p -> p.getName().equals("pathParam"))
114+
.findFirst().get();
115+
116+
Parameter headerParam = Arrays.stream(method.getParameters())
117+
.filter(p -> p.getName().equals("headerParam"))
118+
.findFirst().get();
119+
120+
Boolean validationAnnotationExists = Arrays.stream(annotationsPerParameter)
121+
.allMatch(annotations -> Arrays.stream(annotations)
122+
.filter(a -> a.annotationType().equals(Valid.class)).toList()
123+
.size() == 1);
124+
125+
assertThat(validationAnnotationExists).isTrue();
126+
127+
assertThat(pathParam.isAnnotationPresent(Valid.class)).isTrue();
128+
assertThat(pathParam.isAnnotationPresent(NotNull.class)).isTrue();
129+
assertThat(pathParam.isAnnotationPresent(Pattern.class)).isTrue();
130+
assertThat(pathParam.isAnnotationPresent(Size.List.class)).isTrue();
131+
assertThat(pathParam.isAnnotationPresent(PathParam.class)).isTrue();
132+
133+
assertThat(headerParam.isAnnotationPresent(Valid.class)).isTrue();
134+
assertThat(headerParam.isAnnotationPresent(NotNull.class)).isFalse();
135+
assertThat(headerParam.isAnnotationPresent(Size.List.class)).isTrue();
136+
assertThat(headerParam.isAnnotationPresent(Pattern.class)).isTrue();
137+
assertThat(headerParam.isAnnotationPresent(HeaderParam.class)).isTrue();
138+
}
102139
}

0 commit comments

Comments
 (0)