【发布时间】:2015-12-15 19:30:42
【问题描述】:
我们有一些我们正在尝试映射的旧数据...旧数据具有月日年字段...
是否可以转换
MyObject.day
MyObject.year
MyObject.month
到
MyOtherObject.date
我找不到有关此主题的任何文档。任何将不胜感激。
【问题讨论】:
我们有一些我们正在尝试映射的旧数据...旧数据具有月日年字段...
是否可以转换
MyObject.day
MyObject.year
MyObject.month
到
MyOtherObject.date
我找不到有关此主题的任何文档。任何将不胜感激。
【问题讨论】:
我知道这是一个旧帖子,但我找不到令人满意的答案,花了很多时间才发现这个(我认为)简单的方法。您可以将 ConfigurableCustomConver 与 mapping.xml 中的“this”引用结合使用。
例如:
public class Formatter implements ConfigurableCustomConverter
{
private String format;
private String[] fields;
@Override
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
List valueList = new ArrayList();
for (String field : fields){
try {
valueList.add(sourceClass.getMethod(field).invoke(sourceFieldValue));
}
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Reflection error during mapping", e);
}
}
return MessageFormat.format(format, valueList.toArray());
}
@Override
public void setParameter(String parameter)
{
String[] parameters = parameter.split("\\|");
format = parameters[0];
fields = Arrays.copyOfRange( parameters, 1, parameters.length);
}
}
在你的 mapping.xml 中:
<mapping type="one-way">
<class-a>test.model.TestFrom</class-a>
<class-b>test.model.TestTo</class-b>
<field custom-converter="nl.nxs.dozer.Formatter" custom-converter-param="{0}{1}|getFirstValue|getSecondValue">
<a>this</a>
<b>combinedValue</b>
</field>
</mapping>
类:
public class TestFrom
{
private String firstValue;
private String secondValue;
public String getFirstValue()
{
return firstValue;
}
public void setFirstValue(String firstValue)
{
this.firstValue = firstValue;
}
public String getSecondValue()
{
return secondValue;
}
public void setSecondValue(String secondValue)
{
this.secondValue = secondValue;
}
}
public class TestTo
{
private String combinedValue;
public String getCombinedValue(){
return combinedValue;
}
public void setCombinedValue(String combinedValue){
this.combinedValue = combinedValue;
}
}
【讨论】:
如果您需要将两个字段映射到单个字段,反之亦然,我会推荐一些不同的解决方案。
Dozer 可以使用用户 setter/getter 来进行映射。在您必须执行此操作的类上(您有两个字段并希望映射到单个字段)使用 setter,您可以在其中提供来自不同对象的单个字段,并在 setter/getter 逻辑上分配这两个字段。
示例映射:
<mapping type="bi-directional">
<class-a>ClassWithTwoFields</class-a>
<class-b>ClassWithSingleField</class-b>
<field>
<a get-method="getHelperField" set-method="setHelperField" >helperField</a>
<b>helperField</b>
</field>
getter/setter 示例:
public FieldType getHelperField() {
if (!isNull(field1) && !isNull(field2)) {
return field1 + field2;
}
return null;
}
public void setHelperField(FieldType singleField) {
if (!isNull(singleField)) {
this.field1 = singleField.part1();
this.field2 = singleField.part2();
}
}
这是解决问题的快速方法。
【讨论】:
如何将多个字段映射到一个字段?
Dozer 目前不支持此功能。由于周围的复杂性?实施它,此功能目前不在路线图上。一种可能的解决方案是将多个字段包装在自定义复杂类型中,然后定义自定义转换器以在复杂类型和单个字段之间进行映射。这样,您可以处理将三个字段映射到自定义转换器中的单个字段所需的自定义逻辑。
如果您可以控制旧数据,则可以创建一个类型来包装各个日期字段:
MyWrapperObject.java
public class MyWrapperObject {
private int day;
private int month;
private int year;
}
MyObject.java
public class MyObject {
private MyWrapperObject myWrapperObject;
}
然后使用自定义转换器将 3 个字段映射为日期字段:
MyOtherWrapperObject.java
public class MyOtherWrapperObject {
private Date date;
}
DateCustomConverter .java
public class DateCustomConverter implements CustomConverter {
@Override
public Object convert(Object destination, Object source,
@SuppressWarnings("rawtypes") Class destClass,
@SuppressWarnings("rawtypes") Class sourceClass) {
// Source object is null
if (source == null) {
return null;
}
if (source instanceof MyWrapperObject) {
MyOtherWrapperObject dest = new MyOtherWrapperObject();
MyWrapperObject src = (MyWrapperObject) source;
Calendar c = Calendar.getInstance();
// Months are 0 based in Java
c.set(src.getYear(), src.getMonth() - 1, src.getDay());
dest.setDate(c.getTime());
return dest;
}
return null;
}
然后在您的 XML 映射文件中引用此转换器:
dozer.xml
<mapping map-null="false" >
<class-a>com.xxx.MyObject</class-a>
<class-b>com.xxx.MyOtherObject</class-b>
...
<field custom-converter="com.xxx.DateCustomConverter">
<a>myWrapperObject</a>
<b>myOtherWrapperObject</b>
</field>
</mapping>
如果您无法控制旧数据,那么我相信您必须编写一个自定义映射器来将 MyObject 映射到 MyOtherObject。
【讨论】:
这可能与问题 100% 不匹配,但我来到这里试图找到这个解决方案(可能还有许多其他解决方案)。这是做什么的:将单个字段值映射到目标类中的两个字段,条件是要处理哪个目标。想象一个单一的“名称”字段,该字段应映射到目标类中的名称和名称缩写字段。 我正在使用推土机“ConfigurableCustomConverter”。
映射:
<field custom-converter="de.foo.MyConfCustomConverter" custom-converter-param="name">
<a>person.name</a>
<b>student.name</b>
</field>
<field custom-converter="de.foo.MyConfCustomConverter" custom-converter-param="abbreviation">
<a>person.name</a>
<b>student.shortName</b>
</field>
匹配的自定义转换器:
public class MyConfCustomConverter implements ConfigurableCustomConverter {
private String param;
@SuppressWarnings("rawtypes")
@Override
public Object convert(Object destination, Object source, Class destClass, Class sourceClass) {
if ("name".equals(this.param)) {
return (String) source;
}
else if ("abbreviation".equals(this.param)) {
return myAbbrevFunction((String) source);
}
return null;
}
@Override
public final void setParameter(String parameter) {
this.param = parameter;
}
}
如果您有要映射的其他复杂类型,您还可以实现“MapperAware”以在您的 CustomConverter 中使用 Dozer Mapper 函数:
public class MyConfCustomConverter implements ConfigurableCustomConverter, MapperAware{
private String param;
private Mapper mapper;
@SuppressWarnings("rawtypes")
@Override
public Object convert(Object destination, Object source, Class destClass, Class sourceClass) {
if ("name".equals(this.param)) {
return (String) source;
}
else if ("abbreviation".equals(this.param)) {
if(isSourceClassAComplexType()){
return mapper.map(source, my.target.package.ComplexType.class);
}
return myAbbrevFunction((String) source);
}
return null;
}
@Override
public final void setParameter(String parameter) {
this.param = parameter;
}
}
【讨论】: