Skip to content

Support for implicit conversion between java.time.LocalDate and java.time.LocalDateTime #3199

@belkin1667

Description

@belkin1667

Expected behavior

Either LocalDateTime map(LocalDate date) results in compilation error or mapping results in date == null ? null : LocalDateTime.of(date, LocalTime.MIN)

Actual behavior

LocalDateTime map(LocalDate date) maps any date to null

The problem seems to be related to incorrect mapping sequence: LocalDate to XMLGregorianCalendar and XMLGregorianCalendar to LocalDateTime. Separately those mappings are correct, but combined are not:
Generated mapper contains the following line:

LocalDateTime localDateTime = xmlGregorianCalendarToLocalDateTime( localDateToXmlGregorianCalendar( date ) ); 

Generated method xmlGregorianCalendarToLocalDateTime(..) returns null if hours, minutes or seconds are equal to DatatypeConstants.FIELD_UNDEFINED, which they are cause localDateToXmlGregorianCalendar(..) calls javax.xml.datatype.DatatypeFactory::newXMLGregorianCalendarDate which sets hours, minuts, seconds and milliseconds as FIELD_UNDEFINED

Methods I'm talking about for reference:

        private static LocalDateTime xmlGregorianCalendarToLocalDateTime( XMLGregorianCalendar xcal ) {
            if ( xcal == null ) {
                return null;
            }

            if ( xcal.getYear() != DatatypeConstants.FIELD_UNDEFINED
                && xcal.getMonth() != DatatypeConstants.FIELD_UNDEFINED
                && xcal.getDay() != DatatypeConstants.FIELD_UNDEFINED
                && xcal.getHour() != DatatypeConstants.FIELD_UNDEFINED
                && xcal.getMinute() != DatatypeConstants.FIELD_UNDEFINED
            ) { //some mapping }
            return null;
        }
private XMLGregorianCalendar localDateToXmlGregorianCalendar( LocalDate localDate ) {
            if ( localDate == null ) {
                return null;
            }

            return datatypeFactory.newXMLGregorianCalendarDate(
                localDate.getYear(),
                localDate.getMonthValue(),
                localDate.getDayOfMonth(),
                DatatypeConstants.FIELD_UNDEFINED );
        }
    public XMLGregorianCalendar newXMLGregorianCalendarDate(
            final int year,
            final int month,
            final int day,
            final int timezone) {

            return newXMLGregorianCalendar(
                    year,
                    month,
                    day,
                    DatatypeConstants.FIELD_UNDEFINED, // hour
                    DatatypeConstants.FIELD_UNDEFINED, // minute
                    DatatypeConstants.FIELD_UNDEFINED, // second
                    DatatypeConstants.FIELD_UNDEFINED, // millisecond
                    timezone);
            }

Steps to reproduce the problem

Define Mapper:

@Mapper
public interface IssueBelkinmikeMapper {

    IssueBelkinmikeMapper INSTANCE = Mappers.getMapper( IssueBelkinmikeMapper.class );

    LocalDateTime map(LocalDate date);
}

Define Test:

@WithClasses({
    IssueBelkinmikeMapper.class
})
@IssueKey("belkinmike")
class IssueBelkinmikeMapperTest {

    @ProcessorTest
    void throwsException() {
        LocalDate source = LocalDate.of(2022, 2, 2);
        LocalDateTime target = IssueBelkinmikeMapper.INSTANCE.map(source);
        assertThat(target).isNotNull();
    }
}

Test should pass or fail at mapper generation stage, but it is not

IMHO: It should fail at generating such mapping, cause I met this problem mapping dtos:

I had this classes

class EntityDto {
    LocalDate dateFrom;
}
class Entity {
    LocalDate dateFrom;
}

interface MyMapper {
    EntityDto map(Entity e);
}

then dto field's type changed to LocalDateTime:

class EntityDto {
    LocalDateTime dateFrom;
}
class Entity {
    LocalDate dateFrom;
}

interface MyMapper {
    EntityDto map(Entity e);
}

And I would expect mapping to fail and attract my attention to it, but it did not

MapStruct Version

main branch (commit id=a7ba12676d237957be0753076f436d7974c9f7f4)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions