Announcement Announcement Module
Collapse
No announcement yet.
Spring mongodb cross store MappingExceptionCannot use a complex object as a key value Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring mongodb cross store MappingExceptionCannot use a complex object as a key value

    Can you please point me to where I am going wrong with spring mongodb cross store?

    18:41:55,094 DEBUG MongoChangeSetPersister:org.springframework.data.m ongodb.crossstore.MongoChangeSetPersister.persistS tate(MongoChangeSetPersister.java:153) - Flush: saving: { "_entity_id" : 958 , "_entity_class" : "com.vidzone.cmswarrior.domain.trevor.Package" , "_entity_field_name" : "test"}
    18:41:55,275 DEBUG MongoPersistentEntityIndexCreator:org.springframew ork.data.mongodb.core.index.MongoPersistentEntityI ndexCreator.checkForIndexes(MongoPersistentEntityI ndexCreator.java:98) - Analyzing class class org.apache.log4j.DefaultCategoryFactory for index information.
    FAILED CONFIGURATION: @AfterMethod springTestContextAfterTestMethod(public void com.vidzone.cmswarrior.service.integration.trevor. PackageServiceTest.testSave())
    org.springframework.data.mapping.model.MappingExce ption: Cannot use a complex object as a key value.
    at org.springframework.data.mongodb.core.convert.Mapp ingMongoConverter.writeMapInternal(MappingMongoCon verter.java:558)
    Code:
    dao.xml
    <!-- CMS Warrior Entity Manager Factory -->
    	<bean id="cmsWarriorEntityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    		p:persistenceUnitName="cmsWarriorPersistenceUnit" p:dataSource-ref="cmsWarriorDataSource"
    		p:jpaVendorAdapter-ref="jpaVendorAdapter" p:loadTimeWeaver-ref="loadTimeWeaver">
    	</bean>
    
    	<!-- CMS Warrior Transaction Manager -->
    	<bean id="cmsWarriorTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
    		p:entityManagerFactory-ref="cmsWarriorEntityManagerFactory" />
    
    	<!-- Package scanned for repository candidates -->
    	<jpa:repositories base-package="com.vidzone.cmswarrior.repository"
    		transaction-manager-ref="cmsWarriorTransactionManager"
    		entity-manager-factory-ref="cmsWarriorEntityManagerFactory"
    		factory-class="com.vidzone.common.repository.CustomRepositoryFactoryBean" />
    
    	<jpa:auditing set-dates="true" />
    
    	<!-- Enabled annotation based configuration -->
    	<context:annotation-config />
    
    	<!-- Enabled annotation based transaction management -->
    	<tx:annotation-driven mode="aspectj"
    		transaction-manager="cmsWarriorTransactionManager" />
    
    	<bean id="cmsWarriorStatisticsMBean" class="org.hibernate.jmx.StatisticsService"
    		p:statisticsEnabled="true" p:sessionFactory="#{cmsWarriorEntityManagerFactory.sessionFactory}" />
    
    	<!-- Mongo aspect config -->
    	<mongo:mapping-converter mongo-ref="mongo" mongo-template-ref="mongoTemplate"/>
    	<bean
    		class="org.springframework.data.mongodb.crossstore.MongoDocumentBacking"
    		factory-method="aspectOf" p:changeSetPersister-ref="mongoChangeSetPersister" />
    	<bean id="mongoChangeSetPersister"
    		class="org.springframework.data.mongodb.crossstore.MongoChangeSetPersister"
    		p:mongoTemplate-ref="mongoTemplate" p:entityManagerFactory-ref="cmsWarriorEntityManagerFactory" />
    Code:
    ds.xml
    	<!-- CMS Warrior data source -->
    	<bean id="cmsWarriorDataSource" class="org.apache.commons.dbcp.BasicDataSource"
    		destroy-method="close" p:username="${jdbc.username}" p:password="${jdbc.password}"
    		p:url="${jdbc.url}" p:poolPreparedStatements="${jdbc.poolPreparedStatements}"
    		p:initialSize="${jdbc.initialSize}" p:maxActive="${jdbc.maxActive}"
    		p:maxIdle="${jdbc.maxIdle}" p:validationQuery="select 1"
    		p:testWhileIdle="true" />
    
    	<!-- Mongo config -->
    	<mongo:db-factory host="localhost" port="27017"
    	dbname="armand-mongo" />
    	<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    		<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
    	</bean>
    	<bean class="org.springframework.data.mongodb.core.MongoExceptionTranslator" />
    Code:
    mappings
    @Entity
    @Table(name = "Package", schema = "Trevor")
    @Indexed
    @NamedNativeQuery(name = "getPackageById", query = "{call Trevor.Package_GetEntityById(:id)}", resultClass = Package.class)
    public class Package extends AbstractTimeAuditable<Integer> {
    
    	private static final long serialVersionUID = 2016484828200966769L;
    	@NotNull
    	@Size(min = 2, max = 255)
    	@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
    	@Column(name = "Name", nullable = false)
    	private String name;
    	@NotNull
    	@Digits(integer = 9, fraction = 0)
    	@Column(name = "CookieExpiryMinutes", nullable = false)
    	private Integer cookieExpiryMinutes;
    	@NotNull
    	@Digits(integer = 9, fraction = 0)
    	@Column(name = "CookieMaximumDailyViews")
    	private Integer cookieMaximumDailyViews;
    	@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
    	@JoinColumn(name = "CountryId", nullable = false)
    	private Country country;
    	@RelatedDocument
    	@Transient
    	private Country test; ...
    
    
    @Entity
    @Table(name = "Country", schema = "dbo")
    @AttributeOverrides({ @AttributeOverride(name = "id", column = @Column(name = "Id", columnDefinition = "TINYINT")) })
    public class Country extends AbstractPersistable<Integer> implements Comparable<Country> {
    
    	private static final long serialVersionUID = 6904187613247012582L;
    	@Column(name = "Country", nullable = false)
    	private String name;
    	@Column(name = "ISO3166TwoChar", columnDefinition = "char(2)")
    	private String isoCode2;
    	@Column(name = "ISO3166ThreeChar", columnDefinition = "char(3)")
    	private String isoCode3; ...

  • #2
    You're trying to persist a document that contains a map with complex keys. MongoDB only supports simple Strings as keys and alternatively mapping the map as { key : …, value : … } would significantly change the way querys have to be built etc.

    Beyond that Country probably should get a different ID type in case you're autogenerating IDs as the ObjectIDs generated by MongoDB do not fit into an Integer.

    Comment


    • #3
      I actually found that the problem was to write a custom converter for the Country type. It now works when I add this to the configuration:
      Code:
      	<mongo:mapping-converter>
      		<mongo:custom-converters>
      			<mongo:converter ref="countryReadConverter" />
      			<mongo:converter ref="countryWriteConverter" />
      		</mongo:custom-converters>
      	</mongo:mapping-converter>
      But if I use the base package scan for converters (as below) it does not register by custom converters.
      Code:
               <mongo:mapping-converter>
                       <mongo:custom-converters base-package="com.vidzone.cmswarrior.converter" /> 
              </mongo:mapping-converter>
      You would have any ideas why?

      Comment

      Working...
      X