Skip to content

Commit 01b7cc0

Browse files
committed
openapi-processor/openapi-processor-spring#229, add @Valid to reactive type and not the wrapped type
1 parent 47f5495 commit 01b7cc0

File tree

8 files changed

+117
-35
lines changed

8 files changed

+117
-35
lines changed

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/converter/ApiOptions.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class ApiOptions {
9999
}
100100
}
101101

102+
/**
103+
* (compatibility) add @Valid on reactive type and not on the wrapped type
104+
*/
105+
var beanValidationValidOnReactive = true
102106
}
103107

104108
/**

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/converter/wrapper/MultiDataTypeWrapper.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ class MultiDataTypeWrapper(
5353
targetType.getPkg(),
5454
(dataType as CollectionDataType).item,
5555
null,
56-
false
56+
false,
57+
multi = true
5758
)
5859
}
5960

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/model/datatypes/MappedCollectionDataType.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ open class MappedCollectionDataType(
1717
override val item: DataType,
1818
override val constraints: DataTypeConstraints? = null,
1919
override val deprecated: Boolean = false,
20-
override val sourceDataType: DataType? = null
20+
override val sourceDataType: DataType? = null,
21+
val multi: Boolean = false
2122
): DataType, CollectionDataType, MappedSourceDataType {
2223

2324
override fun getName(): String {

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/writer/java/BeanValidationFactory.kt

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,34 @@ open class BeanValidationFactory(
2727
return BeanValidationInfoSimple(dataType, emptyList())
2828
}
2929

30-
fun validate(dataType: DataType, required: Boolean = false): BeanValidationInfo {
30+
fun validate(dataType: DataType, required: Boolean = false, parentHasValid: Boolean = false): BeanValidationInfo {
3131
return if (dataType is CollectionDataType) {
32+
val (annotations, valid) = collectAnnotationsWithValid(dataType, required, parentHasValid)
33+
3234
BeanValidationInfoCollection(
3335
dataType,
34-
collectAnnotations(dataType, required),
35-
validate(dataType.item, false)
36+
annotations,
37+
validate(dataType.item, parentHasValid = valid)
3638
)
3739
} else {
3840
BeanValidationInfoSimple(
3941
dataType,
40-
collectAnnotations(dataType, required)
42+
collectAnnotations(dataType, required, parentHasValid)
4143
)
4244
}
4345
}
4446

45-
private fun collectAnnotations(dataType: DataType, required: Boolean = false): List<Annotation> {
47+
private fun collectAnnotations(dataType: DataType, required: Boolean = false, parentHasValid: Boolean): List<Annotation> {
48+
return collectAnnotationsWithValid(dataType, required, parentHasValid).first
49+
}
50+
51+
private fun collectAnnotationsWithValid(dataType: DataType, required: Boolean = false, parentHasValid: Boolean): Pair<List<Annotation>, Boolean> {
4652
val annotations = mutableListOf<Annotation>()
53+
var valid = false
4754

48-
if (dataType.shouldHaveValid()) {
55+
if (!parentHasValid && dataType.shouldHaveValid(options)) {
4956
annotations.add(Annotation(validations.VALID))
57+
valid = true
5058
}
5159

5260
val sourceDataType = getSourceDataType(dataType)
@@ -78,7 +86,7 @@ open class BeanValidationFactory(
7886
annotations.add(createValuesAnnotation(dataType))
7987
}
8088

81-
return annotations
89+
return Pair(annotations, valid)
8290
}
8391

8492
private fun getSourceDataType(dataType: DataType): DataType {
@@ -168,24 +176,48 @@ open class BeanValidationFactory(
168176
}
169177
}
170178

171-
private fun DataType.shouldHaveValid(): Boolean {
172-
if (this is ModelDataType)
173-
return true
179+
private fun DataType.shouldHaveValid(options: ApiOptions): Boolean {
180+
if (options.beanValidationValidOnReactive) {
181+
if (this is SingleDataType)
182+
return true
183+
184+
if (this is ModelDataType)
185+
return true
174186

175-
if (this is ArrayDataType)
176-
return item is ModelDataType
187+
if (this is ArrayDataType)
188+
return item is ModelDataType
177189

178-
if (this is InterfaceDataType)
179-
return true
190+
if (this is InterfaceDataType)
191+
return true
192+
193+
if (this is MappedCollectionDataType)
194+
return multi
195+
196+
if (this is MappedSourceDataType) {
197+
return sourceDataType?.shouldHaveValid(options) ?: false
198+
}
180199

181-
if (this is MappedCollectionDataType)
182200
return false
183201

184-
if (this is MappedSourceDataType) {
185-
return sourceDataType?.shouldHaveValid() ?: false
186-
}
202+
} else {
203+
if (this is ModelDataType)
204+
return true
187205

188-
return false
206+
if (this is ArrayDataType)
207+
return item is ModelDataType
208+
209+
if (this is InterfaceDataType)
210+
return true
211+
212+
if (this is MappedCollectionDataType)
213+
return false
214+
215+
if (this is MappedSourceDataType) {
216+
return sourceDataType?.shouldHaveValid(options) ?: false
217+
}
218+
219+
return false
220+
}
189221
}
190222

191223
private fun DataType.isString(): Boolean = this is StringDataType

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/writer/java/BeanValidationInfo.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import io.openapiprocessor.core.model.datatypes.*
1111
data class BeanValidationValue(
1212
val dataTypeValue: String,
1313
val imports: Set<String>,
14-
val annotations: List<String>)
14+
val annotations: List<String>) // could be set?
1515

1616
interface BeanValidationInfo {
1717
val dataType: DataType

openapi-processor-core/src/test/groovy/com/github/hauner/openapi/core/writer/java/BeanValidationFactorySpec.groovy

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class BeanValidationFactorySpec extends Specification {
3434
'Foo', '', [:], null, false, null)
3535

3636
when:
37-
def info = validation.validate (dataType, false)
37+
def info = validation.validate (dataType, false, false)
3838

3939
then:
4040
def prop = info.prop
@@ -53,7 +53,7 @@ class BeanValidationFactorySpec extends Specification {
5353
def dataType = new OtherDataType()
5454

5555
when:
56-
def info = validation.validate (dataType, false)
56+
def info = validation.validate (dataType, false, false)
5757

5858
then:
5959
info.annotations == []
@@ -69,7 +69,7 @@ class BeanValidationFactorySpec extends Specification {
6969
def dataType = new StringDataType("string", constraints, false, null)
7070
7171
when:
72-
def info = validation.validate (dataType, false)
72+
def info = validation.validate (dataType, false, false)
7373
7474
then:
7575
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -96,7 +96,7 @@ class BeanValidationFactorySpec extends Specification {
9696
DataType dataType = new ArrayDataType(new NoneDataType(), constraints, false)
9797
9898
when:
99-
def info = validation.validate (dataType, false)
99+
def info = validation.validate (dataType, false, false)
100100
101101
then:
102102
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -126,11 +126,12 @@ class BeanValidationFactorySpec extends Specification {
126126
new StringDataType (),
127127
constraints,
128128
false,
129-
null
129+
null,
130+
false
130131
)
131132
132133
when:
133-
def info = validation.validate (dataType, false)
134+
def info = validation.validate (dataType, false, false)
134135
135136
then:
136137
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -152,7 +153,7 @@ class BeanValidationFactorySpec extends Specification {
152153
DataType dataType = createDataType (type, new DataTypeConstraints ())
153154
154155
when:
155-
def info = validation.validate (dataType, required)
156+
def info = validation.validate (dataType, required, false)
156157
157158
then:
158159
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -178,7 +179,7 @@ class BeanValidationFactorySpec extends Specification {
178179
DataType dataType = createDataType (type, constraints)
179180

180181
when:
181-
def info = validation.validate (dataType, false)
182+
def info = validation.validate (dataType, false, false)
182183

183184
then:
184185
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -216,7 +217,7 @@ class BeanValidationFactorySpec extends Specification {
216217
DataType dataType = createDataType (type, constraints)
217218

218219
when:
219-
def info = validation.validate (dataType, false)
220+
def info = validation.validate (dataType, false, false)
220221

221222
then:
222223
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -255,7 +256,7 @@ class BeanValidationFactorySpec extends Specification {
255256
DataType dataType = new DoubleDataType ("number:double", constraints, false, null)
256257

257258
when:
258-
def info = validation.validate (dataType, false)
259+
def info = validation.validate (dataType, false, false)
259260

260261
then:
261262
info.annotations.collect {it.imports }.flatten().containsAll (resultImports)
@@ -295,7 +296,8 @@ class BeanValidationFactorySpec extends Specification {
295296
new StringDataType (),
296297
constraints,
297298
false,
298-
null
299+
null,
300+
false
299301
)
300302
}
301303
null

openapi-processor-core/src/test/groovy/com/github/hauner/openapi/core/writer/java/MethodWriterSpec.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ class MethodWriterSpec extends Specification {
145145
where:
146146
collection | response
147147
new ArrayDataType (new StringDataType (), null, false) | 'String[]'
148-
new MappedCollectionDataType ('List', '', new StringDataType (), null, false, null) | 'List<String>'
149-
new MappedCollectionDataType ('Set', '', new StringDataType (), null, false, null) | 'Set<String>'
148+
new MappedCollectionDataType ('List', '', new StringDataType (), null, false, null, false) | 'List<String>'
149+
new MappedCollectionDataType ('Set', '', new StringDataType (), null, false, null, false) | 'Set<String>'
150150
}
151151
152152
void "writes parameter annotation" () {

openapi-processor-core/src/test/kotlin/io/openapiprocessor/core/writer/java/BeanValidationFactorySpec.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,46 @@ class BeanValidationFactorySpec : StringSpec({
194194
io.imports shouldBe setOf("${apiOptions.packageName}.validation.Values")
195195
io.annotations.shouldBeEmpty()
196196
}
197+
198+
"does apply @Valid annotations to single wrapper, not to the wrapped type" {
199+
val dataType = SingleDataType (
200+
"Single",
201+
"wrapper",
202+
ObjectDataType("Foo", "pkg", linkedMapOf("foo" to propertyDataType(StringDataType())))
203+
)
204+
val info = validation.validate(dataType, true)
205+
206+
val prop = info.prop
207+
prop.dataTypeValue shouldBe "Single<Foo>"
208+
prop.imports shouldBe setOf(validations.NOT_NULL, validations.VALID)
209+
prop.annotations shouldBe setOf("@Valid", "@NotNull")
210+
211+
val io = info.inout
212+
io.dataTypeValue shouldBe "@Valid @NotNull Single<Foo>"
213+
io.imports shouldBe setOf(validations.NOT_NULL, validations.VALID)
214+
io.annotations.shouldBeEmpty()
215+
}
216+
217+
"does apply @Valid annotations to multi wrapper, not to the wrapped type" {
218+
val dataType = MappedCollectionDataType(
219+
"Multi",
220+
"wrapper",
221+
ObjectDataType("Foo", "pkg", linkedMapOf("foo" to propertyDataType(StringDataType()))),
222+
null,
223+
false,
224+
multi = true
225+
)
226+
227+
val info = validation.validate(dataType, true)
228+
229+
val prop = info.prop
230+
prop.dataTypeValue shouldBe "Multi<Foo>"
231+
prop.imports shouldBe setOf(validations.NOT_NULL, validations.VALID)
232+
prop.annotations shouldBe setOf("@Valid", "@NotNull")
233+
234+
val io = info.inout
235+
io.dataTypeValue shouldBe "@Valid @NotNull Multi<Foo>"
236+
io.imports shouldBe setOf(validations.NOT_NULL, validations.VALID)
237+
io.annotations.shouldBeEmpty()
238+
}
197239
})

0 commit comments

Comments
 (0)