Skip to content

Commit

Permalink
Use selected validation library for controllers too (#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
ascheja authored Aug 22, 2023
1 parent a45f785 commit 81a003c
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 60 deletions.
2 changes: 2 additions & 0 deletions src/main/kotlin/com/cjbooms/fabrikt/cli/CodeGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,14 @@ class CodeGenerator(
ControllerCodeGenTargetType.SPRING -> SpringControllerInterfaceGenerator(
packages,
sourceApi,
MutableSettings.validationLibrary().annotations,
MutableSettings.controllerOptions()
)

ControllerCodeGenTargetType.MICRONAUT -> MicronautControllerInterfaceGenerator(
packages,
sourceApi,
MutableSettings.validationLibrary().annotations,
MutableSettings.controllerOptions()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ abstract class ValidationAnnotations(packageName: String) {
.useSiteTarget(AnnotationSpec.UseSiteTarget.GET)
.build()

fun parameterValid() = AnnotationSpec
.builder(validClass)
.build()

fun min(value: Int) = AnnotationSpec
.builder(minClass)
.addMember("%L", value)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.cjbooms.fabrikt.generators.controller

import com.cjbooms.fabrikt.configurations.Packages
import com.cjbooms.fabrikt.generators.controller.metadata.JavaXAnnotations
import com.cjbooms.fabrikt.generators.ValidationAnnotations
import com.cjbooms.fabrikt.model.ControllerType
import com.cjbooms.fabrikt.model.KotlinTypes
import com.cjbooms.fabrikt.model.RequestParameter
Expand All @@ -16,7 +16,8 @@ import com.squareup.kotlinpoet.TypeSpec

abstract class ControllerInterfaceGenerator(
private val packages: Packages,
private val api: SourceApi
private val api: SourceApi,
private val validationAnnotations: ValidationAnnotations,
) {
abstract fun generate(): KotlinTypes
abstract fun buildFunction(path: Path, op: Operation, verb: String): FunSpec
Expand Down Expand Up @@ -45,9 +46,9 @@ abstract class ControllerInterfaceGenerator(
)
}
fun ParameterSpec.Builder.addValidationAnnotations(parameter: RequestParameter): ParameterSpec.Builder {
if (parameter.minimum != null) this.addAnnotation(JavaXAnnotations.min(parameter.minimum.toInt()))
if (parameter.maximum != null) this.addAnnotation(JavaXAnnotations.max(parameter.maximum.toInt()))
if (parameter.typeInfo.isComplexType) this.addAnnotation(JavaXAnnotations.validBuilder().build())
if (parameter.minimum != null) this.addAnnotation(validationAnnotations.min(parameter.minimum.toInt()))
if (parameter.maximum != null) this.addAnnotation(validationAnnotations.max(parameter.maximum.toInt()))
if (parameter.typeInfo.isComplexType) this.addAnnotation(validationAnnotations.parameterValid())
return this
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import com.cjbooms.fabrikt.cli.ControllerCodeGenOptionType
import com.cjbooms.fabrikt.configurations.Packages
import com.cjbooms.fabrikt.generators.GeneratorUtils.toIncomingParameters
import com.cjbooms.fabrikt.generators.GeneratorUtils.toKdoc
import com.cjbooms.fabrikt.generators.ValidationAnnotations
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.SecuritySupport
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.happyPathResponse
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.methodName
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.securitySupport
import com.cjbooms.fabrikt.generators.controller.metadata.JavaXAnnotations
import com.cjbooms.fabrikt.generators.controller.metadata.MicronautImports
import com.cjbooms.fabrikt.generators.controller.metadata.MicronautImports.SECURITY_RULE_IS_ANONYMOUS
import com.cjbooms.fabrikt.generators.controller.metadata.MicronautImports.SECURITY_RULE_IS_AUTHENTICATED
Expand All @@ -35,8 +35,9 @@ import com.squareup.kotlinpoet.TypeSpec
class MicronautControllerInterfaceGenerator(
private val packages: Packages,
private val api: SourceApi,
private val validationAnnotations: ValidationAnnotations,
private val options: Set<ControllerCodeGenOptionType> = emptySet(),
) : ControllerInterfaceGenerator(packages, api) {
) : ControllerInterfaceGenerator(packages, api, validationAnnotations) {

private val useSuspendModifier: Boolean
get() = options.any { it == ControllerCodeGenOptionType.SUSPEND_MODIFIER }
Expand Down Expand Up @@ -97,7 +98,7 @@ class MicronautControllerInterfaceGenerator(
AnnotationSpec
.builder(MicronautImports.BODY).build(),
)
.addAnnotation(JavaXAnnotations.validBuilder().build())
.addAnnotation(validationAnnotations.parameterValid())
.build()

is RequestParameter ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import com.cjbooms.fabrikt.cli.ControllerCodeGenOptionType
import com.cjbooms.fabrikt.configurations.Packages
import com.cjbooms.fabrikt.generators.GeneratorUtils.toIncomingParameters
import com.cjbooms.fabrikt.generators.GeneratorUtils.toKdoc
import com.cjbooms.fabrikt.generators.ValidationAnnotations
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.happyPathResponse
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.methodName
import com.cjbooms.fabrikt.generators.controller.ControllerGeneratorUtils.securitySupport
import com.cjbooms.fabrikt.generators.controller.metadata.JavaXAnnotations
import com.cjbooms.fabrikt.generators.controller.metadata.SpringAnnotations
import com.cjbooms.fabrikt.generators.controller.metadata.SpringImports
import com.cjbooms.fabrikt.model.BodyParameter
Expand All @@ -34,8 +34,9 @@ import com.squareup.kotlinpoet.TypeSpec
class SpringControllerInterfaceGenerator(
private val packages: Packages,
private val api: SourceApi,
private val validationAnnotations: ValidationAnnotations,
private val options: Set<ControllerCodeGenOptionType> = emptySet(),
) : ControllerInterfaceGenerator(packages, api) {
) : ControllerInterfaceGenerator(packages, api, validationAnnotations) {

private val addAuthenticationParameter: Boolean
get() = options.any { it == ControllerCodeGenOptionType.AUTHENTICATION }
Expand Down Expand Up @@ -82,7 +83,7 @@ class SpringControllerInterfaceGenerator(
it
.toParameterSpecBuilder()
.addAnnotation(SpringAnnotations.requestBodyBuilder().build())
.addAnnotation(JavaXAnnotations.validBuilder().build())
.addAnnotation(validationAnnotations.parameterValid())
.build()
is RequestParameter ->
it
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ class MicronautAuthenticationTest {

private fun setupTest(testPath: String): Collection<FileSpec> {
val api = SourceApi(readTextResource("/authenticationTest/$testPath"))
return MicronautControllerInterfaceGenerator(Packages(basePackage), api, setOf(ControllerCodeGenOptionType.AUTHENTICATION)).generate().files
return MicronautControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
setOf(ControllerCodeGenOptionType.AUTHENTICATION)
).generate().files
}

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.cjbooms.fabrikt.generators
import com.cjbooms.fabrikt.cli.CodeGenerationType
import com.cjbooms.fabrikt.cli.ControllerCodeGenOptionType
import com.cjbooms.fabrikt.cli.ControllerCodeGenTargetType
import com.cjbooms.fabrikt.cli.ValidationLibrary
import com.cjbooms.fabrikt.configurations.Packages
import com.cjbooms.fabrikt.generators.controller.MicronautControllerInterfaceGenerator
import com.cjbooms.fabrikt.generators.controller.MicronautControllers
Expand All @@ -20,6 +21,7 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.EnumSource
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream

Expand All @@ -36,9 +38,9 @@ class MicronautControllerGeneratorTest {
"parameterNameClash",
)

private fun setupGithubApiTestEnv() {
private fun setupGithubApiTestEnv(validationAnnotations: ValidationAnnotations = JavaxValidationAnnotations) {
val api = SourceApi(readTextResource("/examples/githubApi/api.yaml"))
generated = MicronautControllerInterfaceGenerator(Packages(basePackage), api).generate().files
generated = MicronautControllerInterfaceGenerator(Packages(basePackage), api, validationAnnotations).generate().files
}

@BeforeEach
Expand All @@ -62,6 +64,7 @@ class MicronautControllerGeneratorTest {
val controllers = MicronautControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
).generate().toSingleFile()

assertThat(controllers).isEqualTo(expectedControllers)
Expand All @@ -76,6 +79,7 @@ class MicronautControllerGeneratorTest {
val controllers = MicronautControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
setOf(ControllerCodeGenOptionType.AUTHENTICATION),
).generate().toSingleFile()

Expand Down Expand Up @@ -121,10 +125,30 @@ class MicronautControllerGeneratorTest {
)
}

@ParameterizedTest
@EnumSource(ValidationLibrary::class)
fun `ensure controller method parameters have correct validation annotations`(library: ValidationLibrary) {
setupGithubApiTestEnv(library.annotations)
val desiredPackagePrefix = when (library) {
ValidationLibrary.JAVAX_VALIDATION -> "javax.validation."
ValidationLibrary.JAKARTA_VALIDATION -> "jakarta.validation."
}
val parameterValidationAnnotations = generated
.flatMap { it.members }
.filterIsInstance<TypeSpec>()
.flatMap { it.funSpecs }
.flatMap { it.parameters }
.flatMap { it.annotations }
.map { it.className.canonicalName }
.filter { ".validation." in it }
.distinct()
assertThat(parameterValidationAnnotations).allMatch { it.startsWith(desiredPackagePrefix) }
}

@Test
fun `ensure that subresource specific controllers are created`() {
val api = SourceApi(readTextResource("/examples/githubApi/api.yaml"))
val controllers = MicronautControllerInterfaceGenerator(Packages(basePackage), api).generate()
val controllers = MicronautControllerInterfaceGenerator(Packages(basePackage), api, JavaxValidationAnnotations).generate()

assertThat(controllers.files).size().isEqualTo(6)
assertThat(controllers.files.map { it.name }).containsAll(
Expand Down Expand Up @@ -165,6 +189,7 @@ class MicronautControllerGeneratorTest {
val controllers = MicronautControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
setOf(ControllerCodeGenOptionType.SUSPEND_MODIFIER),
).generate()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ class SpringAuthenticationTest {

private fun setupTest(testPath: String): Collection<FileSpec> {
val api = SourceApi(readTextResource("/authenticationTest/$testPath"))
return SpringControllerInterfaceGenerator(Packages(basePackage), api, setOf(ControllerCodeGenOptionType.AUTHENTICATION)).generate().files
return SpringControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
setOf(ControllerCodeGenOptionType.AUTHENTICATION)
).generate().files
}

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.cjbooms.fabrikt.generators

import com.cjbooms.fabrikt.cli.CodeGenerationType
import com.cjbooms.fabrikt.cli.ControllerCodeGenOptionType
import com.cjbooms.fabrikt.cli.ValidationLibrary
import com.cjbooms.fabrikt.configurations.Packages
import com.cjbooms.fabrikt.generators.controller.SpringControllerInterfaceGenerator
import com.cjbooms.fabrikt.generators.controller.SpringControllers
Expand All @@ -19,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.EnumSource
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream

Expand All @@ -35,9 +37,9 @@ class SpringControllerGeneratorTest {
"parameterNameClash",
)

private fun setupGithubApiTestEnv() {
private fun setupGithubApiTestEnv(annotations: ValidationAnnotations = JavaxValidationAnnotations) {
val api = SourceApi(readTextResource("/examples/githubApi/api.yaml"))
generated = SpringControllerInterfaceGenerator(Packages(basePackage), api).generate().files
generated = SpringControllerInterfaceGenerator(Packages(basePackage), api, annotations).generate().files
}

@BeforeEach
Expand All @@ -58,6 +60,7 @@ class SpringControllerGeneratorTest {
val controllers = SpringControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
).generate().toSingleFile()

assertThat(controllers).isEqualTo(expectedControllers)
Expand All @@ -72,6 +75,7 @@ class SpringControllerGeneratorTest {
val controllers = SpringControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
setOf(ControllerCodeGenOptionType.AUTHENTICATION),
).generate().toSingleFile()

Expand Down Expand Up @@ -119,10 +123,30 @@ class SpringControllerGeneratorTest {
)
}

@ParameterizedTest
@EnumSource(ValidationLibrary::class)
fun `ensure controller method parameters have correct validation annotations`(library: ValidationLibrary) {
setupGithubApiTestEnv(library.annotations)
val desiredPackagePrefix = when (library) {
ValidationLibrary.JAVAX_VALIDATION -> "javax.validation."
ValidationLibrary.JAKARTA_VALIDATION -> "jakarta.validation."
}
val parameterValidationAnnotations = generated
.flatMap { it.members }
.filterIsInstance<TypeSpec>()
.flatMap { it.funSpecs }
.flatMap { it.parameters }
.flatMap { it.annotations }
.map { it.className.canonicalName }
.filter { ".validation." in it }
.distinct()
assertThat(parameterValidationAnnotations).allMatch { it.startsWith(desiredPackagePrefix) }
}

@Test
fun `ensure that subresource specific controllers are created`() {
val api = SourceApi(readTextResource("/examples/githubApi/api.yaml"))
val controllers = SpringControllerInterfaceGenerator(Packages(basePackage), api).generate()
val controllers = SpringControllerInterfaceGenerator(Packages(basePackage), api, JavaxValidationAnnotations).generate()

assertThat(controllers.files).size().isEqualTo(6)
assertThat(controllers.files.map { it.name }).containsAll(
Expand Down Expand Up @@ -163,6 +187,7 @@ class SpringControllerGeneratorTest {
val controllers = SpringControllerInterfaceGenerator(
Packages(basePackage),
api,
JavaxValidationAnnotations,
setOf(ControllerCodeGenOptionType.SUSPEND_MODIFIER),
).generate()

Expand Down Expand Up @@ -194,7 +219,7 @@ class SpringControllerGeneratorTest {
@Test
fun `controller parameters should have spring DateTimeFormat annotations`() {
val api = SourceApi(readTextResource("/examples/springFormatDateAndDateTime/api.yaml"))
val controllers = SpringControllerInterfaceGenerator(Packages(basePackage), api).generate().toSingleFile()
val controllers = SpringControllerInterfaceGenerator(Packages(basePackage), api, JavaxValidationAnnotations).generate().toSingleFile()
val expectedControllers = readTextResource("/examples/springFormatDateAndDateTime/controllers/Controllers.kt")

assertThat(controllers.trim()).isEqualTo(expectedControllers.trim())
Expand Down

0 comments on commit 81a003c

Please sign in to comment.