How to avoid services in DtoMappers layer

92 views Asked by At

Good day, I have a Spring Boot based backend , we are using own library to convert JPA entities to Dto's (library works based on reflection). The problem is , we inject service layer directly to some mappers. Let's say I have a UserEntity and UserDto. UserDto has a field called avatar and avatars are stored in S3. So in order to build a UserDto we are using the code like this.

@Component
class UserMapper {

 @Inject
 S3Service s3Service;

 public UserDto toDto(UserEntity entity){
     UserDto dto = new UserDto();
     BeanUtils.copy(entity,dto);
     dto.setAvatar(s3Service.getAvatarByUser(entity));

}

}

I don't like this approach because Mapper mustn't know anything about Service layer . However this mapper is used by other mappers as well. In case I want to return an OrderDto, it has a nested UserDto so OrderDto calls UserMapper internally. Are there any best practices for Mappers to be service free ?

So far I tried the following.

  1. Store avatar in ThreadLocal cache. When controller calls a service to get a user, service will store user's avatar in the ThreadLocal, and then Mapper will get it from ThreadLocal cache. Disadvantage - it's hard to test it and requires me to make Mocks
  2. Create a separate POJO called UserWithAvatar that stores UserEntity entity;String avatar and create a mapper for UserWithAvatar instead of UserEntity. Disadvantage - as I said this mapper will be used by OrderMapper and order mapper takes OrderEntity with nested UserEntity instead of UserWithAvatar
1

There are 1 answers

2
J Asgarov On

I think mapper should be inside of service but I will try working with ur requirements

u have 2 choices:

  1. You inject both service and mapper to controller, get entity back to the controller and map it using mapper before returning response

  2. Use event publishing to publish an event which mapper then catches and produces the mapping. After that you could either directly return the dto to controller or produce another event. (event publishing is by default synchroneous so you dont have to worry about concurrency issues)

Event publishing is done via spring and results in very uncoupled code where publisher doesnt know anything about event subscribers and hence these 2 can be in 2 seperate layers that wont know anything about each other

Easy to follow guide: https://www.baeldung.com/spring-events