How to map a DTO to an existing JPA entity?
Asked Answered
R

5

11

I'm trying to map a Java DTO object to an existing JPA entity object without having to do something like the following:

public MyEntity mapToMyEntity(SomeDTO dto, MyEntity entity) {
    entity.setField1(dto.getField1());
    entity.setField2(dto.getField2());
    ...
    entity.setField20(dto.getField20());

    return entity;
}

Up to now I've been using ModelMapper like so: MyEntity entity = modelMapper.map(dto, SomeDTO.class);, but what I'm trying to do instead is map to an existing entity object rather than creating a new entity object from a DTO. I've looked through the ModelMapper manual and couldn't find how to map without creating a new object. Am I stuck adding each member variable manually for each entity object I might have?

Ranita answered 3/10, 2017 at 1:48 Comment(0)
F
4

You can use dozer mapper or gson.

DozerMapper ex:

Mapper mapper = DozerBeanMapperBuilder.createDefault();
DestinationObject destObject = mapper.map(sourceObject,DestinationClassName.class);

You can check github page for more information

Feedback answered 3/10, 2017 at 1:59 Comment(1)
While this is a good suggestion I don't think is any different from what OP is actually doing. OP is asking how to map from a DTO to an existing entity instance, not to a new instance. Something like mapper.map(dto, entityObj) I guess.Pule
Z
4

Currently ModelMapper supports mapping also to an existing object.

It is possible to do the following (for a pseudo Spring example):

MyEntity mye = repository.findById(id);
ModelMapper mm = new ModelMapper();    
mm.map(myDTO, mye);
repository.save(mye):

I am using version 2.3.1 but earlier versions might support this functionality also

Zaratite answered 17/11, 2018 at 14:21 Comment(0)
F
3

You can define next class:

public class ObjectMapperUtils {

    private static ModelMapper modelMapper = new 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:

MyEntity entity = ObjectMapperUtils.map(dto, existingEntity);
Fimbriate answered 14/12, 2017 at 15:29 Comment(0)
S
1

We can use Map Struct here. Link for reference on how to use it : https://www.baeldung.com/mapstruct

Sent answered 4/5, 2021 at 6:58 Comment(0)
N
0

Translated from Portuguese

https://pt.https://mcmap.net/q/263202/-what-would-a-log4net-wrapper-class-look-like

Use Pattern Assembler: You could convert Entity to DTO through the assembler pattern but it is wrong (I think), it breaks the sense of the DTO which is a standard for transferring objects. See that it can be composed by of several entities. The correct thing is to use set methods of the instances of the objects in the classes of services, taking the DTO's and assembling them as entities, it is simply because you are working correctly with the standard.

But it has a way that even if it being wrong it would work, but only a 1 x 1 association between entity x DTO, use Guava function.

Eg: to convert Translate to transform into objects and lists with

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);
    }
}

What 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 inverse process of turning one or a list of DTOs into objects, but keep in mind that the association was 1x1. To do this, simply reverse the objects in the implementation of the function, eg:

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);
        }
    }
Northumbria answered 3/10, 2017 at 2:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.