Skip to content

Instantiate introspected beans only when request values are present#12632

Open
iamsb97 wants to merge 5 commits into
micronaut-projects:5.0.xfrom
iamsb97:issue-12608
Open

Instantiate introspected beans only when request values are present#12632
iamsb97 wants to merge 5 commits into
micronaut-projects:5.0.xfrom
iamsb97:issue-12608

Conversation

@iamsb97
Copy link
Copy Markdown
Contributor

@iamsb97 iamsb97 commented Apr 24, 2026

Fixes #12608.

Avoid instantiating @Introspected beans for @QueryValue and @RequestBean when 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, @RequestBean and @Body as specified in the issue. Please let me know if there are other annotations that should follow the same behavior.

@sdelamo sdelamo requested review from Copilot and dstepanov April 28, 2026 04:29
@sdelamo sdelamo added this to 5.0.0-M3 Apr 28, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in 5.0.0-M3 Apr 28, 2026
@sdelamo sdelamo added the type: bug Something isn't working label Apr 28, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 @RequestBean binding to return an empty (satisfied) binding result when no properties bind to any present value.
  • Update @QueryValue POJO 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.

Comment on lines 93 to 97
Optional<Object> bindableResult = getBindableResult(source, argumentToBind);
if (bindableResult.isPresent()) {
bindingFound = true;
}
argumentValues[i] = constructorArgument.isOptional() ? bindableResult : bindableResult.orElse(null);
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
@iamsb97
Copy link
Copy Markdown
Contributor Author

iamsb97 commented May 14, 2026

@dstepanov, please review this PR when you get a chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug Something isn't working

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Introspected types are always instantiated when binding from request

3 participants