You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
JSpecify: False positive error for nullable source with nullable-param non-null-return method #4086
When a @Nullable source property is mapped to a @NonNull constructor parameter via a reused mapping method that accepts @Nullable (explicitly handles null) and returns a non-null value, the mapping should compile successfully. The reused method's parameter and return type annotations prove the mapping is safe - null is handled and the result is guaranteed non-null.
error: Can't map potentially nullable source property "value" to @NonNull
constructor parameter "payload". Consider adding a defaultValue or defaultExpression.
The current check only inspects the source getter chain nullability, which reports NULLABLE. It does not consider that the assignment was resolved through a reused method whose parameter is @Nullable (no null guard needed before the call) and whose return type is @NonNull (the result is guaranteed non-null).
Steps to reproduce the problem
A @Nullable source property mapped to a @NonNull constructor parameter
via qualifiedByName referencing a method with @Nullable parameter and non-null return. Can be reproduced in this branch: main...RaniAgus:mapstruct:issues/4086
The condition only looks at the source property and the target constructor parameter. It has assignment in scope but never consults it — so a value routed through a qualified method whose return type is non-null is treated identically to a value assigned directly. In the reported case mapValue(@Nullable String) -> Target.Nested makes the result provably non-null, and the diagnostic still fires.
The obstacle to the obvious fix — "skip the error when the assignment's method returns non-null" — is that the return nullability isn't reachable from there. MethodReference takes a Method in its constructor but only retains method.getReturnType():
NullabilityResolver.getNullability(ExecutableElement, ...) already returns the return type nullability for an ExecutableElement, so the resolver side needs nothing new — the missing piece is that the ExecutableElement (or a precomputed nullability flag) isn't carried on MethodReference to the point where the check runs.
So the fix seems to need one of:
retain the Method on MethodReference, or
compute the return Nullability at construction and store that flag,
then gate the diagnostic on it. (2) is narrower but still touches a core model class on every mapping path, so it's worth a maintainer opinion on the preferred shape before someone writes it.
Worth noting the same gap likely affects #4081 — both are the reused-method return-nullability path not being considered.
I haven't opened a PR; flagging the analysis rather than guessing at the architecture.
Activity
tests: reproduce mapstruct#4086
mapstruct#4086: Check nullable status of methode return types
tests: reproduce mapstruct#4086
mapstruct#4086: Check nullable status of methode return types
r0h1tb commentedon Aug 1, 2026
I had a go at this and got as far as pinning the root cause, so posting it in case it's useful to whoever picks it up.
The error is raised in
PropertyMapping.java(PropertyMappingBuilder.build(), ~L286–303):The condition only looks at the source property and the target constructor parameter. It has
assignmentin scope but never consults it — so a value routed through a qualified method whose return type is non-null is treated identically to a value assigned directly. In the reported casemapValue(@Nullable String) -> Target.Nestedmakes the result provably non-null, and the diagnostic still fires.The obstacle to the obvious fix — "skip the error when the assignment's method returns non-null" — is that the return nullability isn't reachable from there.
MethodReferencetakes aMethodin its constructor but only retainsmethod.getReturnType():NullabilityResolver.getNullability(ExecutableElement, ...)already returns the return type nullability for anExecutableElement, so the resolver side needs nothing new — the missing piece is that theExecutableElement(or a precomputed nullability flag) isn't carried onMethodReferenceto the point where the check runs.So the fix seems to need one of:
MethodonMethodReference, orNullabilityat construction and store that flag,then gate the diagnostic on it. (2) is narrower but still touches a core model class on every mapping path, so it's worth a maintainer opinion on the preferred shape before someone writes it.
Worth noting the same gap likely affects #4081 — both are the reused-method return-nullability path not being considered.
I haven't opened a PR; flagging the analysis rather than guessing at the architecture.