簡體   English   中英

不能使用自定義轉換器進行推土機雙向映射(字符串,字符串)?

[英]Dozer bidirectional mapping (String, String) with custom comverter impossible?

我有一個帶有自定義轉換器的推土機映射:

<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;
    }
}

當我沿一個方向(客戶-> CustomerDAO)調用映射器時,將調用方法“ convertTo”。

由於Dozer能夠處理雙向映射,因此我希望,一旦我以相反的方向調用映射器,就會調用方法“ convertFrom”。

但是永遠不會調用convertTo方法。

我懷疑問題在於,這兩種類型都是Strings-但是如何使這項工作有效?

解決方法是創建兩個單向映射,這是標准解決方案,還是行為錯誤?

是的,問題在於您的源類和目標類是相同的。 這是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() + ")!");
    }

  }

不必使用convertFromconvertTo方法(它們是新API的一部分),而是必須按照本教程中所示的那樣實現CustomConverter.convert的原始方法。

我遇到了同樣的問題,目前(從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用作兩個參數,作為dozer映射文件中的自定義轉換器。 此類轉換器的實現應擴展: DozerConverter<String,String>並實現MapperAware接口。 這一點很重要,因為您可以使用MapperAware ,因為有了Mapper,您就可以將其投射到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個全局Dozer映射器對象,每個映射方向一個。 應該為它們配置相同的映射文件,但使用不同的direction參數。 例如:

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

當然,您將需要使用正確的映射器(從/到)以向自定義映射器提供有關映射方向的信息。

幾年后,我遇到了同樣的問題,以某種方式,作為新API的DozerConverter API仍然不能作為雙向正常工作!

因此,我沒有創建這里建議的所有這些復雜解決方案,而是創建了2個單向映射來解決此問題(使用)。 然后我的轉換開始工作。 我正在使用DozerConverter api,如下所示:

公共類MapToStringConverter擴展了DozerConverter

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM