Skip to content

NullValuePropertyMappingStrategy.IGNORE strategy ignored for Optional fields #4128

Open

Description

@ijioio

Expected behavior

The NullValuePropertyMappingStrategy.IGNORE strategy should be applied to Optional fields in exactly the same way as it is applied to other field types. Its behavior is clearly defined in the Javadoc:

If a source bean property equals null the target bean property will be ignored and retain its existing value.

Instead, NullValuePropertyMappingStrategy.IGNORE is effectively ignored for Optional fields. This also doesn't align with common JSON mapping semantics, where an absent field is ignored (i.e. nothing is done), while an explicitly provided null value is mapped to Optional.empty().

This approach is often used to cover patch semantics during mapping. A patch needs to distinguish between three states, which is why Optional is used:

  • null - ignore the field and keep its existing value
  • Optional.empty() - clear the field by setting it to null
  • Optional.of(value) - update the field with the wrapped value

Previously, NullValuePropertyMappingStrategy.IGNORE did exactly what was expected: it applied the necessary null checks and preserved the distinction between an absent field and an explicitly provided empty value.

Quite a few production systems are already built around these semantics. The recent changes therefore introduce breaking changes for existing applications that rely on this distinction.

Actual behavior

The NullValuePropertyMappingStrategy.IGNORE strategy is simply ignored, and no null check is generated:

Steps to reproduce the problem

  1. Create source and target objects with Optional field:
public class Source {
    private Optional<String> foo;
    public Optional<String> getFoo() { return foo; }
    public void setFoo(Optional<String> foo) { this.foo = foo; }
}

public class Target {
    private Optional<String> foo;
    public Optional<String> getFoo() { return foo; }
    public void setFoo(Optional<String> foo) { this.foo = foo; }
}
  1. Create mapper to map source to target:
@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface InvalidMapper {
    public static final InvalidMapper INSTANCE = Mappers.getMapper(InvalidMapper.class);
    public Target map(Source source);
}
  1. Check generated mapper implementation:
@Override
public Target map(Source source) {
    if ( source == null ) {
        return null;
    }

    Target target = new Target();

    target.setFoo( source.getFoo() );

    return target;
}

No null checks are applied

MapStruct Version

1.7.0.Beta2

Activity

  1. nu11Po1nter1 commented on Oct 13, 2026

    @nu11Po1nter1

    Hi, I'd be interested in working on this issue.

    I've looked into the problem and the related PR #4124. As I understand it, the three-state PATCH behavior with NullValuePropertyMappingStrategy.IGNORE is not covered by that PR.

    I'd like to investigate the generated mapping logic, implement a fix, and add regression tests for null, Optional.empty(), and Optional.of(value).

    Is anyone currently working on this issue, and would a PR addressing this behavior be welcome?

    Thanks!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions