sissythem
sissythem

Reputation: 831

Define two datasources with Hibernate - One relational and one NoSQL

In our project we have two databases: one relational (ms sql server) and one NoSQL (MongoDB). When I start the project I get this error:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appServiceRepository': Cannot create inner bean '(inner bean)#2f5abe7' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#2f5abe7': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in eu.voiceweb.config.DatabaseConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'entityManagerFactory' threw exception; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: java.util.List, at table: Rule, for columns: [org.hibernate.mapping.Column(filledSlots)]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:327) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:131) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1681) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1433) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1248) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1168) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    ... 141 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#2f5abe7': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in eu.voiceweb.config.DatabaseConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'entityManagerFactory' threw exception; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: java.util.List, at table: Rule, for columns: [org.hibernate.mapping.Column(filledSlots)]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:662) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:479) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:312) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    ... 154 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in eu.voiceweb.config.DatabaseConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'entityManagerFactory' threw exception; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: java.util.List, at table: Rule, for columns: [org.hibernate.mapping.Column(filledSlots)]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    ... 162 common frames omitted

AppServiceService uses a repository from the Relational database, while the Rule and FilledSlots objects are in the MongoDB database. I suspect that we are missing something in the configuration of the two databases.

The configuration for the relational database is the below:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = Constants.PERSISTENCE_PACKAGE)
public class DatabaseConfig {

    @Value("${jdbc.jndi.url}")
    private String jndiUrl;

    @Value("${application.database}")
    private String database;

    @Bean(name = Constants.DATASOURCE)
    @Primary
    public DataSource dataSource() {
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        dsLookup.setResourceRef(true);
        return dsLookup.getDataSource(jndiUrl);
    }

    @Bean(name = Constants.ENTITY_MANAGER_FACTORY)
    @Primary
    public EntityManagerFactory entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabase(Database.valueOf(database));
        vendorAdapter.setGenerateDdl(true);
        if (database.equalsIgnoreCase(Constants.SQL_SERVER)) {
            vendorAdapter.setDatabasePlatform(Constants.HIBERNATE_SQL_SERVER_DIALECT);
        } else if (database.equalsIgnoreCase(Constants.ORACLE)) {
            vendorAdapter.setDatabasePlatform(Constants.HIBERNATE_ORACLE_DIALECT);
        }
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan(Constants.PERSISTENCE_PACKAGE);
        factory.setDataSource(dataSource());
        factory.setJpaDialect(new HibernateJpaDialect());

        Map<String, Object> properties = factory.getJpaPropertyMap();
        properties.put(Constants.HIBERNATE_NAMING_STRATEGY, NamingConfig.class.getName());
        properties.put(Constants.HIBERNATE_ENTITY_MANAGER_FACTORY_NAME, Constants.ENTITY_MANAGER_FACTORY);
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    @Bean(name = Constants.TRANSACTION_MANAGER)
    @Primary
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        return txManager;
    }

    @Bean(name = Constants.ENTITY_MANAGER)
    @Primary
    public EntityManager entityManager() {
        EntityManagerFactory entityManagerFactory = entityManagerFactory();
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        return entityManager;
    }
}

The configuration for MongoDB:

@Configuration
@EnableMongoRepositories(basePackages = Constants.PERSISTENCE_PACKAGE)
@ComponentScan(basePackages = Constants.VOICEWEB_PACKAGE,
        excludeFilters =
                {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class),
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = ControllerAdvice.class)})
public class MongoConfig extends AbstractMongoConfiguration{

    @Value("${application.mongo.host}")
    private String mongoHost;

    @Value("${application.mongo.port}")
    private String mongoPort;

    @Value("${application.mongo.database}")
    private String mongoDatabase;

    @Override
    protected String getDatabaseName() {
        return mongoDatabase;
    }

    @Bean
    @Override
    public MongoClient mongoClient() {
        return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
    }

    @Bean(name="mongoDbFactory")
    public MongoDbFactory mongoDbFactory() {
        return new SimpleMongoDbFactory(this.mongoClient(), this.getDatabaseName());
    }

    @Bean(name="mongoTemplate")
    public MongoTemplate mongoTemplate() {
        return new MongoTemplate(mongoClient(), mongoDatabase);
    }

    @Bean
    @Override
    public MappingMongoConverter mappingMongoConverter() throws Exception {
        MappingMongoConverter mmc = super.mappingMongoConverter();
        mmc.setTypeMapper(customTypeMapper());
        return mmc;
    }

    @Bean
    public MongoTypeMapper customTypeMapper() {
        return new CustomMongoTypeMapper();
    }

}

I noticed that in MongoDB, there is no datasource but instantiates the MongoClient using the host and the port. Is there a way to define in Hibernate that MongoDB is a different datasource?

EDIT

The Rule Entity:

@Document(collection = Constants.RULES )
@Entity
public class Rule extends AbstractMongoEntity {

    @DBRef
    private Intention intention;

    @DBRef
    private List<FilledSlot> filledSlots = new ArrayList<>();

    @DBRef
    private Segment segment;

    @DBRef
    private Task task;


    public Rule() {
    }

    public Rule(Intention intention, List<FilledSlot> filledSlots, Segment segment, Task task) {
        this.intention = intention;
        this.filledSlots = filledSlots;
        this.segment = segment;
        this.task = task;
    }

    public Rule(String id, Intention intention, List<FilledSlot> filledSlots, Segment segment, Task task) {
        this._id = id;
        this.intention = intention;
        this.filledSlots = filledSlots;
        this.segment = segment;
        this.task = task;
    }

    public Intention getIntention() {
        return intention;
    }

    public void setIntention(Intention intention) {
        this.intention = intention;
    }


    public List<FilledSlot> getFilledSlots() {
        return filledSlots;
    }

    public void setFilledSlots(List<FilledSlot> filledSlots) {
        this.filledSlots = filledSlots;
    }

    public Segment getSegment() {
        return segment;
    }

    public void setSegment(Segment segment) {
        this.segment = segment;
    }

    public Task getTask() {
        return task;
    }

    public void setTask(Task task) {
        this.task = task;
    }

    @Override
    public String toString() {
        return "Rule{" +
                "intention=" + intention +
                ", filledSlots=" + filledSlots +
                ", segment=" + segment +
                ", task=" + task +
                ", id='" + _id + '\'' +
                '}';
    }
}

and the FilledSlot entity:

@Document(collection = Constants.SLOTS)
@Entity
public class FilledSlot extends AbstractMongoEntity {

    private String slotKey;
    private String slotValue;

    public FilledSlot(){
    }

    @PersistenceConstructor
    public FilledSlot(String slotKey, String slotValue){
        setSlotKey(slotKey);
        setSlotValue(slotValue);
    }

    public String getSlotKey() {
        return slotKey;
    }

    public void setSlotKey(String slotKey) {
        this.slotKey = slotKey;
    }

    public String getSlotValue() {
        return slotValue;
    }

    public void setSlotValue(String slotValue) {
        this.slotValue = slotValue;
    }

    @Override
    public String toString() {
        return "FilledSlot{" +
                "slotKey='" + slotKey + '\'' +
                ", slotValue='" + slotValue + '\'' +
                ", _id='" + _id + '\'' +
                '}';
    }
}

Upvotes: 2

Views: 182

Answers (1)

sissythem
sissythem

Reputation: 831

The entities of the relational datasource was in a different jar file from those of MongoDB. The problem was that the persistence package of both configurations was the same, so by changing the persistence package in mongo db configuration the problem was solved

Upvotes: 2

Related Questions