Skip to content

Missing accessable Constrctor check for updating existing bean #4060

Description

@hduelme

Expected behavior

MapStruct should report a compilation error during annotation processing when SET_TO_DEFAULT requires instantiation of a type that cannot be constructed through an accessible no-args constructor, rather than generating invalid code.
Maybe something like

GENERAL_NO_SUITABLE_CONSTRUCTOR( "%s does not have an accessible constructor." ),

Actual behavior

When updating an existing bean with NullValuePropertyMappingStrategy.SET_TO_DEFAULT, MapStruct generates code that attempts to instantiate target property types using a no-args constructor.

However, for types that do not have an accessible no-args constructor (e.g. Comparable, LocalDate, LocalDateTime, Instant, BigDecimal, and BigInteger), MapStruct still generates instantiation code such as:

target.localDate = new LocalDate();
target.comparable = new Comparable<String>();

Steps to reproduce the problem

Example

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;

import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;

@Mapper
public interface UpdateMapper {

    class Target {
        public Comparable<String> comparable;
        public LocalDate localDate;
        public LocalDateTime localDateTime;
        public Instant instant;
        public BigDecimal bigDecimal;
        public BigInteger bigInteger;

    }

    class Source  {
        public Comparable<String> comparable;
        public LocalDate localDate;
        public LocalDateTime localDateTime;
        public Instant instant;
        public BigDecimal bigDecimal;
        public BigInteger bigInteger;
    }

    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
    void update(@MappingTarget Target target, Source from);
}

generates

import javax.annotation.processing.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2026-06-02T22:45:28+0200",
    comments = "version: 1.6.3, compiler: javac, environment: Java 21.0.5 (Eclipse Adoptium)"
)
public class UpdateMapperImpl implements UpdateMapper {

    @Override
    public void update(Target target, Source from) {
        if ( from == null ) {
            return;
        }

        if ( from.comparable != null ) {
            target.comparable = from.comparable;
        }
        else {
            target.comparable = new Comparable<String>();
        }
        if ( from.localDate != null ) {
            target.localDate = from.localDate;
        }
        else {
            target.localDate = new LocalDate();
        }
        if ( from.localDateTime != null ) {
            target.localDateTime = from.localDateTime;
        }
        else {
            target.localDateTime = new LocalDateTime();
        }
        if ( from.instant != null ) {
            target.instant = from.instant;
        }
        else {
            target.instant = new Instant();
        }
        if ( from.bigDecimal != null ) {
            target.bigDecimal = from.bigDecimal;
        }
        else {
            target.bigDecimal = new BigDecimal();
        }
        if ( from.bigInteger != null ) {
            target.bigInteger = from.bigInteger;
        }
        else {
            target.bigInteger = new BigInteger();
        }
    }
}

None of the targets has an accessible constructor.

MapStruct Version

MapStruct 1.6.3

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions