题
我想要做的是这样的:
ArrayList<CustomObject> objects = new ArrayList<CustomObject>();
...
DozerBeanMapper MAPPER = new DozerBeanMapper();
...
ArrayList<NewObject> newObjects = MAPPER.map(objects, ...);
假设:
<mapping>
<class-a>com.me.CustomObject</class-a>
<class-b>com.me.NewObject</class-b>
<field>
<a>id</a>
<b>id2</b>
</field>
</mapping>
我尝试:
ArrayList<NewObject> holder = new ArrayList<NewObject>();
MAPPER.map(objects, holder);
但保持器对象是空的。我也发挥与改变第二个参数没有任何的运气...
解决方案
要报价:
“嵌套集合被处理 自动的,但你是正确的 是顶级藏品需 遍历。目前还没有一个 更优雅的方式来处理这种“。
有人想出一种方法来做到这一点而不一个循环构造在代码库一>,但我认为它只是更容易(和更具可读性/维护),把它放在你的代码。希望他们会更快地增加这种能力比晚。
其他提示
我面临着类似的问题,并决定使用通用工具方法,以避免每次迭代我需要执行这种映射的时间。
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;
}
用法然后将是这样的:
final List<CustomObject> accounts.....
final List<NewObject> actual = Util.map(mapper, accounts, NewObject.class);
可能这可以进一步简化,虽然
正在发生的事情是,你得到的类型擦除咬伤。在运行时,JAVA只看到一个ArrayList.class
。类型CustomObject
和NewObject
的是不存在,所以推土机试图映射java.util.ArrayList
,而不是你CustomObject
到NewObject
。
什么应该工作(完全未测试):
List<CustomObject> ori = new ArrayList<CustomObject>();
List<NewObject> n = new ArrayList<NewObject>();
for (CustomObject co : ori) {
n.add(MAPPER.map(co, CustomObject.class));
}
您可以做这样的:
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;
}
和使用它:
ArrayList<CustomObject> objects = ....
List<NewObject> newObjects = mapListObjectToListNewObject(objects,NewObject.class);
有关该使用情况下,我一次写了一个小的辅助类:
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);
}
}
然后,将调用推土机以下列方式:
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();
}
唯一的缺点:你会得到一个mapper.map(...)
“选中”的警告,因为推土机映射接口不处理泛型类型
我已经使用Java 8和推土机5.5做到了。你不需要任何XML文件的映射。你可以做到这一点在Java中。
您不需要为列表下,只有你需要的就是
任何额外的映射需要在列表中添加作为字段在映射
。请参见下面的样品豆配置。
Spring配置类
@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;
}
}
//回答类和AnswerDTO类具有相同的属性
public class AnswerDTO {
public AnswerDTO() {
super();
}
protected int id;
protected String value;
//setters and getters
}
// QuestionAndAnswerDTO类有答案的列表
public class QuestionAndAnswerDTO {
protected String question;
protected List<AnswerDTO> answers;
//setters and getters
}
//让QuestionAndAnswer类具有类似于字段QuestionAndAnswerDTO
//然后使用映射器中的代码,自动装配它
@Autowired
private DozerBeanMapper dozerBeanMapper;
// in your method
QuestionAndAnswerDTO questionAndAnswerDTO =
dozerBeanMapper.map(questionAndAnswer, QuestionAndAnswerDTO.class);
希望这会帮助别人遵循Java方法取代XML。
不是一个真正的改进,更像是可以实现由于番石榴一>(和最有可能的类似的事情是可能的阿帕奇百科全书):
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);
}
}));
此,也可以变成一个通用的功能 - 如在其他的答案提示
您可以实现自己的映射类这将延长推土机映射。 例: 创建增加了额外的方法来推土机映射器接口:
public interface Mapper extends org.dozer.Mapper {
<T> List<T> mapAsList(Iterable<?> sources, Class<T> destinationClass);
}
下一步:通过实现上述接口写自己的映射器类
。以下方法添加到实现类:
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.
}
希望这有助于