Search code examples
bean-validationmicronaut

Micronaut custom validation Annotation does not work


I was trying to write a custom annotation to validate a field in a Micronaut project, I came across this section in their documentation Defining Additional Constraints

My understanding was that is completely possible to write my own annotation to validate a field in my POJO but after trying for hours, I can't get my validation to work, it simply does not get invoked, could it be I'm missing something fundamental about the way how Micronaut works?

Annotation

@Retention(RUNTIME)
@Constraint(validatedBy = [])
annotation class FieldValidator(
    val message: String = "invalid format ({validatedValue})"
)

Factory

@Factory
class ValidatorFactory {

    @Singleton
    fun fieldPatternValidator(): ConstraintValidator<FieldValidator, CharSequence> {
        return ConstraintValidator { value, annotation, context ->
            context.messageTemplate("invalid format ({validatedValue}), should be test") 
            value == "test"
        }
    }
}

Filter

@Introspected
data class HelloWorldFilter(
    @FieldValidator
    val field: String?
)

Controller

@Controller("/hello")
open class HelloController() {

    @Get("{?filters*}")
    @Produces(MediaType.TEXT_PLAIN)
    open fun index(@Valid filters: HelloWorldFilter): String {
        return filters.toString()
    }
}

I have a small demo on Github, to reproduce

  1. run ./gradlew run

  2. call http://localhost:8080/hello?field=abc that expected behaviour should be bad request since the field is matching the desired value.


Solution

  • Using your demo project, I changed your HelloWorldFilter class to

    @Introspected
    data class HelloWorldFilter(
        @field:FieldValidator
        val field: String?
    )
    

    Ran it, then:

    curl "http://localhost:8080/hello?field=abc"
    

    Output was as you expect:

    {"message":"Bad Request","_embedded":{"errors":[{"message":"filters.field: invalid format (abc), should be test"}]},"_links":{"self":{"href":"/hello?field=abc","templated":false}}}
    

    With:

    curl "http://localhost:8080/hello?field=test"
    

    Output:

    HelloWorldFilter(field=test)