使用推土机是否可以将多个字段映射到一个字段?
With dozer is it possible to map several fields to one field?
我们有一些我们正在尝试映射的遗留数据...遗留数据有月日年的字段...
是否可以转换
MyObject.day
MyObject.year
MyObject.month
至
MyOtherObject.date
我找不到关于此主题的任何文档。任何将不胜感激。
How do I map multiple fields to a single field?
Dozer doesn't currently support this. And because of the complexities around ? implementing it, this feature is not currently on the road map. A possible solution would be to wrap the multiple fields in a custom complex type and then define a custom converter for mapping between the complex type and the single field. This way, you could handle the custom logic required to map the three fields into the single one within the custom converter.
如果您可以控制遗留数据,则可以创建一个类型来包装各个日期字段:
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;
}
日期自定义转换器.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
。
如果您需要将两个字段映射到一个字段,反之亦然,我会推荐一些不同的解决方案。
Dozer 可以将用户 setters/getters 作为制作地图的方式。在你必须这样做的 class 上(你有两个字段并想映射到单个字段)使用设置器,你可以在其中提供来自不同对象的单个字段,并在 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>
示例getters/setters:
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();
}
}
这是解决问题的快速方法。
这可能与问题 100% 不匹配,但我来这里是为了找到这个解决方案(可能还有许多其他问题)。这是做什么的:将单个字段值映射到目标 class 中的两个字段,条件是要寻址哪个目标。想象一个单一的“名称”字段,它应该映射到目标 class 中的名称和名称缩写字段。
我正在使用推土机“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;
}
}
我知道这是一个古老的 post,但我找不到令人满意的答案,花了很多时间才发现这个(我认为)简单的方法。您可以在 mapping.xml.
中将 ConfigurableCustomConver 与 '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;
}
}
我们有一些我们正在尝试映射的遗留数据...遗留数据有月日年的字段...
是否可以转换
MyObject.day
MyObject.year
MyObject.month
至
MyOtherObject.date
我找不到关于此主题的任何文档。任何将不胜感激。
How do I map multiple fields to a single field?
Dozer doesn't currently support this. And because of the complexities around ? implementing it, this feature is not currently on the road map. A possible solution would be to wrap the multiple fields in a custom complex type and then define a custom converter for mapping between the complex type and the single field. This way, you could handle the custom logic required to map the three fields into the single one within the custom converter.
如果您可以控制遗留数据,则可以创建一个类型来包装各个日期字段:
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;
}
日期自定义转换器.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
。
如果您需要将两个字段映射到一个字段,反之亦然,我会推荐一些不同的解决方案。
Dozer 可以将用户 setters/getters 作为制作地图的方式。在你必须这样做的 class 上(你有两个字段并想映射到单个字段)使用设置器,你可以在其中提供来自不同对象的单个字段,并在 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>
示例getters/setters:
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();
}
}
这是解决问题的快速方法。
这可能与问题 100% 不匹配,但我来这里是为了找到这个解决方案(可能还有许多其他问题)。这是做什么的:将单个字段值映射到目标 class 中的两个字段,条件是要寻址哪个目标。想象一个单一的“名称”字段,它应该映射到目标 class 中的名称和名称缩写字段。 我正在使用推土机“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;
}
}
我知道这是一个古老的 post,但我找不到令人满意的答案,花了很多时间才发现这个(我认为)简单的方法。您可以在 mapping.xml.
中将 ConfigurableCustomConver 与 '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;
}
}