Having something like:
@Getter @Setter
public static class Entity {
private int hash;
private LocalDateTime createdTime;
}
and
@Getter @Setter
public static class DTO {
private String hash;
private String createdTime;
}
I need birectional mapping so I should be able to map Entity -> DTO -> Entity. In this example the property type happens to be LocalDateTime but could be any type that needs parsing from String or so (just to say that I am not after better way to map LocalDateTime but in general).
There are no problems in mapping. I create TypeMap, add Converter and for LocalDateTime a Provider also since it does note have public default constructor. Something like here.
If I had in my DTO also LocalDateTime createdTime(or String createdTime in my Entity) then ModelMapper.validate() would be happy. But I do not have and I need to create all the converting stuff.
All this leads to ModelMapper.validate() to complain:
Unmapped destination properties found in TypeMap[DTO -> Entity]:
org.example.test.modelmapper.validation.TestIt$Entity.setCreatedTime()
The code I currently use for validating mapping for LocalDateTime case is:
ModelMapper mm = new ModelMapper();
mm.createTypeMap(Entity.class, DTO.class);
mm.createTypeMap(DTO.class, Entity.class);
mm.createTypeMap(String.class, LocalDateTime.class)
.setPropertyProvider(localDateTimeProvider);
mm.addConverter(toStringDate);
mm.validate();
(so I am not doing any actual mapping but validating the mapping)
with
Provider<LocalDateTime> localDateTimeProvider =
new AbstractProvider<LocalDateTime>() {
@Override
public LocalDateTime get() {
return LocalDateTime.now();
}
};
and
Converter<String, LocalDateTime> toStringDate = new AbstractConverter<>() {
@Override
protected LocalDateTime convert(String source) {
return LocalDateTime.parse(source);
}
};
Ask for more details/code. I'll update question as needed
The setPropertyProvider method allows to specify a Provider to be used for providing instances of mapped properties within a TypeMap.
So when you write:
mm.createTypeMap(String.class, LocalDateTime.class)
.setPropertyProvider(localDateTimeProvider);
It does not fit the case because we are not using this provider in the mapping of a property of the String type to a property of a LocalDateTime type. It should rather be moved above to be associated with the DTO -> Entity TypeMap (The error message is by the way a good hint about that). So it should rather be.
mm.createTypeMap(DTO.class, Entity.class)
.setPropertyProvider(localDateTimeProvider);
Which makes perfect sense because we are using the provider to provide instance for the mapping of a String property of the DTO (String createdTime;) to a LocalDateTime property of the Entity (LocalDateTime createdTime;).
On the other hand the converter should be added to the ModelMapper before the corresponding provider.
Also leaving in mm.createTypeMap(String.class, LocalDateTime.class), my compiler complains that a similar typemap already exist and there is no need to create a new one. So with that I can discard it.
With these two changes, my bean looks like:
@Bean
ModelMapper demoModelMapper() {
Provider<LocalDateTime> localDateTimeProvider =
new AbstractProvider<LocalDateTime>() {
@Override
public LocalDateTime get() {
return LocalDateTime.now();
}
};
Converter<String, LocalDateTime> toStringDate = new AbstractConverter<String,
LocalDateTime>() {
@Override
protected LocalDateTime convert(String source) {
return LocalDateTime.parse(source);
}
};
ModelMapper mm = new ModelMapper();
mm.createTypeMap(Entity.class, DTO.class);
mm.addConverter(toStringDate);
mm.createTypeMap(DTO.class, Entity.class)
.setPropertyProvider(localDateTimeProvider);
mm.validate();
return mm;
}
Notice that I am calling validate() before returning the bean. This works for me. Please test and see on your side.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With