Reputation: 7719
I have the follwoing code for converting an object of class User
to its DTO of type GetUserDto
:
public GetUserDto convertToDto(User user) {
Converter<User, GetUserDto> converter = context -> {
User source = context.getSource();
GetUserDto target = new GetUserDto();
target.setDescription(source.getDescription());
target.setId(source.getId());
target.setName(source.getName());
target.setImageId(source.getImageId());
return target;
};
modelMapper.createTypeMap(User.class, GetUserDto.class).setConverter(converter);
return modelMapper.map(user, GetUserDto.class);
}
It works fine for the first time, but the subsequent calls to convertToDto
throws:
java.lang.IllegalStateException: A TypeMap already exists for class com.boot.cut_costs.model.User and class com.boot.cut_costs.dto.user.ExtendedGetUserDto
I found some other posts regarding this, one suggested to null check TypeMap
for modelMapper
and not to create it again if it wasn't null
. This is not a good solution as if you have thousands of calls to this method it adds unnecessary overhead to it.
Any good solution ?
Upvotes: 0
Views: 2513
Reputation: 131346
I found some other posts regarding this, one suggested to null check TypeMap for modelMapper and not to create it again if it wasn't null. This is not a good solution as if you have thousands of calls to this method it adds unnecessary overhead to it.
If you look into the code of org.modelmapper.ModelMapper.getTypeMap()
and org.modelmapper.ModelMapper.createTypeMap()
, you will see that
creating a TypeMap
that is a higher overhead as simply invoking a method to retrieve a TypeMap
.
Returning the object from a map if it exists is straight:
public <S, D> TypeMap<S, D> getTypeMap(Class<S> sourceType, Class<D> destinationType) {
Assert.notNull(sourceType, "sourceType");
Assert.notNull(destinationType, "destinationType");
return config.typeMapStore.<S, D>get(sourceType, destinationType, null);
}
While the adding performs much more things.
It creates a proxy type, does a synchronized task and does some checks before creating a TypeMap
instance and at last it puts it in the map :
private <S, D> TypeMap<S, D> createTypeMapInternal(S source, Class<S> sourceType,
Class<D> destinationType, String typeMapName, Configuration configuration) {
if (source != null)
sourceType = Types.<S>deProxy(source.getClass());
Assert.state(config.typeMapStore.get(sourceType, destinationType, typeMapName) == null,
String.format("A TypeMap already exists for %s and %s", sourceType, destinationType));
return config.typeMapStore.create(source, sourceType, destinationType, typeMapName,
(InheritingConfiguration) configuration, engine);
}
that invokes also :
public <S, D> TypeMap<S, D> create(S source, Class<S> sourceType, Class<D> destinationType,
String typeMapName, InheritingConfiguration configuration, MappingEngineImpl engine) {
synchronized (lock) {
TypeMapImpl<S, D> typeMap = new TypeMapImpl<S, D>(sourceType, destinationType, typeMapName,
configuration, engine);
if (configuration.isImplicitMappingEnabled()
&& ImplicitMappingBuilder.isMatchable(typeMap.getSourceType())
&& ImplicitMappingBuilder.isMatchable(typeMap.getDestinationType()))
new ImplicitMappingBuilder<S, D>(source, typeMap, config.typeMapStore,
config.converterStore).build();
typeMaps.put(TypePair.of(sourceType, destinationType, typeMapName), typeMap);
return typeMap;
}
}
So do the check if a more efficient solution :
if (modelMapper.getTypeMap(User.class,GetUserDto.class) == null){
modelMapper.createTypeMap(User.class, GetUserDto.class).setConverter(converter);
}
return modelMapper.map(user, GetUserDto.class);
Now, if you want really avoid unnecessary processing, you could create the TypeMap and set all converter associated to in a specific class once.
public void initTypeMaps(){
modelMapper.createTypeMap(User.class, GetUserDto.class).setConverter(converterUserAndUserDto);
modelMapper.createTypeMap(Other.class, GetOtherDto.class).setConverter(converterOtherAndOtherDto);
...
}
At last, if you have thousands of calls to this method in a short time and you want to reduce to the maximum the overhead, don't use ModelMapper and a converter but do the mapping between two classes at hand.
Upvotes: 3