Skip to content

Missing accessable Constrctor check for updating existing bean #4060

@hduelme

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions