Skip to content

#3704 Fix NPE when forging a mapping to an Optional target with a wildcard type argument - #4139

Open
sharanggupta wants to merge 1 commit into
mapstruct:mainfrom
sharanggupta:gh-3704-optional-wildcard-target
Open

sharanggupta wants to merge 1 commit into
mapstruct:mainfrom
sharanggupta:gh-3704-optional-wildcard-target

Conversation

@sharanggupta

@sharanggupta sharanggupta commented Oct 6, 2026 •

Copy link
Copy Markdown

Fixes #3704

Problem — With a target setter like setDate(Optional<? extends Nested>) (common for Immutables-generated builders) and a source Optional<SourceNested>, the processor crashes on main with Internal error in the mapping processor: java.lang.NullPointerException in DefaultMappingExclusionProvider.isExcluded, called from MappingBuilderContext#canGenerateAutoSubMappingFor: the Optional base type is a wildcard whose TypeElement is null. On 1.6.x the same code reported "Can't map property … Optional<? extends …>" instead of generating a mapping.

Regression — The NPE site was introduced with the Optional support from #3971 (#674, 2026-01-30) and ships in 1.7.0.Beta1 and Beta2; on 1.4.2 and 1.6.0 the same mapper produced the "Can't map property" diagnostic instead of crashing. It would be good to have this in 1.7.0.RC1.

Fix — PropertyMapping#forgeMapping(SourceRHS) now forges the sub-mapping against targetType.withoutBounds() for Optional targets (the same approach forgeMapMapping already uses for Map<? extends K, ? extends V>), so a method Optional<Nested> nestedOptionalToNestedOptional(Optional<SourceNested>) is generated and assigned to the wildcard setter. canGenerateAutoSubMappingFor is also made null-safe for the Optional branch, mirroring the existing non-Optional branch.

Tests — Issue3704Test (bugs/_3704): present/empty Optional mapped through a wildcard setter with fixture comparison, plus the exact scenario from the issue thread (overloaded setDate + generic <T> Optional<T> wrapOptional(T)). ./mvnw -pl processor verify is green (3649 tests, checkstyle, license, forbidden-apis). Reverting the two production changes makes Issue3704Test fail 6/6 (javac and Eclipse JDT) with the reported NPE, so the test is load-bearing.

Design note — The wildcard bound is resolved in forgeMapping, consistent with how forgeMapMapping handles Map<? extends K, ? extends V>. If you would rather have the check closer to the Optional handling (Type#getOptionalBaseType() / canGenerateAutoSubMappingFor), I am happy to move it.

… with a wildcard type argument

A target setter such as `setDate(Optional<? extends Nested>)` made
`MappingBuilderContext#canGenerateAutoSubMappingFor` dereference the
`TypeElement` of the wildcard `Optional` base type, which is `null`, and
the processor crashed with an internal `NullPointerException`.

Resolve the wildcard bound before forging (as is already done for `Map`
targets) so that an `Optional<Nested>` sub-mapping method is generated and
assigned to the wildcard setter, and make the exclusion check null-safe.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generic optional mapping not working on version 1.6.0

1 participant