rap example dozerbeanmapper bean java mapping dozer data-mapping

java - example - Cómo mapear colecciones en Dozer



dozerbeanmapper (8)

Me gustaría hacer algo como:

ArrayList<CustomObject> objects = new ArrayList<CustomObject>(); ... DozerBeanMapper MAPPER = new DozerBeanMapper(); ... ArrayList<NewObject> newObjects = MAPPER.map(objects, ...);

Asumiendo:

<mapping> <class-a>com.me.CustomObject</class-a> <class-b>com.me.NewObject</class-b> <field> <a>id</a> <b>id2</b> </field> </mapping>

Lo intenté :

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

pero el objeto titular está vacío. También jugué cambiando el segundo argumento sin suerte ...



Lo he hecho usando Java 8 y Dozer 5.5. No necesitas ningún archivo XML para mapear. Puedes hacerlo en Java.

No necesita ningún mapeo adicional para las listas , solo lo que necesita es

necesita agregar la lista como un campo en el mapeo

. Vea la configuración del bean de muestra a continuación.

Clase de configuracion 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; } }

// Las clases Answer y AnswerDTO tienen los mismos atributos

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

// La clase QuestionAndAnswerDTO tiene una lista de Respuestas

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

// LET la clase QuestionAndAnswer tiene campos similares como QuestionAndAnswerDTO

// Luego, para usar el mapeador en tu código, autowire it

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

Espero que esto ayude a alguien a seguir el enfoque de Java en lugar de XML.


Lo que está sucediendo es que está siendo mordido por el borrado de tipo. En el tiempo de ejecución, Java solo ve un ArrayList.class . El tipo de CustomObject y NewObject no están allí, por lo que Dozer está intentando asignar un java.util.ArrayList , no su CustomObject a NewObject .

Lo que debería funcionar (totalmente no probado):

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


Me enfrenté a un problema similar y decidí usar un método de utilidad genérico para evitar la iteración cada vez que necesitaba realizar dicho mapeo.

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

El uso sería entonces algo como:

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

Posiblemente esto podría ser simplificado aún más.


No es realmente una mejora, es más como un azúcar sintáctico que se puede lograr gracias a la Guava (y lo más probable es que sea posible con Apache Commons ):

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

Esto también puede convertirse en una función genérica, como se sugiere en otras respuestas.


Para ese caso de uso, una vez escribí una pequeña clase de ayuda:

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

Entonces llamaría a dozer de la siguiente manera:

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

Solo inconveniente: mapper.map(...) advertencia "sin mapper.map(...) " en mapper.map(...) debido a que la interfaz de Dozers Mapper no maneja tipos genéricos.


Puede implementar su propia clase de asignador que extenderá el asignador de topadora. Ejemplo: Cree una interfaz que agregue un método adicional al Dozer Mapper:

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

Siguiente paso: escriba su propia clase de asignador implementando la interfaz anterior.

Agregue el siguiente método a su clase de implementación:

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

Espero que esto ayude


Puedes hacerlo así:

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

}

y úsalo:

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