DTO Assembler, how do you really use it?

Asked

Viewed 999 times

0

I’m reading about DTO and tbm viewmodel in ASP.NET and wanted to do something like this in JAVA. If I’m not mistaken, DTO is a way to move data between layers in a specific way without having to change the domain entities.

Well, in ASP we have the automapper that will transform an Entity into a Viewmodel/DTO and for java I found some solutions that facilitate.

My difficulty is the reverse process, transforming a Viewmodel/DTO into an entity. Imagine the following scenario:

I have an entity:

public class Pedido{
   private long codigo;
   private Cliente cliente;
   private Vendedor vendedor;
}

and a DTO

public class PedidoDTO{
   private long codigo;
   private long codCliente;
   private long nomeCliente;
   private long codVendedor;
   private long nomeVendedor;
}

Transforming the entity into DTO is easy, because the DTO is much simpler, you can even create a lib to do this, but the opposite process is more complex. I even created a mapper here to do this "at hand".

    public Pedido preencherModelo(PedidoDTO pDTO, Pedido pPedido) {     
            pPedido.setCodigo(pDTO.getCodigo());
            if (pDTO.getCodCliente() > 0){
                Cliente lCliente = _servicoCliente.buscar(pDTO.getCodCliente()); 
                pPedido.setCliente(lCliente);
            }       
            if (pDTO.getCodVendedor() > 0){
                Vendedor lVendedor = _servicoVendedor.buscar(pDTO.getCodVendedor()); 
                pPedido.setVendedor(lVendedor);
            }
            return pPedido;
}

The question is: I’m screwing up ? you have a better solution than this ?

1 answer

1


Convert Entity to DTO through the Pattern Assembler is wrong, breaks the sense of DTO which is a Pattern for object transfer. See that it can be composed of multiple entities. The correct is to use methods set of the instances of objects in the service classes, taking the values of these DTO’s and assembling the entities, on the contrary, as you said yourself, is simple, because you would be working correctly with Pattern.

But there is a way that even if wrong would work, but it would only be valid if the association was 1x1 between Entity x DTO, using Function.

Ex: to convert using transforms to objects and lists with Guava:

import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Function;

    /**
     * Classe de transformação para popular os dados em DTOs, seguindo o pattern
     * Transfer Object Assembler.
     */
    public class Transformer {

        /**
         * Executa a transformação de um objeto para um DTO.
         * 
         * @param from
         * @param function
         * @return <F, T> T
         */
        public static <F, T> T transform(F from, Function<? super F, ? extends T> function) {
            return (from == null) ? null : function.apply(from);
        }

        /**
         * Executa a transformação de uma lista de objetos para uma lista de DTOs.
         * 
         * @param fromList
         * @param function
         * @return <F, T> List<T>
         */
        public static <F, T> List<T> transform(List<F> source, Function<? super F, ? extends T> function) {
            List<T> out = new ArrayList<>(source.size());

            for (F from : source) {
                out.add(function.apply(from));
            }    
            return out;
        }    
    }

Pattern Assembler:

import java.util.List;
import br.com.myapp.model.dto.AuthUserDTO;
import br.com.myapp.model.entity.AuthUser;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

/**
 * Classe que transforma entidade USUARIOS em DTO.
 * 
 * @author Dilnei Cunha
 */
public class AuthUserDTOAssembler implements Function<AuthUser, AuthUserDTO>{

    /**
     * Método responsável por fazer a conversão da entidade USUARIOS em um AuthUserDTO.
     */
@Override
public AuthUserDTO apply(AuthUser e) {

    AuthGroupDTO groupDTO = Transformer.transform(e.getAuthGroup(), new  AuthGroupDTOAssembler());

    return new AuthUserDTO(e.getId(),
                       e.getName(),
                       e.getPassword(),
                       e.getEmail(),
                       e.getCreationDate(),
                       e.getLastModificationdate(),
                       e.getLastAccessDate(),
                       e.getAtivo(),
                       e.getUserName(),
                       e.getRamal(),
                       groupDTO);
    }
}

How would be the service that would use these Patterns...

/**
 * Método responsável por buscar um AuthUserDTO pelo ID do usuário.
 */
@Override
public AuthUserDTO findById(Long id) {
    return Transformer.transform(authUserRepository.findUserById(id), new AuthUserDTOAssembler());
}

Now let’s do the reverse process, of turning one or a list of DTO’s into objects, but keeping in mind that the association was 1x1. To do this, simply invert the objects in the Function implementation, e.g.:

import java.util.List;
import br.com.myapp.model.dto.AuthUserDTO;
import br.com.myapp.model.entity.AuthUser;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

/**
 * @author Dilnei Cunha
 */
public class AuthUserAssembler implements Function<AuthUserDTO, AuthUser>{

@Override
public AuthUser apply(AuthUserDTO e) {

    AuthGroup group = Transformer.transform(e.getAuthGroupDTO(), new  AuthGroupAssembler());

    return new AuthUser(e.getId(),
                       e.getName(),
                       e.getPassword(),
                       e.getEmail(),
                       e.getCreationDate(),
                       e.getLastModificationdate(),
                       e.getLastAccessDate(),
                       e.getAtivo(),
                       e.getUserName(),
                       e.getRamal(),
                       group);
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.