2015-04-03 28 views
0

我試圖堅持以下文件:力彈簧數據MongoDB的讀取所有日期爲喬達DateTime類型

class Document { 
    ... 
    private Map data; 
    ... 
} 

存儲日期,我使用Joda的DateTime對象:

data.put("date", DateTime.now()); 

我我正在使用MongoRepository來保存數據。寫作效果很好,我可以看到mongoDB有一個日期類型。

但是,當我讀取數據時,我的地圖不包含DateTime,而是包含Date對象。

我明白了,沒有什麼可以告訴Spring來改變對象的類型從日期(默認)讀取,以日期時間,因爲我不是讀書的具體類型。

有沒有辦法告訴MongoTemplate/MongoRepository總是轉換成java.util.Date日期時間約達就是BEING讀的時候嗎?

這可能是與轉換器,但我一直沒能找到如何做到這一點的例子。

謝謝。 -AP_

+0

爲什麼你使用地圖而不是特定的嵌入類? – chrylis 2015-04-03 20:45:22

+0

我正在通過Jackson讀取數據,並且JSON對象的某些部分已定義好(時間戳,ID,類型),其他部分完全靈活。我需要能夠在MongoDB中讀取和存儲這個對象。最後,我想實現一個「混合」對象,它具有一些定義的字段和一些任意的字段,但還沒有得到這個。所以,我到目前爲止所有的地圖都包含了所有的字段。 – 2015-04-04 03:21:00

回答

0

您必須實現自己的轉換器,然後在啓用MongoDB存儲庫的類中覆蓋customConversions()@EnableMongoRepositories)。

這也取決於你使用的是春數據版本;到目前爲止,我還記得還有一個DateTimeConverters

它會像this,但實現Spring的Converter<T, K>接口。

2

所以,最後我不得不做出一點妥協。由於我使用Map來保存任意數據,因此無法調用轉換器,因爲任何對象都可以設置爲Object,因此Spring Data不需要進行從Date到DateTime的任何轉換。

而不是使用一個通用的地圖,我創建了自己的類型,其簡單地從地圖擴展:

public class EventData extends HashMap<String, Object> { 
    ... 
} 

然後,我改變了使用EVENTDATA我的父類,而不是地圖:

public class Event implements Serializable { 
    private final EventData 
     data; 

    ... 
} 

現在有EVENTDATA,我可以創建一個自定義的映射:

@ReadingConverter 
public class ConsumerHandlerEventDataReadConverter implements Converter<DBObject, EventData> { 

    @Resource 
    private MappingMongoConverter 
     mappingMongoConverter; 

    @Override 
    public EventData convert(final DBObject source) { 
     //First, use the general mapping mongo converter to read the source as it would normally be read 
     // 
     final EventData 
      eventData = 
       mappingMongoConverter 
        .read(
         EventData.class, 
         source 
        ); 

     //Now replaces all occurances of Date in EventData with DateTime 
     // 
     for (final Map.Entry<String, Object> entry : eventData.entrySet()) { 
      //Get the value of this entry 
      // 
      final Object 
       entryValue = 
        entry 
         .getValue(); 

      //If it's a date, replace with Datetime 
      // 
      if (entryValue instanceof Date) { 
       entry 
        .setValue(
         new DateTime(
          entryValue 
         ) 
        ); 
      } 
     } 

     //Return result 
     // 
     return 
      eventData; 
    } 
} 

大多數映射的是由標準映射器完成,因此我簡單地連接了一個「不同的」MappingMongoConverter並使用它的讀取方法來讀取數據。然後,我查找所有Date對象,並用DateTime替換它們。

要我轉換器加到蒙戈,我註冊自定義轉換輸入與MappingMongoConverter:

@Configuration 
public class ConsumerHandlerMongoDBConfiguration { 
    ... 
    @Bean 
    public CustomConversions customConversions() { 
     return 
      new CustomConversions(
       Arrays.asList(
        consumerHandlerEventDataReadConverter() 
       ) 
      ); 
    } 

    @Bean 
    @Description("Mapping mongo converter for the event") 
    public MappingMongoConverter consumerProcessHandlerMappingMongoConverter() { 
     final MappingMongoConverter 
      converter = 
       new MappingMongoConverter(
        mongoDBConfiguration.dbRefResolver(), 
        mongoDBConfiguration.mongoMappingContext() 
       ); 

     converter 
      .setTypeMapper(
       mongoDBConfiguration.mongoTypeMapper() 
      ); 

     converter 
      .setCustomConversions(
       customConversions() 
      ); 

     return 
      converter; 
    } 
    ... 
} 

理想情況下,我也希望以某種方式創建一個映射與一個Date類型打交道時MappingMongoConverter可以隨時諮詢沒有特別在EventData的上下文中,然而,看着readMap(...在Spring數據)的代碼,我看到這種情況不會發生:

private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) { 

    if (value == null || target == null || target.isAssignableFrom(value.getClass())) { 
     return value; 
    } 

    if (conversions.hasCustomReadTarget(value.getClass(), target)) { 
     return conversionService.convert(value, target); 
    } 

    if (Enum.class.isAssignableFrom(target)) { 
     return Enum.valueOf((Class<Enum>) target, value.toString()); 
    } 

    return conversionService.convert(value, target); 
} 

上面的代碼不會叫任何映射器如果target.isAssignableFrom(value.getClass()),並且因爲一切都可以分配給一個對象,有無論如何,只是無法註冊自定義映射器。代碼中的下一個語句確實檢查了是否轉換.hasCustomReadTarget,但我們從來沒有去過它。

無論如何,下次記錄這一點,以及任何正在嘗試做類似的轉換器的人。

-AP_

+0

這有效,但不完全。如果EventData包含一個包含另一個Map的Object,則該Map中的Date不會被轉換。此外,由於我在轉換器中使用了一個*不同的轉換器(沒有配置自定義轉換),因此不會應用嵌套轉換。如果我使用相同的映射器(註冊了轉換器),我將進入一個以堆棧溢出結束的無限循環。 所以,我真的希望簡單地,不分青紅皁白地將Date的任何實例更改爲DateTime。有沒有辦法用SpringData來做到這一點,我一直沒有找到? – 2015-04-13 18:48:27