Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Micronaut 4 Validation - Cannot use dependency injection in custom validator classes #258

Closed
MattyCi opened this issue Nov 15, 2023 · 8 comments · Fixed by #336
Closed
Labels
type: improvement A minor improvement to an existing feature

Comments

@MattyCi
Copy link

MattyCi commented Nov 15, 2023

Expected Behavior

Hello, I previously followed this documentation here to create a custom validator class using Micronaut 3. My validator class used @Inject to inject a singleton service class to be used in my validator, and this worked without issue.

Here is an example:
https://github.com/MattyCi/seasongg-services/blob/e1f0aea71f1920896474278c15f3a22a459aa418/src/main/java/com/sgg/users/UserRegistrationValidator.java

In Micronaut 4, I would expect the same behavior to work.

Actual Behaviour

However, in Micronaut 4, there are different errors thrown depending on how you go about using dependency injection:

  • using @Inject on a field:
Caused by: java.lang.NullPointerException: Cannot invoke "com.example.SomeService.logUserName(String)" because "this.someService" is null
  • using constructor injection:
io.micronaut.core.reflect.exception.InstantiationException: No default constructor exists
	at io.micronaut.inject.beans.AbstractInitializableBeanIntrospection.instantiate(AbstractInitializableBeanIntrospection.java:292)
	at io.micronaut.validation.validator.DefaultValidator.validateConstrains(DefaultValidator.java:1352)
	at io.micronaut.validation.validator.DefaultValidator.visitElement(DefaultValidator.java:1113)
	at io.micronaut.validation.validator.DefaultValidator.visitElement(DefaultValidator.java:1086)
	at io.micronaut.validation.validator.DefaultValidator.visitElement(DefaultValidator.java:1069)
	at io.micronaut.validation.validator.DefaultValidator.validateParametersInternal(DefaultValidator.java:915)
	at io.micronaut.validation.validator.DefaultValidator.validateParameters(DefaultValidator.java:356)
	at io.micronaut.validation.ValidatingInterceptor.intercept(ValidatingInterceptor.java:113)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:137)
	at com.example.$UserController$Definition$Intercepted.helloUser(Unknown Source)
	at com.example.$UserController$Definition$Exec.dispatch(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethodsDefinition$DispatchedExecutableMethod.invokeUnsafe(AbstractExecutableMethodsDefinition.java:447)
	at io.micronaut.context.DefaultBeanContext$BeanContextUnsafeExecutionHandle.invokeUnsafe(DefaultBeanContext.java:4184)
	at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:263)
	at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:74)
	at io.micronaut.http.server.RouteExecutor.executeRouteAndConvertBody(RouteExecutor.java:480)
	at io.micronaut.http.server.RouteExecutor.callRoute(RouteExecutor.java:470)
	at io.micronaut.http.server.RequestLifecycle.lambda$normalFlow$2(RequestLifecycle.java:146)
	at io.micronaut.core.execution.ImperativeExecutionFlowImpl.flatMap(ImperativeExecutionFlowImpl.java:72)
	at io.micronaut.http.server.RequestLifecycle.lambda$normalFlow$4(RequestLifecycle.java:146)
	at io.micronaut.http.server.RequestLifecycle.lambda$runWithFilters$14(RequestLifecycle.java:264)
	at io.micronaut.http.filter.FilterRunner.processRequestFilter(FilterRunner.java:306)
	at io.micronaut.http.filter.FilterRunner.filterRequest0(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.lambda$filterRequest0$3(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.processRequestFilter(FilterRunner.java:242)
	at io.micronaut.http.filter.FilterRunner.filterRequest0(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.lambda$filterRequest0$3(FilterRunner.java:183)
	at io.micronaut.core.execution.ImperativeExecutionFlowImpl.flatMap(ImperativeExecutionFlowImpl.java:72)
	at io.micronaut.http.filter.FilterRunner.processRequestFilter(FilterRunner.java:272)
	at io.micronaut.http.filter.FilterRunner.filterRequest0(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.filterRequest(FilterRunner.java:167)
	at io.micronaut.http.filter.FilterRunner.run(FilterRunner.java:162)
	at io.micronaut.http.server.RequestLifecycle.runWithFilters(RequestLifecycle.java:281)
	at io.micronaut.http.server.RequestLifecycle.normalFlow(RequestLifecycle.java:143)
	at io.micronaut.http.server.netty.NettyRequestLifecycle.handleNormal(NettyRequestLifecycle.java:85)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.accept(RoutingInBoundHandler.java:220)
	at io.micronaut.http.server.netty.handler.PipeliningServerHandler$OptimisticBufferingInboundHandler.read(PipeliningServerHandler.java:422)
	at io.micronaut.http.server.netty.handler.PipeliningServerHandler.channelRead(PipeliningServerHandler.java:206)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
	at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)
  • BeanContext manually:
Message: No bean of type [io.micronaut.reactor.config.ReactorConfiguration] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new ReactorInstrumentation(ReactorConfiguration configuration) --> new ReactorInstrumentation([ReactorConfiguration configuration])
	at io.micronaut.context.DefaultBeanContext.initializeContext(DefaultBeanContext.java:1979)
	at io.micronaut.context.DefaultBeanContext.readAllBeanDefinitionClasses(DefaultBeanContext.java:3337)
	at io.micronaut.context.DefaultBeanContext.finalizeConfiguration(DefaultBeanContext.java:3690)
	at io.micronaut.context.DefaultBeanContext.start(DefaultBeanContext.java:345)
	at io.micronaut.context.DefaultBeanContext.start(DefaultBeanContext.java:156)
	at io.micronaut.context.BeanContext.run(BeanContext.java:311)
	at com.example.UserRegistrationValidator.isValid(UserRegistrationValidator.java:28)
	at com.example.UserRegistrationValidator.isValid(UserRegistrationValidator.java:12)
	at io.micronaut.validation.validator.DefaultValidator.validateConstrains(DefaultValidator.java:1398)
	at io.micronaut.validation.validator.DefaultValidator.visitElement(DefaultValidator.java:1113)
	at io.micronaut.validation.validator.DefaultValidator.visitElement(DefaultValidator.java:1086)
	at io.micronaut.validation.validator.DefaultValidator.visitElement(DefaultValidator.java:1069)
	at io.micronaut.validation.validator.DefaultValidator.validateParametersInternal(DefaultValidator.java:915)
	at io.micronaut.validation.validator.DefaultValidator.validateParameters(DefaultValidator.java:356)
	at io.micronaut.validation.ValidatingInterceptor.intercept(ValidatingInterceptor.java:113)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:137)
	at com.example.$UserController$Definition$Intercepted.helloUser(Unknown Source)
	at com.example.$UserController$Definition$Exec.dispatch(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethodsDefinition$DispatchedExecutableMethod.invokeUnsafe(AbstractExecutableMethodsDefinition.java:447)
	at io.micronaut.context.DefaultBeanContext$BeanContextUnsafeExecutionHandle.invokeUnsafe(DefaultBeanContext.java:4184)
	at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:263)
	at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:74)
	at io.micronaut.http.server.RouteExecutor.executeRouteAndConvertBody(RouteExecutor.java:480)
	at io.micronaut.http.server.RouteExecutor.callRoute(RouteExecutor.java:470)
	at io.micronaut.http.server.RequestLifecycle.lambda$normalFlow$2(RequestLifecycle.java:146)
	at io.micronaut.core.execution.ImperativeExecutionFlowImpl.flatMap(ImperativeExecutionFlowImpl.java:72)
	at io.micronaut.http.server.RequestLifecycle.lambda$normalFlow$4(RequestLifecycle.java:146)
	at io.micronaut.http.server.RequestLifecycle.lambda$runWithFilters$14(RequestLifecycle.java:264)
	at io.micronaut.http.filter.FilterRunner.processRequestFilter(FilterRunner.java:306)
	at io.micronaut.http.filter.FilterRunner.filterRequest0(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.lambda$filterRequest0$3(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.processRequestFilter(FilterRunner.java:242)
	at io.micronaut.http.filter.FilterRunner.filterRequest0(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.lambda$filterRequest0$3(FilterRunner.java:183)
	at io.micronaut.core.execution.ImperativeExecutionFlowImpl.flatMap(ImperativeExecutionFlowImpl.java:72)
	at io.micronaut.http.filter.FilterRunner.processRequestFilter(FilterRunner.java:272)
	at io.micronaut.http.filter.FilterRunner.filterRequest0(FilterRunner.java:183)
	at io.micronaut.http.filter.FilterRunner.filterRequest(FilterRunner.java:167)
	at io.micronaut.http.filter.FilterRunner.run(FilterRunner.java:162)
	at io.micronaut.http.server.RequestLifecycle.runWithFilters(RequestLifecycle.java:281)
	at io.micronaut.http.server.RequestLifecycle.normalFlow(RequestLifecycle.java:143)
	at io.micronaut.http.server.netty.NettyRequestLifecycle.handleNormal(NettyRequestLifecycle.java:85)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.accept(RoutingInBoundHandler.java:220)
	at io.micronaut.http.server.netty.handler.PipeliningServerHandler$OptimisticBufferingInboundHandler.read(PipeliningServerHandler.java:422)
	at io.micronaut.http.server.netty.handler.PipeliningServerHandler.channelRead(PipeliningServerHandler.java:206)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
	at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [configuration] of class: io.micronaut.reactor.instrument.ReactorInstrumentation

Message: No bean of type [io.micronaut.reactor.config.ReactorConfiguration] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new ReactorInstrumentation(ReactorConfiguration configuration) --> new ReactorInstrumentation([ReactorConfiguration configuration])
	at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:2181)
	at io.micronaut.context.AbstractInitializableBeanDefinition.getBeanForConstructorArgument(AbstractInitializableBeanDefinition.java:1328)
	at io.micronaut.reactor.instrument.$ReactorInstrumentation$Definition.instantiate(Unknown Source)
	at io.micronaut.context.DefaultBeanContext.resolveByBeanFactory(DefaultBeanContext.java:2307)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2277)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2289)
	at io.micronaut.context.DefaultBeanContext.createRegistration(DefaultBeanContext.java:3056)
	at io.micronaut.context.SingletonScope.getOrCreate(SingletonScope.java:81)
	at io.micronaut.context.DefaultBeanContext.findOrCreateSingletonBeanRegistration(DefaultBeanContext.java:2958)
	at io.micronaut.context.DefaultBeanContext.initializeEagerBean(DefaultBeanContext.java:2676)
	at io.micronaut.context.DefaultBeanContext.initializeContext(DefaultBeanContext.java:1973)
	... 85 more
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.micronaut.reactor.config.ReactorConfiguration] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
	at io.micronaut.context.DefaultBeanContext.newNoSuchBeanException(DefaultBeanContext.java:2773)
	at io.micronaut.context.DefaultBeanContext.resolveBeanRegistration(DefaultBeanContext.java:2735)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1693)
	at io.micronaut.context.AbstractBeanResolutionContext.getBean(AbstractBeanResolutionContext.java:89)
	at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:2165)
	... 95 more

