Dozer对象映射框架Map到JSONString映射问题排查

引言

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方法中加了断点,发现了传入的源对象是一个空值:
Dozer对象映射框架Map到JSONString映射问题排查
为什么明明有map对象设置,到自定义转换器哪里就为空了。于是从dozer的map方法开始debug:

  1. 实际是调用了MappingProcessor做映射处理,
    Dozer对象映射框架Map到JSONString映射问题排查
  2. 获取每个字段的值:Dozer对象映射框架Map到JSONString映射问题排查 从断点显示的值看,这里取到的就是null了。
  3. 问题就应该出在 srcFieldValue = fieldMapping.getSrcFieldValue(srcObj);
  4. FieldMap有多个对象实现类,Dozer对象映射框架Map到JSONString映射问题排查,在这里需要查看MapFieldMap获取对象。
    Dozer对象映射框架Map到JSONString映射问题排查,默认设置Map和字段做映射的时候,会将Map作为对象,调用get方法,以配置的字段名作为key获取值,在这个场景就是Map.get("field")取值,所以取到的为空。

解决方案

  1. 解决方案其实很简单,更改配置映射文件加上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>
  1. 重新执行后:
    Dozer对象映射框架Map到JSONString映射问题排查

由于getSrcHintContainer() 不为空,会执行到标红的逻辑,即直接从对象中获取Map的字段作为值返回,
Dozer对象映射框架Map到JSONString映射问题排查

上一篇:产品发布 | 阿里云CDN全面支持IETF QUIC


下一篇:EMR Spark-SQL性能极致优化揭秘 Native Codegen Framework