Skip to content

#4056 Extend JSpecify support for container mapping and @NonNull return types - #4057

Merged
filiphr merged 3 commits into
mapstruct:mainfrom
filiphr:4056-jspecify-container-mapping
Jun 5, 2026
Merged

#4056 Extend JSpecify support for container mapping and @NonNull return types#4057
filiphr merged 3 commits into
mapstruct:mainfrom
filiphr:4056-jspecify-container-mapping

Conversation

@filiphr

@filiphr filiphr commented May 15, 2026

Copy link
Copy Markdown
Member

Summary

Closes #4056.

Extends the JSpecify support added in #4033:

  • @NonNull source on collection-typed property mappings skips the wrapping null guard
  • Container mapping methods (Iterable, Map, Stream) honor JSpecify on their source parameter
  • @NonNull mapping-method return type implies NullValueMappingStrategy.RETURN_DEFAULT semantics across bean, iterable, map and stream mapping methods

All new behaviour is gated on JSpecify annotations and remains fully suppressed by mapstruct.disableJSpecify.

…null return types

Follow-up to mapstruct#1243 closing the gaps reported in mapstruct#4056:

* `@NonNull` source on collection-typed property mappings now skips the
  wrapping null guard around the collection construction (mirrors the
  existing non-collection rule in PropertyMapping).
* Container mapping methods (Iterable, Map, Stream, arrays) now honor
  JSpecify on their source parameter: ContainerMappingMethod and
  MapMappingMethod route the source-parameter presence check through the
  JSpecify-aware PresenceCheckMethodResolver (same helper BeanMappingMethod
  already uses), and the corresponding FTL templates wrap the early-return
  block in <#if sourceParameterPresenceCheck??>.
* `@NonNull` mapping-method return type now implies
  NullValueMappingStrategy.RETURN_DEFAULT semantics across bean, iterable,
  map and stream mapping methods, so generated code never violates a
  @nonnull return contract by emitting `return null`.

All new behaviour is gated on JSpecify annotations being present and is
fully suppressed by the existing `mapstruct.disableJSpecify` option.
@filiphr
filiphr force-pushed the 4056-jspecify-container-mapping branch from 26eb64a to 19c830d Compare May 15, 2026 09:26
filiphr added 2 commits June 5, 2026 15:03
…ream + negative tests

- Extract the duplicated 'JSpecify @nonnull return forces RETURN_DEFAULT'
  logic into MappingBuilderContext#isJSpecifyNonNullReturn, used by
  BeanMappingMethod, ContainerMappingMethodBuilder and MapMappingMethod.
- Clarify the comments explaining why the bean path keeps the extra
  presence-check guard while container/map/stream force unconditionally.
- Add Stream coverage (was entirely untested): JSpecifyStreamMethodTest and
  JSpecifyNonNullReturnStreamTest with fixtures.
- Add negative/control coverage: nullable source keeps the method guard,
  @nonnull return overrides an explicit RETURN_NULL, update methods are not
  forced to RETURN_DEFAULT, and mapstruct.disableJSpecify suppresses the new
  container-source and @NonNull-return behaviour.
The supplier resolving the mapper type's @NullMarked scope
(() -> typeFactory.getType(mapperTypeElement.asType()).isNullMarked()) was
duplicated across MappingBuilderContext, PresenceCheckMethodResolver and
PropertyMapping for elements declared directly on the mapper (return types,
source parameters). Extract it into
MappingBuilderContext#getNullabilityInMapperScope and route all three sites
through it.
@filiphr
filiphr merged commit 35334e5 into mapstruct:main Jun 5, 2026
9 checks passed
@filiphr
filiphr deleted the 4056-jspecify-container-mapping branch June 5, 2026 19:46
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.

JSpecify: @NonNull source on collection properties and on container/bean mapping method returns still generates null checks

1 participant