Steps To Reproduce

  • Clone my sample repo containing the example:
    • git clone git@github.com:MattyCi/validator-issue.git
  • build the project and run
    • ./gradlew build
    • ./gradlew run
  • run the following cURL request to create the error:
curl --location 'http://127.0.0.1:8080/user' \
--header 'Content-Type: application/json' \
--data '{
    "username": "matt",
    "password": "test",
    "passwordVerify": "test"
}'

The main class in question is com.example.UserRegistrationValidator

Environment Information

OS: Win 10

JDK:

openjdk version "17.0.7" 2023-04-18 LTS
OpenJDK Runtime Environment Corretto-17.0.7.7.1 (build 17.0.7+7-LTS)                  
OpenJDK 64-Bit Server VM Corretto-17.0.7.7.1 (build 17.0.7+7-LTS, mixed mode, sharing)

Example Application

https://github.com/MattyCi/validator-issue

Version

4.0.4

@yawkat
Copy link
Member

yawkat commented Nov 15, 2023

i think this is a bug. it seems validators are only constructed through introspection.instantiate(), even if the docs suggest otherwise. It also seems the MyValidatorFactory from the docs is not tested and I don't see how it can work. wdyt @dstepanov @andriy-dmytruk

@dstepanov
Copy link
Contributor

Right now, it's only instantiated using the bean introspection.
@yawkat Where is the note about it in the docs?

@yawkat
Copy link
Member

yawkat commented Nov 15, 2023

@dstepanov MyValidatorFactory in the docs shows a validator that is meant to be instantiated through bean context

@dstepanov
Copy link
Contributor

I see. It's a bit confusing, that would work only if there is no validatedBy, those are required to be introspected. I'm going to implement retrieving them from the context as well.

@yawkat
Copy link
Member

yawkat commented Nov 15, 2023

could be called a framework improvement or a docs bug then :)

@markwimpory
Copy link

Plus one vote from me on this one. I spent a happy day or so trying to figure out what was going on!

@loicmathieu
Copy link

Reading this issue, it also explains why it is no longer possible to replace a validator as I discover in #278

@jeremyg484
Copy link
Contributor

At least with the current version, removing @Introspected from a validator that is a dependency injected bean will work as desired. As it doesn't make much sense to use @Introspected in this case, I am proposing that we simply remove @Introspected from the relevant documentation example to eliminate this confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: improvement A minor improvement to an existing feature
Projects
No open projects
Status: Done
Development

Successfully merging a pull request may close this issue.

6 participants