Support for implicit conversion between java.time.LocalDate and java.time.LocalDateTime
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)