【问题标题】:How to map collections in Dozer如何在 Dozer 中映射集合
【发布时间】:2018-10-24 08:46:02
【问题描述】:

我想做这样的事情:

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

但是持有者对象是空的。我还尝试更改第二个参数,但没有任何运气......

【问题讨论】:

    标签: java mapping dozer data-mapping


    【解决方案1】:

    引用:

    "嵌套集合被处理 自动,但你是对的 顶级收藏品需要 迭代了一遍。目前没有一个 更优雅的方式来处理这个问题。”

    Someone has figured a way to do it without a looping construct in your code base,但我认为将它放入您的代码中更容易(并且更具可读性/可维护性)。希望他们能尽快添加此功能。

    【讨论】:

    【解决方案2】:

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

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

    也许这可以进一步简化。

    【讨论】:

      【解决方案3】:

      正在发生的事情是您被类型擦除所困扰。在运行时,java 只看到一个ArrayList.classCustomObjectNewObject 的类型不存在,因此 Dozer 正在尝试将 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));
      }
      

      【讨论】:

      • 那么除了让一个循环一个一个地映射每个对象之外,你会怎么做呢?
      • 我可以看到除了循环之外别无他法(除非 Dozer 支持对集合进行操作,否则我不太熟悉它的 API)。
      • 这就是问题所在。我相信它应该支持一种不循环的方式。我只是找不到具体的细节。
      【解决方案4】:

      你可以这样做:

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

      【讨论】:

        【解决方案5】:

        对于那个用例,我曾经写过一个小助手类:

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

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

        【讨论】:

          【解决方案6】:

          并不是真正的改进,更像是通过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);
              }
          }));
          

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

          【讨论】:

            【解决方案7】:

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

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

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

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

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

            希望对你有帮助

            【讨论】:

              【解决方案8】:

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

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

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

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

              弹簧配置类

              @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 类和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<AnswerDTO> answers;
              
                 //setters and getters
              }
              

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

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

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-11-06
                • 1970-01-01
                • 1970-01-01
                • 2015-10-01
                • 1970-01-01
                • 1970-01-01
                • 2016-02-03
                • 1970-01-01
                相关资源
                最近更新 更多