2011-02-18 27 views
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; 
    } 
} 

當我打電話在一個方向映射器(客戶 - > CustomerDAO)的製造方法「的ConvertTo」是調用。

由於Dozer能夠處理雙向映射,我預計,只要我在相反方向調用映射器,方法'convertFrom'將被調用。

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

我懷疑問題是,這兩種類型都是字符串 - 但我怎麼能做到這一點?

作爲一種解決方法,我創建了兩個單向映射,這是標準解決方案還是行爲錯誤?

回答

2

是的,問題是你的源和目標類是相同的。這裏是推土機sourceDozerConverter

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的一部分),做原始的方式,你有如圖所示tutorial實施CustomConverter.convert的。

+3

我有新的API相同的問題。我不知道映射器是否會調用convertTo()或convertFrom()。較舊的API不起作用,因爲我仍然無法區分映射的工作方向。我將從String轉換爲String。簡單的映射,我需要將數據庫代碼映射到用戶可讀的值。如果任何人有處理這一點將讚賞反饋。謝謝 – 2011-10-28 17:08:01

0

我有同樣的問題,目前(如推土機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)時,在這個dozer映射文件中使用這個類型的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); 

當然,你需要使用適當的映射器(自/至)向哪個方向你映射的自定義映射器提供的信息中。

0

幾年後我又遇到了同樣的問題,不知何故DozerConverter API是一個新的API,仍然無法正常工作作爲雙向!

因此,我並沒有深入到這裏建議的所有這些複雜解決方案中,而是創建了2個單向映射來解決此問題。然後我的轉換開始工作。我使用DozerConverter API象下面這樣:

公共類MapToStringConverter擴展DozerConverter