Instantiate introspected beans only when request values are present#12632
Instantiate introspected beans only when request values are present#12632iamsb97 wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses #12608 by preventing automatic instantiation of @Introspected POJOs during request binding when no request-provided values exist, so optional/nullable arguments can correctly resolve to null instead of an “empty” object (restoring expected validation behavior for required arguments).
Changes:
- Update
@RequestBeanbinding to return an empty (satisfied) binding result when no properties bind to any present value. - Update
@QueryValuePOJO binding to return an empty (satisfied) binding result when no query values (or defaults) are present. - Add/extend tests to assert null binding for nullable query objects, nullable request beans, and empty request bodies.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| http/src/main/java/io/micronaut/http/bind/binders/RequestBeanAnnotationBinder.java | Track whether any property actually binds before instantiating the request bean; return empty binding result when nothing bound. |
| http/src/main/java/io/micronaut/http/bind/binders/QueryValueArgumentBinder.java | Avoid building introspected POJOs for @QueryValue when no query values/defaults are present. |
| http-server-netty/src/test/groovy/io/micronaut/http/server/netty/binding/ParameterBindingSpec.groovy | Add coverage for missing-object query binding (400) and nullable-object query binding (null). |
| http-server-netty/src/test/groovy/io/micronaut/http/server/netty/binding/JsonBodyBindingSpec.groovy | Add coverage asserting @Body @Nullable introspected bean is null when body content is empty. |
| http-client/src/test/groovy/io/micronaut/http/client/aop/RequestBeanSpec.groovy | Add coverage asserting nullable @RequestBean resolves to null when no input is provided. |
| Optional<Object> bindableResult = getBindableResult(source, argumentToBind); | ||
| if (bindableResult.isPresent()) { | ||
| bindingFound = true; | ||
| } | ||
| argumentValues[i] = constructorArgument.isOptional() ? bindableResult : bindableResult.orElse(null); |
There was a problem hiding this comment.
bindingFound is set based on any property binder returning a present value. This includes framework-provided binders like HttpRequest, HttpHeaders, HttpParameters, Cookies, etc. (see DefaultRequestBinderRegistry where these are always present), which means a @RequestBean @Nullable argument may still be instantiated even when no user-supplied request values (query/header/body/etc.) are present. Consider excluding these always-satisfied types from bindingFound (or otherwise only counting bindings that reflect actual request input) so that nullable request beans can correctly resolve to null when nothing was provided.
|
@dstepanov, please review this PR when you get a chance. |
Fixes #12608.
Avoid instantiating
@Introspectedbeans for@QueryValueand@RequestBeanwhen no request values are present. Return null instead of an empty object.Existing behavior for required arguments (e.g. HTTP 400) is unchanged; this applies when the argument is treated as optional/nullable.
This change currently covers
@QueryValue,@RequestBeanand@Bodyas specified in the issue. Please let me know if there are other annotations that should follow the same behavior.