复杂对象的推土机映射
Dozer mapping for complex objects
我有 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>
现在上面的映射将名称等字段从 SourceObj 复制到 DestObj,但无法将地址列表从 src 包映射到目标包的地址列表。同样在 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:?]
请告知本案例的解决方案。
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 映射这两个字段,因为它们具有不同的名称。
经过反复试验,我找到了答案。请参考以下解决方案。
<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,如上所示。所有其他字段名称在两个地址对象中具有相同的名称,因此将自动复制值。
我有 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>
现在上面的映射将名称等字段从 SourceObj 复制到 DestObj,但无法将地址列表从 src 包映射到目标包的地址列表。同样在 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:?]
请告知本案例的解决方案。
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 映射这两个字段,因为它们具有不同的名称。
经过反复试验,我找到了答案。请参考以下解决方案。
<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,如上所示。所有其他字段名称在两个地址对象中具有相同的名称,因此将自动复制值。