2011-07-24 22 views
26

默認MappingMongoConverter向數據庫中的每個對象添加自定義類型鍵(「_class」)。所以,如果我創建了一個人:Spring數據MongoDb:MappingMongoConverter刪除_class

package my.dto; 
public class Person { 
    String name; 
    public Person(String name) { 
     this.name = name; 
    } 
} 

,並將其保存到數據庫:

MongoOperations ops = new MongoTemplate(new Mongo(), "users"); 
ops.insert(new Person("Joe")); 

在蒙戈生成的目標將是:

{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" } 

問題:

  1. 將Person類移入不同的命名空間有什麼含義?

  2. 是否有可能不用「_class」鍵污染對象;沒有爲Person類寫一個獨特的轉換器?

+0

那麼這個故事是怎麼回事呢?有沒有辦法阻止「_class」字段存儲在MongoDB中? – hodgesz

回答

20

所以這裏的故事:我們默認添加類型作爲某種提示什麼類實際實例化。你一定要管的類型的文件讀入通過MongoTemplate反正有兩個可能的選擇:

  1. 你的手在類型上實際存儲的類型可以被分配到。在這種情況下,我們考慮存儲類型,將其用於對象創建。這裏的典型例子是做多態查詢。假設你有一個抽象類Contact和你的Person。然後,您可以查詢Contact s,我們基本上必須確定要實例化的類型。
  2. 如果你 - 另一方面 - 傳入一個完全不同的類型,我們只是編入該給定類型,而不是實際存儲在文檔中。這將涵蓋你的問題,如果你移動類型會發生什麼。

您可能有興趣觀看this ticket,它涵蓋了某種可插入類型映射策略,將類型信息轉換爲實際類型。這可以用於簡單節省空間的目的,因爲您可能想要將長合格的類名稱減少爲幾個字母的散列。它還可以實現更復雜的遷移場景,您可能會發現其他數據存儲客戶端生成的完全任意類型的鍵並將其綁定到Java類型。

+0

謝謝你的回答。將類型提取到配置是否有意義?而不是保持與對象?例如,要在代碼中提供映射:('converter.configure(Contact.class,Person.class)')。 –

+0

奧利弗,有沒有簡單的方法來刪除1.0GA中的_class? [This](http://forum.springsource.org/showthread.php?112505-Spring-data-MongoDb-MappingMongoConverter-remove-_class)現在不起作用。看起來最簡單的方法是:((MappingMongoConverter)template.getConverter())。setTypeMapper(new DefaultMongoTypeMapper(null));'。但這是醜陋的和錯誤的... – Shcheklein

+1

你的意思是'不起作用'是什麼意思?如果您通過代碼或XML配置預先正確配置'MappingMongoConverter',則無需執行投射作業。 –

14

這是我的註釋,它的工作原理。

@Configuration 
public class AppMongoConfig { 

    public @Bean 
    MongoDbFactory mongoDbFactory() throws Exception { 
     return new SimpleMongoDbFactory(new Mongo(), "databasename"); 
    } 

    public @Bean 
    MongoTemplate mongoTemplate() throws Exception { 

     //remove _class 
     MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()); 
     converter.setTypeMapper(new DefaultMongoTypeMapper(null)); 

     MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter); 

     return mongoTemplate; 

    } 

} 
+0

這裏有一個警告:此代碼刪除每個類型的轉換代碼。例如,Spring Data不再能夠轉換(和存儲)LocalDate屬性。 – ChrLipp

+0

