如何在Dozer中映射集合
我想做的事情如下:
ArrayList objects = new ArrayList(); ... DozerBeanMapper MAPPER = new DozerBeanMapper(); ... ArrayList newObjects = MAPPER.map(objects, ...);
假设:
com.me.CustomObject com.me.NewObject id id2
我试过了 :
ArrayList holder = new ArrayList(); MAPPER.map(objects, holder);
但是持有者对象是空的。 我还玩了改变第二个参数没有任何运气…
去引用:
“嵌套集合是自动处理的,但你认为顶层集合需要迭代是正确的。目前没有更优雅的方法来处理它。”
有人在你的代码库中没有循环结构的情况下找到了一种方法 ,但我认为将它放在你的代码中会更容易(并且更易读/可维护)。 希望他们能够比以后更快地添加这种能力。
我遇到了类似的问题,并决定使用通用实用程序方法来避免每次需要执行此类映射时进行迭代。
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; }
用法将是这样的:
final List accounts..... final List actual = Util.map(mapper, accounts, NewObject.class);
可能这可以进一步简化。
发生的事情是你被类型擦除所咬。 在运行时,java只能看到一个ArrayList.class
。 不存在CustomObject
和NewObject
的类型,因此Dozer正在尝试将java.util.ArrayList
而不是CustomObject
到NewObject
。
什么应该工作(完全未经测试):
List ori = new ArrayList (); List n = new ArrayList (); for (CustomObject co : ori) { n.add(MAPPER.map(co, CustomObject.class)); }
你可以这样做:
public List mapListObjectToListNewObject(List objects, Class newObjectClass) { final List newObjects = new ArrayList (); for (S s : objects) { newObjects.add(mapper.map(s, newObjectClass)); } return newObjects;
}
并使用它:
ArrayList objects = .... List newObjects = mapListObjectToListNewObject(objects,NewObject.class);
对于那个用例,我曾写过一个小助手类:
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); } }
然后,您将以下列方式调用dozer:
private Mapper mapper; @SuppressWarnings("unchecked") public Collection getMappedCollection(final Collection collection) { TopLevelCollectionWrapper wrapper = mapper.map( TopLevelCollectionWrapper.of(collection), TopLevelCollectionWrapper.class); return wrapper.getCollection(); }
唯一的缺点:由于Dozers Mapper接口不处理generics类型,因此在mapper.map(...)
上出现“未选中”警告。
我使用Java 8和dozer 5.5完成了它。 您不需要任何XML文件进行映射。 你可以用Java做到这一点。
您不需要任何其他列表映射 ,只需要您需要的东西
您需要将列表添加为映射中的字段
。 请参阅下面的示例bean配置。
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类有一个Answers列表
public class QuestionAndAnswerDTO { protected String question; protected List answers; //setters and getters }
//然后在代码中使用映射器,自动assembly它
@Autowired private DozerBeanMapper dozerBeanMapper; // in your method QuestionAndAnswerDTO questionAndAnswerDTO = dozerBeanMapper.map(questionAndAnswer, QuestionAndAnswerDTO.class);
希望这有助于有人遵循Java方法而不是XML。
这不是一个改进,更像是一个可以通过Guava实现的语法糖(并且很可能与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); } }));
这也可以转换为通用function – 如其他答案所示。
您可以实现自己的mapper类,它将扩展dozer映射器。 示例:创建一个向dozer映射器添加其他方法的接口:
public interface Mapper extends org.dozer.Mapper { List mapAsList(Iterable> sources, Class destinationClass); }
下一步:通过实现上面的接口编写自己的Mapper类。
将以下方法添加到您的实现类:
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. }
希望这可以帮助