引言
Dozer是一个优秀的对象映射的框架,可以帮助程序员减少大量的对象之间映射的get/set代码,在ATA上有好几篇文章介绍了dozer的使用:
dozer开发手册
使用Dozer帮你提高开发效率(解决繁琐的DO转BO、TO转BO问题) 有兴趣的同学,可以去看下基本的使用。
问题
我在开发后台系统中,经常会遇到从前台提交的对象,转为后台的服务模型对象做操作,通过dozer工具,灵活的配置就可以轻易的解决。我需要将将一个对象的Map对象转为json的字符串,按照dozer的文档需要编写自定义的Convertor来进行处理(这里面针对字段的转换,,dozer支持类级别,字段级别的Convertor. ),但测试却发现了一些问题。具体请看例子:
源对象
public class SourceA{
private Map<String,Object> field;
//省略get/set
}
public class SourceB{
private String field;
//省略get/set
}
//dozerMapper配置
<?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">
<mapping type="bi-directional">
<class-a>com.alibaba.xxx.SourceA</class-a>
<class-b>com.alibaba.xxx.SourceB</class-b>
<field custom-converter="com.alibaba.xxx.JsonConverter">
<a>field</a>
<b>field</b>
</field>
</mapping>
</mappings>
//自定义的Convertor
public class JsonConverter extends DozerConverter<Map,String> {
public JsonConverter(){
super(Map.class, String.class);
}
@Override
public String convertTo(Map source, String destination) {
if (source == null) {
return null;
}
return JSON.toJSONString(source);
}
@Override
public Map convertFrom(String source, Map destination) {
if (source == null) {
return null;
}
return JSON.parseObject(source);
}
}
//单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:dozer_test/test.xml" })
public class DozerBugTest {
@Resource
DozerBeanMapper dozerBeanMapper;
@Test
public void test_mapper(){
SourceA sa = new SourceA();
Map<String,Object> map = Maps.newHashMap();
map.put("losemoney", "losemoney");
clueInfo.setField(map);
SourceB sourceB = new SourceB();
dozerBeanMapper.map(sa, sourceB);
assertNotNull(sourceB.getField());
}
}
从结果上,我是期望传入的Map对象自动可以转为JSON的字符串进行处理,但是跑了单元测试执行的结果是不通过。
分析
我在自定义的转换器JsonConverter类的convertTo方法中加了断点,发现了传入的源对象是一个空值:
为什么明明有map对象设置,到自定义转换器哪里就为空了。于是从dozer的map方法开始debug:
- 实际是调用了MappingProcessor做映射处理,
- 获取每个字段的值: 从断点显示的值看,这里取到的就是null了。
- 问题就应该出在 srcFieldValue = fieldMapping.getSrcFieldValue(srcObj);
- FieldMap有多个对象实现类,,在这里需要查看MapFieldMap获取对象。
,默认设置Map和字段做映射的时候,会将Map作为对象,调用get方法,以配置的字段名作为key获取值,在这个场景就是Map.get("field")取值,所以取到的为空。
解决方案
- 解决方案其实很简单,更改配置映射文件加上java.util.HashMap
<?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">
<mapping type="bi-directional">
<class-a>com.alibaba.xxx.SourceA</class-a>
<class-b>com.alibaba.xxx.SourceB</class-b>
<field custom-converter="com.alibaba.xxx.JsonConverter">
<a>field</a>
<b>field</b>
<a-hint>java.util.HashMap</a-hint>
</field>
</mapping>
</mappings>
- 重新执行后:
由于getSrcHintContainer() 不为空,会执行到标红的逻辑,即直接从对象中获取Map的字段作为值返回,