问题
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
回答1:
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.
回答2:
As in answer from alainlompo I had to move the adding of converter before the creation of type map.
But I also had to remove the provider part because it seemed to cause all string fields to be mapped as LocalDateTime so I got errors like:
org.modelmapper.MappingException: ModelMapper mapping errors:
1) The provided destination instance 2020-01-05T17:28:22.088694 is not of the required type int.
Above I think means that ModelMapper tried to populate field hash
with a string representing LocalDateTime
.
It seems that the provider is not needed at all. So my final code with just a converter added:
ModelMapper mm = new ModelMapper();
mm.createTypeMap(Entity.class, DTO.class);
mm.addConverter(toStringDate);
mm.createTypeMap(DTO.class, Entity.class);//.setPropertyProvider(localDateTimeProvider);
mm.validate();
This actually means that I asked a bit wrong question claiming that I need to use the provider
来源:https://stackoverflow.com/questions/59568360/how-to-have-modelmapper-validate-succeed-when-using-converters-and-providers-i