Como mapear collections no Dozer

Eu gostaria de fazer algo como:

ArrayList objects = new ArrayList(); ... DozerBeanMapper MAPPER = new DozerBeanMapper(); ... ArrayList newObjects = MAPPER.map(objects, ...); 

Assumindo:

  com.me.CustomObject com.me.NewObject  id id2   

Eu tentei :

 ArrayList holder = new ArrayList(); MAPPER.map(objects, holder); 

mas o object titular está vazio. Eu também joguei com mudar o segundo argumento sem sorte …

Citar:

“As collections aninhadas são tratadas automaticamente, mas você está certo de que as collections de nível superior precisam ser iteradas. Atualmente, não há uma maneira mais elegante de lidar com isso.”

Alguém descobriu uma maneira de fazer isso sem uma construção de loop na sua base de código , mas acho que é mais fácil (e mais legível / sustentável) colocá-lo em seu código. Espero que eles adicionem essa habilidade mais cedo ou mais tarde.

Eu enfrentei um problema semelhante e decidi usar um método utilitário genérico para evitar a repetição toda vez que eu precisasse executar esse mapeamento.

 public static  List map(final Mapper mapper, final List source, final Class destType) { final List dest = new ArrayList<>(); for (T element : source) { dest.add(mapper.map(element, destType)); } return dest; } 

O uso seria então algo como:

  final List accounts..... final List actual = Util.map(mapper, accounts, NewObject.class); 

Possivelmente isso poderia ser simplificado ainda mais.

O que está acontecendo é que você está sendo mordido pelo apagamento do tipo. Em tempo de execução, o java só vê um ArrayList.class . O tipo de CustomObject e NewObject não está lá, então o Dozer está tentando mapear um java.util.ArrayList , não seu CustomObject para NewObject .

O que deve funcionar (totalmente não testado):

 List ori = new ArrayList(); List n = new ArrayList(); for (CustomObject co : ori) { n.add(MAPPER.map(co, CustomObject.class)); } 

você pode fazer assim:

 public  List mapListObjectToListNewObject(List objects, Class newObjectClass) { final List newObjects = new ArrayList(); for (S s : objects) { newObjects.add(mapper.map(s, newObjectClass)); } return newObjects; 

}

e usá-lo:

 ArrayList objects = .... List newObjects = mapListObjectToListNewObject(objects,NewObject.class); 

Para esse caso de uso, uma vez escrevi uma pequena class de ajudante:

 import java.util.Collection; /** * Helper class for wrapping top level collections in dozer mappings. * * @author Michael Ebert * @param  */ public final class TopLevelCollectionWrapper { private final Collection collection; /** * Private constructor. Create new instances via {@link #of(Collection)}. * * @see {@link #of(Collection)} * @param collection */ private TopLevelCollectionWrapper(final Collection collection) { this.collection = collection; } /** * @return the wrapped collection */ public Collection getCollection() { return collection; } /** * Create new instance of {@link TopLevelCollectionWrapper}. * * @param  * Generic type of {@link Collection} element. * @param collection * {@link Collection} * @return {@link TopLevelCollectionWrapper} */ public static  TopLevelCollectionWrapper of(final Collection collection) { return new TopLevelCollectionWrapper(collection); } } 

Você então chamaria dozer da seguinte maneira:

 private Mapper mapper; @SuppressWarnings("unchecked") public Collection getMappedCollection(final Collection collection) { TopLevelCollectionWrapper wrapper = mapper.map( TopLevelCollectionWrapper.of(collection), TopLevelCollectionWrapper.class); return wrapper.getCollection(); } 

Única desvantagem: Você obtém um aviso “não verificado” no mapper.map(...) porque a interface do Dozers Mapper não manipula tipos genéricos.

Eu fiz isso usando o Java 8 e dozer 5.5. Você não precisa de nenhum arquivo XML para mapeamento. Você pode fazer isso em Java.

Você não precisa de nenhum mapeamento adicional para listas , a única coisa que você precisa é

você precisa adicionar a lista como um campo no mapeamento

. Veja a configuração do bean de amostra abaixo.

Classe de configuração de primavera

 @Configuration public class Config { @Bean public DozerBeanMapper dozerBeanMapper() throws Exception { DozerBeanMapper mapper = new DozerBeanMapper(); mapper.addMapping( new BeanMappingBuilder() { @Override protected void configure() { mapping(Answer.class, AnswerDTO.class); mapping(QuestionAndAnswer.class, QuestionAndAnswerDTO.class).fields("answers", "answers"); } }); return mapper; } } 

// A class de resposta e as classs AnswerDTO possuem os mesmos atributos

 public class AnswerDTO { public AnswerDTO() { super(); } protected int id; protected String value; //setters and getters } 

// A class QuestionAndAnswerDTO tem uma lista de respostas

 public class QuestionAndAnswerDTO { protected String question; protected List answers; //setters and getters } 

// Então, para usar o mapeador em seu código, autowire

 @Autowired private DozerBeanMapper dozerBeanMapper; // in your method QuestionAndAnswerDTO questionAndAnswerDTO = dozerBeanMapper.map(questionAndAnswer, QuestionAndAnswerDTO.class); 

Espero que isso ajude alguém a seguir a abordagem Java em vez de XML.

Não é realmente uma melhoria, mais como um açúcar sintático que pode ser alcançado graças a Goiaba (e provavelmente algo similar é possível com o Apache Commons ):

 final List mapped = Lists.newArrayList(Iterables.transform(inputList, new Function() { @Override public MyPojo apply(final MyEntity arg) { return mapper.map(arg, MyPojo.class); } })); 

Isso também pode ser transformado em uma function genérica – como sugerido em outras respostas.

Você pode implementar sua própria class de mapeador que estenderá o mapeador do dozer. Exemplo: crie uma interface que adicione método adicional ao mapeador do dozer:

 public interface Mapper extends org.dozer.Mapper {  List mapAsList(Iterable sources, Class destinationClass); } 

Próxima etapa: escreva sua própria class Mapper implementando a interface acima.

adicione o método abaixo à sua class de implementação:

 public class MyMapper implements Mapper { @Override public  List mapAsList(Iterable sources, Class destinationClass) { //can add validation methods to check if the object is iterable ArrayList targets = new ArrayList(); for (Object source : sources) { targets.add(map(source, destinationClass)); } return targets; } //other overridden methods. } 

Espero que isto ajude

Intereting Posts