4

我有一个带有自定义转换器的推土机映射:

<mapping>
    <class-a>com.xyz.Customer</class-a>
    <class-b>com.xyz.CustomerDAO</class-b>
    <field custom-converter="com.xyz.DozerEmptyString2NullConverter">
        <a>customerName</a>
        <b>customerName</b>
    </field>
</mapping>

和转换器:

public class DozerEmptyString2NullConverter extends DozerConverter<String, String> {

    public DozerEmptyString2NullConverter() {
        super(String.class, String.class);
    }

    public String convertFrom(String source, String destination) {
        String ret = null;
        if (source != null) {
            if (!source.equals(""))
            {
                ret = StringFormatter.wildcard(source);
            } 
        }
        return ret;
    }

    public String convertTo(String source, String destination) {
        return source;
    }
}

当我在一个方向(客户->客户DAO)调用映射器时,会调用“convertTo”方法。

由于 Dozer 能够处理双向映射,我希望只要我在相反方向调用映射器,就会调用方法“convertFrom”。

但是永远不会调用 convertTo 方法。

我怀疑问题是,这两种类型都是字符串 - 但我怎样才能使它工作?

作为一种解决方法,我创建了两个单向映射,这是标准解决方案,还是行为错误?

4

3 回答 3

2

是的,问题在于您的源类和目标类是相同的。这是推土机的来源DozerConverter

  public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
    Class<?> wrappedDestinationClass = ClassUtils.primitiveToWrapper(destinationClass);
    Class<?> wrappedSourceClass = ClassUtils.primitiveToWrapper(sourceClass);

    if (prototypeA.equals(wrappedDestinationClass)) {
      return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
    } else if (prototypeB.equals(wrappedDestinationClass)) {
      return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
    } else if (prototypeA.equals(wrappedSourceClass)) {
      return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
    } else if (prototypeB.equals(wrappedSourceClass)) {
      return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
    } else if (prototypeA.isAssignableFrom(wrappedDestinationClass)) {
      return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
    } else if (prototypeB.isAssignableFrom(wrappedDestinationClass)) {
      return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
    } else if (prototypeA.isAssignableFrom(wrappedSourceClass)) {
      return convertTo((A) sourceFieldValue, (B) existingDestinationFieldValue);
    } else if (prototypeB.isAssignableFrom(wrappedSourceClass)) {
      return convertFrom((B) sourceFieldValue, (A) existingDestinationFieldValue);
    } else {
      throw new MappingException("Destination Type (" + wrappedDestinationClass.getName()
          + ") is not accepted by this Custom Converter (" 
          + this.getClass().getName() + ")!");
    }

  }

不要使用convertFromand方法(它们是新 API 的一部分),而是按照教程中所示convertTo的原始方式来实现。CustomConverter.convert

于 2011-02-18T14:59:22.133 回答
0

我遇到了同样的问题,目前(从 Dozer 5.5.x 开始)没有简单的方法,但有一个复杂的方法。

请注意,它依赖于在 JVM 中未启用安全管理器,否则您将需要在安全规则中添加少量权限。这是因为该解决方案使用反射来访问 Dozer 类的私有字段。

您需要扩展 2 个类:DozerBeanMapperMappingProcessor. 您还需要枚举用于方向和接口,以从上述类中获取方向。

枚举:

public enum Direction {
    TO,
    FROM;
}

界面:

public interface DirectionAware {
    Direction getDirection();
}

类扩展DozerBeanMapper

public class DirectionAwareDozerBeanMapper extends DozerBeanMapper implements DirectionAware {
    private Direction direction;

    public DirectionAwareDozerBeanMapper(Direction direction) {
        super();
        this.direction = direction;
    }

    public DirectionAwareDozerBeanMapper(Direction direction, List<String> mappingFiles) {
        super(mappingFiles);
        this.direction = direction;
    }

