Skip to content

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

@filiphr

Description

@filiphr

Follow-up to #1243 (JSpecify nullness support, merged via #4033).

Two gaps were reported in #4035 (comment) (originally posted under #4035 but unrelated to that issue's array-element scope, so splitting out here):

  1. Collection-typed property mapping — when the source getter is JSpecify @NonNull (or unannotated in a @NullMarked scope), MapStruct still emits

    List<String> list = source.getNonNullListValue();
    if ( list != null ) {
        target.setValues( new ArrayList<>( list ) );
    }

    The wrapper should be skipped, mirroring the non-collection property mapping behaviour already in PropertyMapping.setterWrapperNeedsSourceNullCheck.

  2. Container mapping methods (Iterable → Iterable, Map → Map, Stream → Stream) — ContainerMappingMethod and MapMappingMethod hardcode a NullPresenceCheck for the source parameter and always emit if ( source == null ) return null;, bypassing the JSpecify-aware PresenceCheckMethodResolver that BeanMappingMethod already uses.

Additionally, when a mapping method's return type is JSpecify @NonNull, generating return null; violates the return contract (e.g. NullAway flags returning @Nullable expression from method with @NonNull return type). The fix should force NullValueMappingStrategy.RETURN_DEFAULT semantics in that case, consistently across BeanMappingMethod, IterableMappingMethod, MapMappingMethod, and StreamMappingMethod.

The user's reproducer is the comment linked above (modifying JSpecifyNullMarkedTest's SourceBean/TargetBean to add a @NonNull List<String> field, plus the List<X> mapAll(List<Y>) shape).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions