Reputation: 390
I am writing simple blog web application using Spring MVC framework. I am willing to add DTO
layer to my app.
I decided to use ModelMapper framework for conversion from Entity
objects to DTO
objects used in my views.
I have just one problem.
On my main page, I am showing a list of posts on my blog. In my view, it's just list of Post
(Entity) objects. I want to change it to pass a list of PostDTO
objects to my view. Is there any way to map List
of Post
objects to List
of PostDTO
object with single method call?
I was thinking about writing converter that will convert this but I am not sure it's a good way to do it.
Also, I am using Lists
of Entities
in few more places like administrative panel or comment below every Post on my page.
Link to code of my app on GitHub repository: repository
Upvotes: 30
Views: 102320
Reputation: 392
I resolved this by extending ModelMapper
and adding the generic mapList()
method. Register the new mapper as a Spring bean.
@Component
public class ModelMapperEx extends ModelMapper {
public <T, U> List<U> mapList(List<T> source, Class<U> targetClass) {
return source.stream()
.map(element -> map(element, targetClass))
.toList();
}
}
@Service
class UserService {
private final UserRepository userRepository;
private final ModelMapperEx mapper;
UserService(UserRepository userRepository, ModelMapperEx mapper) {
this.userRepository = userRepository;
this.mapper = mapper;
}
List<UserDto> list() {
List<User> list = userRepository.findAll();
// List mapping
return mapper.mapList(list, UserDto.class);
}
UserDto save(UserDto user) {
// Entity mapping
User entity = mapper.map(user, User.class);
entity = userRepository.save(entity);
return mapper.map(entity, UserDto.class);
}
}
Upvotes: 0
Reputation: 1895
You can create util class:
public class ObjectMapperUtils {
private static final ModelMapper modelMapper;
/**
* Model mapper property setting are specified in the following block.
* Default property matching strategy is set to Strict see {@link MatchingStrategies}
* Custom mappings are added using {@link ModelMapper#addMappings(PropertyMap)}
*/
static {
modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
}
/**
* Hide from public usage.
*/
private ObjectMapperUtils() {
}
/**
* <p>Note: outClass object must have default constructor with no arguments</p>
*
* @param <D> type of result object.
* @param <T> type of source object to map from.
* @param entity entity that needs to be mapped.
* @param outClass class of result object.
* @return new object of <code>outClass</code> type.
*/
public static <D, T> D map(final T entity, Class<D> outClass) {
return modelMapper.map(entity, outClass);
}
/**
* <p>Note: outClass object must have default constructor with no arguments</p>
*
* @param entityList list of entities that needs to be mapped
* @param outCLass class of result list element
* @param <D> type of objects in result list
* @param <T> type of entity in <code>entityList</code>
* @return list of mapped object with <code><D></code> type.
*/
public static <D, T> List<D> mapAll(final Collection<T> entityList, Class<D> outCLass) {
return entityList.stream()
.map(entity -> map(entity, outCLass))
.collect(Collectors.toList());
}
/**
* Maps {@code source} to {@code destination}.
*
* @param source object to map from
* @param destination object to map to
*/
public static <S, D> D map(final S source, D destination) {
modelMapper.map(source, destination);
return destination;
}
}
And use it for your needs:
List<PostDTO> listOfPostDTO = ObjectMapperUtils.mapAll(listOfPosts, PostDTO.class);
Upvotes: 68
Reputation: 451
Try the following simple way:
List<PostDTO> postDtoList = Arrays.asList(modelMapper.map(postEntityList, PostDTO[].class));
Upvotes: 21
Reputation: 2296
Let's assume you are reading from the database, and want to convert from entities in the DB to DTOs
The service layer might be separated from the controller (always the best approach), then do this:
Service layer code:
@Override
public List<PostDTO> convertEntityToDTOList( ){
List<Post> post = postRepository.findAll();
Type listType = new TypeToken<List<PostDTO>>(){}.getType();
List<PostDTO> postDTOList = modelMapper.map(post, listType);
return postDTOList;
}
Then in your controller, add this:
public ResponseEntity<?> list(){
List<PostDTO> postDTOList = iPost.convertEntityToDTOList();
return new ResponseEntity<>(postDTOList, HttpStatus.OK);
}
Note that the iPost is an interface that defines method. This is it:
public interface iPost {
List<PostDTO> convertEntityToDTOList();
}
Credits to @André Carvalho
Upvotes: 5
Reputation: 571
considering you have a list of Post Entity (postEntityList
) and a PostDTO class, you can try following:
use the following imports to get the desired results
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import java.lang.reflect.Type;
use the below code
Type listType = new TypeToken<List<PostDTO>>(){}.getType();
List<PostDTO> postDtoList = modelmapper.map(postEntityList,listType);
Upvotes: 44
Reputation: 584
since you want to convert Entity to Dto, you can try the following one
List<PostDTO> entityToDto = modelMapper.map(postEntity, new TypeToken<List<PostDTO>>(){}.getType());
Upvotes: 16