    @Override
    protected Mapper getMappingProcessor() {
        try {
            Method m = DozerBeanMapper.class.getDeclaredMethod("initMappings");
            m.setAccessible(true);
            m.invoke(this);
        } catch (NoSuchMethodException|SecurityException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) {
            // Handle the exception as you want
        }

        ClassMappings arg1 = (ClassMappings)getField("customMappings");
        Configuration arg2 = (Configuration)getFieldValue("globalConfiguration");
        CacheManager arg3 = (CacheManager)getField("cacheManager");
        StatisticsManager arg4 = (StatisticsManager)getField("statsMgr");
        List<CustomConverter> arg5 = (List<CustomConverter>)getField("customConverters");
        DozerEventManager arg6 = (DozerEventManager)getField("eventManager");
        Map<String, CustomConverter> arg7 = (Map<String, CustomConverter>)getField("customConvertersWithId");

        Mapper mapper = new DirectionAwareMappingProcessor(arg1, arg2, arg3, arg4, arg5,
                                arg6, getCustomFieldMapper(), arg7, direction);

        return mapper;
    }

    private Object getField(String fieldName) {
        try {
            Field field = DozerBeanMapper.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(this);
        } catch (NoSuchFieldException|SecurityException|IllegalArgumentException|IllegalAccessException e) {
            // Handle the exception as you want
        }
        return null;
    }

    public Direction getDirection() {
        return direction;
    }
}

类扩展MappingProcessor

public class DirectionAwareMappingProcessor extends MappingProcessor implements DirectionAware {
    private Direction direction;

    protected DirectionAwareMappingProcessor(ClassMappings arg1, Configuration arg2, CacheManager arg3, StatisticsManager arg4, List<CustomConverter> arg5, DozerEventManager arg6, CustomFieldMapper arg7, Map<String, CustomConverter> arg8, Direction direction) {
        super(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
        this.direction = direction;
    }

    public Direction getDirection() {
        return direction;
    }
}

现在,用法。

1) 每次您想要映射相同的原始类型(例如 String-String)时,DozerConverter在您的推土机映射文件中使用该类型作为两个参数的自定义转换器。这种转换器的实现应该扩展:DozerConverter<String,String>并实现MapperAware接口。这一点很重要MapperAware,因为有了映射器,您就可以将其投射到DirectionAware然后获得方向。

例如:

public class MyMapper extends DozerConverter<String, String> implements MapperAware {
    private DirectionAware dirAware;

    public MyMapper(Class<String> cls) {
        super(cls, cls);
    }

    @Override
    public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<String> destinationClass, Class<String> sourceClass) {
        if (dirAware.getDirection() == Direction.FROM) {
            // TODO convert sourceFieldValue for "FROM" direction and return it
        } else {
            // TODO convert sourceFieldValue for "TO" direction and return it
        }
    }

    @Override
    public void setMapper(Mapper mapper) {
        dirAware = (DirectionAware)mapper;
    }
}

2)您需要创建 2 个全局推土机映射器对象,每个映射方向一个。它们应该配置相同的映射文件,但使用不同的方向参数。例如:

DirectionAwareDozerBeanMapper mapperFrom = DirectionAwareDozerBeanMapper(mappingFiles, Direction.FROM);
DirectionAwareDozerBeanMapper mapperTo = DirectionAwareDozerBeanMapper(mappingFiles, Direction.TO);

当然,您将需要使用适当的映射器(从/到)向自定义映射器提供有关您正在映射的方向的信息。

于 2014-06-09T07:52:08.293 回答
0

I got into same kind of issue after couple of years and somehow DozerConverter API which is a new API, still does not work properly as bi-direction !!

So, rather than getting into all these complex solutions advised here, I also created 2 one-way mapping to get over this issue(with ) . And then my conversions started working . I am using DozerConverter api like below :

public class MapToStringConverter extends DozerConverter

于 2016-03-28T18:26:01.350 回答