Reputation: 1
To ensure the SRP (Single Responsibility Principle) is followed within a ports and adapters architecture, I have made a split between DTO, domain and DB entities. I would like my Spring @Repository to automatically perform my conversion from Domain object to DB Entity and vice versa. I would like to simplify my current Service call which performs double mapping like this:
public Client createClient(Client client) {
return clientMapper.mapToClient(
clientRepository.save(
clientMapper.mapToClientDocument(client)));
}
Into
return clientMapper.map(clientRepository.save(client));
Or is there an alternative solution you might see?
As an example, here are my objects:
@Data
public class ClientCreationCommand {
private String id;
private String clientName;
}
public class Client {
private String id;
private String clientName;
}
@Document(collection = "clients")
public class ClientDocument {
@Id
private String id;
private String clientName;
}
here is a MapStruct mapper:
@Mapper(componentModel = "spring")
public interface ClientMapper {
Client mapToClient(ClientDocument clientCreationCommand);
ClientDocument mapToClientDocument(Client client);
}
And a repository:
@Repository
public interface ClientRepository extends MongoRepository<ClientDocument, String> {
@NotNull <S extends ClientDocument> S save(@NotNull S client);
}
Upvotes: 0
Views: 367
Reputation: 31
I was initially confused by your naming convention.... we usually keep the entity object to be the same as the table, and put the DTO in the name of the data transfer object, for example
Client <-- entity
ClientDTO <-- DTO
Regardless of what you do for naming convention, there's going to still be double mapping going on.... at least if you manually do it like you are doing, and maybe use a different naming convention, it's easier to debug.
btw, we use the @InheritInverseConfiguration tag in mapstruct, you might define like this to enhance readability?
@Mapper
public interface ClientMapper {
Client toEntity(ClientDTO clientCreationCommand);
@InheritInverseConfiguration
ClientDTO toDTO(Client client);
}
though it's not exactly what you want, might be easier to read if you convert it before calling your service?
ClientDTO result = myService.createClient(clientMapper.ToEntity(client));
public ClientDTO createClient(Client client) {
return clientMapper.toDTO(
clientRepository.save(client)
);
}
or how you are doing it...
public ClientDTO createClient(ClientDTO client) {
return clientMapper.toDTO(
clientRepository.save(clientMapper.toEntity(client))
);
}
a little easier to work with when using different naming conventions
as far as having your repository itself perform the mapping... I wouldn't recommend that. It's best to let the repository do only data stuff (no logic), the controller to do only the restful stuff (no logic), and your service layer to handle all the conversions and business logic.
Upvotes: 0