0

I am working on a Spring Boot application and I have the following doubt.

I have this service method (that works fine) that insert an object into the DB calling the repository:

@Override
@Transactional
public CoinDTO createCoin(CoinDTO coin) throws DuplicateException {
    Coin checkCoinExists = coinRepository.findByCode(coin.getCode());

    if (checkCoinExists != null) {
        String MsgErr = String.format("Coin %s already registered in the system !!! "
                + "Impossible to use POST", coin.getCode());

        log.warning(MsgErr);

        throw new DuplicateException(MsgErr);
    }

    Coin result = coinRepository.save(conversionService.convert(coin,Coin.class));
    return conversionService.convert(result,CoinDTO.class);
}

As you can see the save() methjod return the inserted Coin object (that is an Hibernate entity class mapping my table). The service method than convert this Coin object into the CoinDTO object in order to return the DTO object instead the entity instance. It works fine and it is the expected behavior.

Now I created this second service method that simply retrieve the list of all the Coin objects and must return the list of the related CoinDTO objects:

@Override
public List<CoinDTO> getCoinList() {
    
    List<Coin> coinsList = this.coinRepository.findAll();
    
    return null;
}

and here I have the following doubt: I think that I can implement thid ENTITY to DTO conversion behavior iterating on the coinsList element, converting each element of the list one by one and then adding it to a new List list. It should work

Exist some more modern and smarter way to do it? Maybe using lambda function? Can you help me to implement this behavior in a modern and a smart way?

AndreaNobili
  • 40,955
  • 107
  • 324
  • 596

3 Answers3

2

You may create an generic abstract class like this:

public abstract class AbstractConverter<T, DTO> {
    public abstract T fromDto(DTO dto);

    public abstract DTO toDTO(T t);

    public List<T> fromDTOs(List<DTO> dtos) {
        if (dtos == null || dtos.isEmpty()) {
            return null;
        } else {
            return dtos.stream().map(this::fromDTO).collect(Collectors.toList());
        }
    }

    public List<DTO> toDTOs(List<T> ts) {
        if (ts == null || ts.isEmpty()) {
            return null;
        } else {
            return ts.stream().map(this::toDTO).collect(Collectors.toList());
        }
    }

}

Then create another class that implements the aforecreated abstract class by assigning your desired values like this:

@Component(value = "coinConverter")
public class CoinConverter extends AbstractConverter<Coin, CoinDTO> {

    @Override
    public Coin fromDTO(CoinDTO dto) {
        if (dto == null) {
            return null;
        } else {
            Coin coin = new Coin();
            // Assign all values you wanted to consume
            // of the following form
            // coin.setYourAttribite(dto.getYourAttribute())
            return coin;
        }
    }

    @Override
    public CoinDTO toDTO(Coin coin) {
        if (t == null) {
            return null;
        } else {
            CoinDTO coinDTO = new CoinDTO();
            // Assign all values you wanted to expose
            // of the following form
            // coinDTO.setYourAttribite(coin.getYourAttribute())
            return coinDTO;
        }
    }
}

In controller layer you may change your existing code by this one:

@Autowired
@Qualifier("coinConverter")
AbstractConverter<Coin, CoinDTO> abstractConverter;

@Override
public List<CoinDTO> getCoinList() {

    List<Coin> coinsList = this.coinRepository.findAll();
    return abstractConverter.toDTOs(cointList);
}

This way your code is flexible to add more converters without changing the existing ones.

Ali Arabat
  • 118
  • 7
0

As far as I understand, you are looking for a way that makes the conversion process shorter and more convenient. if so use ModelMapper class in this case, read this http://modelmapper.org/ documentation, ModelMapper uses TypeTokens to allow mapping of generic parameterized types.

0

Not sure if I understood your question, but is the following what you are looking for:

@Override
public List<CoinDTO> getCoinList() {
    return this.coinRepository.findAll().stream()
        .map(coin -> conversionService.convert(coin, CoinDTO.class))
        .collect(Collectors.toList());
}
João Dias
  • 16,277
  • 6
  • 33
  • 45