Java 如何在 Dozer 中映射集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1358595/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:08:00  来源:igfitidea点击:

How to map collections in Dozer

javamappingdozerdata-mapping

提问by Stephane Grenier

I'd like to do something like:

我想做类似的事情:

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

Assuming:

假设:

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

I tried :

我试过 :

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

but the holder object is empty. I also played with changing the second argument without any luck...

但持有者对象是空的。我也玩过改变第二个论点而没有任何运气......

采纳答案by Stephane Grenier

To quote:

报价:

"Nested collections are handled automatically, but you are correct that top level collections need to be iterated over. Currently there isn't a more elegant way to handle this."

“嵌套集合是自动处理的,但是顶级集合需要迭代是正确的。目前没有更优雅的方法来处理这个问题。”

Someone has figured a way to do it without a looping construct in your code base, but I think it's just easier (and more readable/maintainable) to put it in your code. Hopefully they'll add this ability sooner than later.

有人已经想出了一种方法来在您的代码库中不使用循环结构,但我认为将它放在您的代码中更容易(并且更具可读性/可维护性)。希望他们迟早会添加此功能。

回答by Yishai

What is happening is that you are getting bitten by type erasure. At runtime, java only sees an ArrayList.class. The type of CustomObjectand NewObjectaren't there, so Dozer is attempting to map a java.util.ArrayList, not your CustomObjectto NewObject.

正在发生的事情是你被类型擦除咬了。在运行时,java 只看到一个ArrayList.class. 该类型的CustomObjectNewObject不存在,所以推土机试图映射java.util.ArrayList,而不是你CustomObjectNewObject

What should work (totally untested):

什么应该工作(完全未经测试):

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

回答by ebi

For that use case I once wrote a little helper 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);
    }
}

You then would call dozer in the following manner:

然后,您可以通过以下方式调用推土机:

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

Only drawback: You get a "unchecked" warning on mapper.map(...)because of Dozers Mapper interface not handling generic types.

唯一的缺点:mapper.map(...)由于 Dozers Mapper 接口不处理泛型类型,您会收到“未经检查”的警告。

回答by Michael-7

I faced a similar issue, and decided on using a generic utility method to avoid iterating every time I needed to perform such mapping.

我遇到了类似的问题,并决定使用通用实用程序方法来避免每次需要执行此类映射时都进行迭代。

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

Usage would then be something like:

用法将类似于:

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

Possibly this could be simplified further though.

可能这可以进一步简化。

回答by Anonymous

Not really an improvement, more like a syntactic sugar that can be achieved thanks to Guava(and most likely similar thing is possible with Apache Commons):

并不是真正的改进,更像是一种可以通过Guava实现的语法糖(很可能类似的事情可以通过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);
    }
}));

This can also be turned into a generic function - as suggested in other answers.

这也可以变成通用函数 - 正如其他答案中所建议的那样。

回答by Taoufiq BOUKCHA

you can do it like this :

你可以这样做:

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;

}

}

and use it :

并使用它:

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

回答by Bikas Katwal

You can implement your own mapper class which will extend dozer mapper. Example: Create a interface that adds additional method to dozer mapper:

您可以实现自己的映射器类,该类将扩展推土机映射器。示例:创建一个向推土机映射器添加附加方法的接口:

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

Next step: Write your own Mapper class by implementing above interface.

下一步:通过实现上述接口编写您自己的 Mapper 类。

add below method to your implementation class:

将以下方法添加到您的实现类:

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.
}

Hope this helps

希望这可以帮助

回答by Vins

I have done it using Java 8 and dozer 5.5. You don't need any XML files for mapping. You can do it in Java.

我已经使用 Java 8 和推土机 5.5 完成了它。您不需要任何用于映射的 XML 文件。你可以用Java来做。

You don't need any additional mapping for lists, only thing you need is

您不需要任何额外的列表映射,您只需要

you need to add the list as a field in the mapping

您需要将列表添加为映射中的字段

. See the sample bean config below.

. 请参阅下面的示例 bean 配置。

Spring configuration class

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

}

//Answer class and AnswerDTO classes have same attributes

//Answer 类和AnswerDTO 类具有相同的属性

public class AnswerDTO {

    public AnswerDTO() {
        super();
    }

    protected int id;
    protected String value;

    //setters and getters
}

//QuestionAndAnswerDTO class has a list of Answers

//QuestionAndAnswerDTO 类有一个答案列表

public class QuestionAndAnswerDTO {

    protected String question;
    protected List<AnswerDTO> answers;

   //setters and getters
}

//LET the QuestionAndAnswer class has similar fields as QuestionAndAnswerDTO

//让 QuestionAndAnswer 类具有与 QuestionAndAnswerDTO 类似的字段

//Then to use the mapper in your code, autowire it

//然后在你的代码中使用映射器,自动装配它

@Autowired
private DozerBeanMapper dozerBeanMapper;
// in your method


 QuestionAndAnswerDTO questionAndAnswerDTO =
    dozerBeanMapper.map(questionAndAnswer, QuestionAndAnswerDTO.class);

Hope this will help someone follow the Java approach instead of XML.

希望这将有助于有人遵循 Java 方法而不是 XML。