diff --git a/src/generators/kotlin/presets/ConstraintsPreset.ts b/src/generators/kotlin/presets/ConstraintsPreset.ts index 447abadae6..8e737cd186 100644 --- a/src/generators/kotlin/presets/ConstraintsPreset.ts +++ b/src/generators/kotlin/presets/ConstraintsPreset.ts @@ -3,6 +3,8 @@ import { ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, + ConstrainedObjectModel, + ConstrainedReferenceModel, ConstrainedStringModel } from '../../../models'; import { KotlinPreset } from '../KotlinPreset'; @@ -20,6 +22,9 @@ export const KOTLIN_CONSTRAINTS_PRESET: KotlinPreset = { renderer.dependencyManager.addDependency( `${importFrom}.validation.constraints.*` ); + renderer.dependencyManager.addDependency( + `${importFrom}.validation.Valid` + ); return content; }, property({ renderer, property, content }) { @@ -29,6 +34,15 @@ export const KOTLIN_CONSTRAINTS_PRESET: KotlinPreset = { annotations.push(renderer.renderAnnotation('NotNull', null, 'get:')); } + // Add @Valid for cascade validation on array/object/reference fields + if ( + property.property instanceof ConstrainedReferenceModel || + property.property instanceof ConstrainedObjectModel || + property.property instanceof ConstrainedArrayModel + ) { + annotations.push(renderer.renderAnnotation('Valid', null, 'get:')); + } + annotations.push( ...getTypeSpecificAnnotations(property.property, renderer) ); diff --git a/test/generators/kotlin/presets/ConstraintsPreset.spec.ts b/test/generators/kotlin/presets/ConstraintsPreset.spec.ts index 23e84ffcca..45ebb816d0 100644 --- a/test/generators/kotlin/presets/ConstraintsPreset.spec.ts +++ b/test/generators/kotlin/presets/ConstraintsPreset.spec.ts @@ -12,11 +12,23 @@ describe('KOTLIN_CONSTRAINTS_PRESET', () => { required: ['min_number_prop', 'max_number_prop'] }; + const docWithNestedObject = { + $id: 'NestedClazz', + type: 'object', + properties: { + array_prop: { type: 'array', items: { type: 'string' } }, + obj_prop: { type: 'object', properties: { inner: { type: 'string' } } } + } + }; + test('should render javax constraints annotations by default', async () => { const generator = new KotlinGenerator({ presets: [KOTLIN_CONSTRAINTS_PRESET] }); - const expectedDependencies = ['import javax.validation.constraints.*']; + const expectedDependencies = [ + 'import javax.validation.constraints.*', + 'import javax.validation.Valid' + ]; const models = await generator.generate(doc); expect(models).toHaveLength(1); @@ -36,7 +48,10 @@ describe('KOTLIN_CONSTRAINTS_PRESET', () => { ] }); - const expectedDependencies = ['import javax.validation.constraints.*']; + const expectedDependencies = [ + 'import javax.validation.constraints.*', + 'import javax.validation.Valid' + ]; const models = await generator.generate(doc); expect(models).toHaveLength(1); @@ -56,11 +71,25 @@ describe('KOTLIN_CONSTRAINTS_PRESET', () => { ] }); - const expectedDependencies = ['import jakarta.validation.constraints.*']; + const expectedDependencies = [ + 'import jakarta.validation.constraints.*', + 'import jakarta.validation.Valid' + ]; const models = await generator.generate(doc); expect(models).toHaveLength(1); expect(models[0].result).toMatchSnapshot(); expect(models[0].dependencies).toEqual(expectedDependencies); }); + + test('should render @Valid annotation for array and object properties', async () => { + const generator = new KotlinGenerator({ + presets: [KOTLIN_CONSTRAINTS_PRESET] + }); + + const models = await generator.generate(docWithNestedObject); + expect(models.length).toBeGreaterThanOrEqual(1); + expect(models[0].result).toContain('@get:Valid'); + expect(models[0].result).toMatchSnapshot(); + }); });