@mkyong,不推薦使用您的代碼片段。已添加工作答案,刪除棄用警告。你介意更新你的答案在這裏,以及在你的博客[這裏](https://www.mkyong.com/mongodb/spring-data-mongodb-remove-_class-column/)。謝謝 – harshavmb

4
<mongo:mongo host="hostname" port="27017"> 
<mongo:options 
...options... 
</mongo:mongo> 
<mongo:db-factory dbname="databasename" username="user" password="pass"      mongo-ref="mongo"/> 
<bean id="mongoTypeMapper"  class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper"> 
<constructor-arg name="typeKey"><null/></constructor-arg> 
</bean> 
<bean id="mongoMappingContext"  class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" /> 
<bean id="mongoConverter"  class="org.springframework.data.mongodb.core.convert.MappingMongoConverter"> 
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> 
<constructor-arg name="mappingContext" ref="mongoMappingContext" /> 
<property name="typeMapper" ref="mongoTypeMapper"></property> 
</bean> 
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> 
<constructor-arg name="mongoConverter" ref="mongoConverter" /> 
<property name="writeResultChecking" value="EXCEPTION" /> 
</bean> 
3

如果要禁用默認_class屬性,但保留polymorfism指定類,你可以顯式地通過configuing定義_class(可選)字段的類型:

@Bean 
public MongoTemplate mongoTemplate() throws Exception { 
    Map<Class<?>, String> typeMapperMap = new HashMap<>(); 
    typeMapperMap.put(com.acme.domain.SomeDocument.class, "role"); 

    TypeInformationMapper typeMapper1 = new ConfigurableTypeInformationMapper(typeMapperMap); 

    MongoTypeMapper typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(typeMapper1)); 
    MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()); 
    converter.setTypeMapper(typeMapper); 

    MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter); 
    return mongoTemplate; 
} 

這將只保留_class字段(或任何你想要在建築師名字中)的指定實體。

您也可以基於註釋編寫自己的TypeInformationMapper。如果你用@DocumentType("aliasName")註釋你的文檔,你將保持多態性,保持類的別名。

I have explained briefly it on my blog,但這裏是一些一段簡單的代碼: https://gist.github.com/athlan/6497c74cc515131e1336

1

我掙扎了很久這個問題。我跟着從mkyong的方法,但是當我介紹了LocalDate屬性(任何JSR310類從Java 8)我收到以下異常:

org.springframework.core.convert.ConverterNotFoundException: 
No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date] 

對應的轉換器org.springframework.format.datetime.standard.DateTimeConverters是彈簧4.1的一部分,並在春季數據MongoDB的被引用1.7。即使我使用新版本的轉換器沒有在跳

的解決方案是利用現有的MappingMongoConverter,只提供了一個新的DefaultMongoTypeMapper(從mkyong代碼正在評論):

@Configuration 
@EnableMongoRepositories 
class BatchInfrastructureConfig extends AbstractMongoConfiguration 
{ 
    @Override 
    protected String getDatabaseName() { 
     return "yourdb" 
    } 

    @Override 
    Mongo mongo() throws Exception { 
     new Mongo() 
    } 

    @Bean MongoTemplate mongoTemplate() 
    { 
     // overwrite type mapper to get rid of the _class column 
//  get the converter from the base class instead of creating it 
//  def converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()) 
     def converter = mappingMongoConverter() 
     converter.typeMapper = new DefaultMongoTypeMapper(null) 

     // create & return template 
     new MongoTemplate(mongoDbFactory(), converter) 
    } 

要總結:

  • 延伸AbstractMongoConfiguration
  • 註釋與EnableMongoRepositories
  • 從基類mongoTemplate GET轉換器,這確保了類型轉換的類被註冊
1

這是我的一個在線解決方案:

@Bean 
public MongoTemplate mongoTemplateFraud() throws UnknownHostException { 

    MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName); 
    ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class 
    return mongoTemplate; 
} 
1

雖然,Mkyong的回答仍然有效,我想補充我的解決方案版本很少被棄用,並且可能處於清理的邊緣。

例如:MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())已棄用new MappingMongoConverter(dbRefResolver, new MongoMappingContext());SimpleMongoDbFactory(new Mongo(), "databasename");,贊成new SimpleMongoDbFactory(new MongoClient(), database);

所以,沒有廢棄警告我的最終工作的答案是:

@Configuration 
public class SpringMongoConfig { 

    @Value("${spring.data.mongodb.database}") 
    private String database; 

    @Autowired 
    private MongoDbFactory mongoDbFactory; 

    public @Bean MongoDbFactory mongoDBFactory() throws Exception { 
     return new SimpleMongoDbFactory(new MongoClient(), database); 
    } 

    public @Bean MongoTemplate mongoTemplate() throws Exception { 

     DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory); 

     // Remove _class 
     MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext()); 
     converter.setTypeMapper(new DefaultMongoTypeMapper(null)); 

     return new MongoTemplate(mongoDBFactory(), converter); 

    } 

} 

希望這有助於人們希望有一個乾淨的類沒有廢棄警告誰。