【问题标题】:Dozer mapping for complex objects复杂物体的推土机映射
【发布时间】:2019-10-11 11:51:20
【问题描述】:

我有 2 个 POJO,如下所示:

package com.main.java.src;

    public class SourceObj {

    protected String name;
    ...
    ...
    10 String objects

    protected Addresses addresses; 

    ...
    ...
    getter and setter for all fields

    }
---------    
package com.java.main.src;

    public class Addresses {
     protected List<Address> address;
    ...
    getters and setters

}

    package com.main.java.src;

    public class Address {
       protected String city;

       protected List<Contact> contact;

    ...

    getters & setters
    }

-----
package com.main.java.dest;
    public class DestObj {

    protected String name;
    ...
    ...
    10 String objects

    protected Addresses addresses; 

    ...
    ...
    getter and setter for all fields

    }

----------------
package com.main.java.dest;

    public class Addresses {
     protected List<Address> address;
    ...
    getters and setters
    }

package com.main.java.dest;
    public class Address {
       protected String city;

       protected List<Contact> contact;

    ...

    getters & setters
    }

Now i have the dozer-configuration.xml as follows:

    <?xml version="1.0" encoding="UTF-8"?>
    <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
        <configuration>
            <stop-on-errors>true</stop-on-errors>
            <trim-strings>true</trim-strings>
            <relationship-type>non-cumulative</relationship-type>       
        </configuration>

        <mapping>
            <class-a>com.main.java.src.SourceObj</class-a>
            <class-b>com.main.java.dest.DestObj</class-b>
            <field>
                <a>addresses.address</a>
                <b>addresses.address</b>
                <a-hint>com.main.java.src.Address</a-hint>
                <b-hint>com.main.java.dest.Address</b-hint>
            <field> 
        </mapping>
    </mappings>

现在上面的映射将 name 等字段从 SourceObj 复制到 DestObj,但无法将 src 包的地址列表映射到 dest 包的地址列表。再次在 Address 对象中,有一个 Contact 对象列表。

我找到的一个解决方案是编写一个自定义转换器,它将原始字段值一个接一个地复制,然后将所有对象从一个列表复制到另一个目标列表。

但我正在 dozer-configuration.xml 中寻找解决方案。

在上述 xml 映射之后,我得到以下异常:

MapId: null
  Type: null
  Source parent class: com.main.java.src.SourceObj
  Source field name: addresses.address
  Source field type: class java.util.ArrayList
  Source field value: [com.main.java.src.Address@1b65d51d]
  Dest parent class: com.main.java.dest.DestObj
  Dest field name: addresses.address
  Dest field type: java.util.List

java.lang.NullPointerException: null
    at org.dozer.util.ReflectionUtils.invoke(ReflectionUtils.java:329) ~[dozer-5.5.1.jar:?]
    at org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.writeDeepDestinationValue(GetterSetterPropertyDescriptor.java:268) ~[dozer-5.5.1.jar:?]
    at org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.setPropertyValue(GetterSetterPropertyDescriptor.java:96) ~[dozer-5.5.1.jar:?]
    at org.dozer.fieldmap.FieldMap.writeDestValue(FieldMap.java:96) ~[dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.writeDestinationValue(MappingProcessor.java:939) ~[dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.mapFromFieldMap(MappingProcessor.java:368) ~[dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.mapField(MappingProcessor.java:307) [dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:267) [dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.mapToDestObject(MappingProcessor.java:216) [dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.createByCreationDirectiveAndMap(MappingProcessor.java:196) [dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.mapGeneral(MappingProcessor.java:170) [dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:104) [dozer-5.5.1.jar:?]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:99) [dozer-5.5.1.jar:?]
    at org.dozer.DozerBeanMapper.map(DozerBeanMapper.java:120) [dozer-5.5.1.jar:?]

请告知本案的解决方案。

【问题讨论】:

    标签: java converters dozer


    【解决方案1】:

    Dozer 将自动映射具有相同名称和类型的任何内容。当您要映射的字段有不同的名称时,您必须在映射中明确告诉 Dozer 哪些字段要相互映射。 在上面的问题中,AddressSrc 和 AddressDest 是具有不同名称的字段。因此,您必须明确告诉 Dozer 将这两个字段相互映射。

    <mapping>
        <class-a>SourceObj</class-a>
        <class-b>DestObj</class-b>    
        <field>
            <a>addressesSrc</a>
            <b set-method="customSetMethodName">addressesDest</b>
        </field>  
    </mapping>
    

    您可能需要额外的映射说明才能获得最终想要的结果。但是,这是让 Dozer 映射这两个字段所需的缺失映射部分,因为它们具有不同的名称。

    【讨论】:

    • 其实两个字段的名字都是地址,但是包名不同。这种情况应该怎么办?
    • 请提供更准确的示例表示(即匹配字段名称和匹配的类型等)另外,请提供有关集合结果的更多详细信息,即结果集合中的对象是否正确类型?和正确的号码?什么是映射的,什么不是?
    • 嗨,John,我已经编辑了代码以获得更好的表示。 SourceObj 和 DestObj 的成员变量名称相同,但它们的类型不同,即 SourceObj 中的地址来自包 com.java.main.src,而 DestObj 中的地址来自 com.java.main.dest。它们再次包含地址对象列表。 Address 对象的一种类型是 com.java.main.src.Address,另一种是 com.java.main.dest.Address。 Contact 类也是 com.java.main.src.Contact 和 com.java.main.dest.Contact 两种类型。请提供推土机映射。
    • 谢谢...非常有帮助,堆栈跟踪也是如此。基本上,堆栈跟踪表明某处缺少/命名错误的设置器。 Dozer 期望 getter/setter 方法遵循约定。如果他们不这样做,您可以为映射中的任何字段指定客户 getter 或 setter 名称。我已经更新了答案以显示如何。
    • 嗨,John,我调试了代码,在调试时我看到控件进入 Addresses 类的 setter 方法,但 Address 对象列表为空。我也尝试过使用自定义设置方法,但这也有同样的问题。
    【解决方案2】:

    经过反复试验,我找到了答案。请参考以下解决方案。

    <mapping>
      <class-a>com.java.main.src.SourceObj</class-a>
      <class-b>com.java.main.dest.DestObj</class-b>
      <field>><!-- java.util.List to java.util.List -->
         <a is-accessible="true">addresses.address</a>
         <b is-accessible="true">addresses.address</b>
         <a-hint>com.java.main.src.Address</a-hint>
         <b-hint>com.java.main.dest.Address</b-hint>
      </field>
    </mapping>
    
    <mapping>
      <class-a>com.java.main.src.Address</class-a>
      <class-b>com.java.main.dest.Address</class-b>
      <field>
         <a get-method="isIsPrimaryAddress">isIsPrimaryAddress</a>
         <b get-method="isIsPrimaryAddress">isIsPrimaryAddress</b>     
      </field>
    </mapping>
    

    如果对于 Address 对象,getter 方法未定义为 getFieldName,在这种情况下,您需要映射,因为我们已经映射了 isIsPrimaryAddress,如上所示。所有其他字段名称在两个地址对象中具有相同的名称,因此将自动复制值。

    【讨论】:

    • Offtopic:Dozer 效率低下,因为它基于 Reflection API。我建议您迁移到现代地图工具,例如 OrikaMapStruct
    • 是的,我们正在考虑迁移到 MapStruct
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多