I am trying to test my repository layer using Spring Boot 2.0.1 but when I run my test class, Spring tries to instantiate a Config class not from the test package.
Here is the test code:
TestConfig.class
#Configuration
#Import(value = {TestDatabaseConfig.class})
#Profile("local")
public class TestConfig {
}
TestDatabaseConfig.class
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "logEntityManagerFactory",
transactionManagerRef = "logTransactionManager",
basePackages = { "it.xxx.yyy.repository.log" })
#EntityScan(basePackages = {"it.xxx.yyy.model.log", "it.xxx.yyy.common"})
#Profile("local")
public class TestDatabaseConfig {
#Bean("logDataSourceProperties")
public DataSourceProperties logDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "logDataSource")
public DataSource dataSource(#Qualifier("logDataSourceProperties") DataSourceProperties properties) {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.build();
}
#Bean(name = "logEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean logEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("logDataSource") DataSource logDataSource) {
return builder.dataSource(logDataSource)
.packages("it.xxx.model.log")
.persistenceUnit("log")
.build();
}
#Bean(name = "logTransactionManager")
public PlatformTransactionManager logTransactionManager(#Qualifier("logEntityManagerFactory")EntityManagerFactory logEntityManagerFactory) {
return new JpaTransactionManager(logEntityManagerFactory);
}
}
When I run this class
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("local")
public class LogRepositoryTest {
#Autowired
private ResultLogRepository resultLogRepository;
#Test
public void init(){
}
}
it says :
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kafkaProducer': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'kafka.topic.operation' in value "${kafka.topic.operation}"
[...]
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'kafka.topic.operation' in value "${kafka.topic.operation}"
But I cannot understand why it brings up my KafkaProducer.class from my main package (that has #Configuration annotation on it).
In your LogRepositoryTest test class you should indicate the alternate test configuration class that should be taken into account, in your case I think should be the TestConfig.
From Spring Boot documentation:
If you are familiar with the Spring Test Framework, you may be used to using #ContextConfiguration(classes=…) in order to specify which Spring #Configuration to load. Alternatively, you might have often used nested #Configuration classes within your test.
So annotate LogRepositoryTest with #ContextConfiguration(classes = {TestConfig.class})
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("local")
#ContextConfiguration(classes = {TestConfig.class})
public class LogRepositoryTest {
#Autowired
private ResultLogRepository resultLogRepository;
#Test
public void init(){
}
}
UPDATE
Also annotate your configuration class with:
#EnableAutoConfiguration
Something like:
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "logEntityManagerFactory",
transactionManagerRef = "logTransactionManager",
basePackages = { "it.xxx.yyy.repository.log" })
#EntityScan(basePackages = {"it.xxx.yyy.model.log", "it.xxx.yyy.common"})
#Profile("local")
public class TestDatabaseConfig {
//...
}
UPDATE 2
For error:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.jdbc.DataSourceProperties' available: expected single matching bean but found 2: logDataSourceProperties,spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
Completely remove the method:
#Bean("logDataSourceProperties")
public DataSourceProperties logDataSourceProperties() {
return new DataSourceProperties();
}
and change your:
#Bean(name = "logDataSource")
public DataSource dataSource(#Qualifier("logDataSourceProperties") DataSourceProperties properties) {
// ...
}
to:
#Bean(name = "logDataSource")
public DataSource dataSource(DataSourceProperties properties) {
// ...
}
Related
I have added an additional datasource in Spring batch project.
When I am trying to run the job locally its running successfully I am having issue on running Integration testcases.
I have data.sql script which inserting data into table. It does not have any sql script to create table as I have added in test properties "spring.jpa.hibernate.ddl-auto=create-drop"
test/resources/application.properties
first.datasource.jdbc-url=jdbc:h2:mem:testdb
first.datasource.driverClassName=org.h2.Driver
first.datasource.username=username
first.datasource.password=password
first.datasource.hikari.connectionTimeout=400000
first.datasource.hikari.maximum-pool-size=600000
first.datasource.hikari.minimum-idle=5
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.jdbc.batch_size=10
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.batch_versioned_data=true
spring.batch.initialize-schema=always
spring.batch.job.enabled=false
second.datasource.jdbc-url=jdbc:h2:mem:testdb
second.datasource.driverClassName=org.h2.Driver
second.datasource.username=username
second.datasource.password=password
second.datasource.hikari.connectionTimeout=400000
second.datasource.hikari.maximum-pool-size=600000
second.datasource.hikari.minimum-idle=5
Configuration file for first Datasource is
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "firstappEntityManagerFactory",
transactionManagerRef = "firstappTransactionManager",
basePackages = "com.app.repository"
)
#EnableTransactionManagement
public class firsDataSourceDBConfig {
#Bean(name="firstappDataSource")
#Primary
#ConfigurationProperties(prefix = "first.datasource")
public DataSource appDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "firstappEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean appEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("firstappDataSource") DataSource appDataSource){
return builder
.dataSource(appDataSource)
.packages("com.app.domain")
.persistenceUnit("firstUnit")
.build();
}
#Bean(name = "firstappTransactionManager")
#Primary
public PlatformTransactionManager appTransactionManager(#Qualifier("firstappEntityManagerFactory") EntityManagerFactory
appEntityManagerFactory) {
return new JpaTransactionManager(appEntityManagerFactory);
}
#Bean
public BatchConfigurer configurer(#Qualifier("firstappEntityManagerFactory") EntityManagerFactory appEntityManagerFactory) {
return new JpaTransactionManager(appEntityManagerFactory);
}
}
Second one is without BatchConfigurer beans
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "secondappEntityManagerFactory",
transactionManagerRef = "secondappTransactionManager",
basePackages = "com.abc.repository"
)
#EnableTransactionManagement
public class firsDataSourceDBConfig {
#Bean(name="secondappDataSource")
#Primary
#ConfigurationProperties(prefix = "second.datasource")
public DataSource appDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "secondappEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean appEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("secondappDataSource") DataSource appDataSource){
return builder
.dataSource(appDataSource)
.packages("com.app.domain")
.persistenceUnit("secondUnit")
.build();
}
#Bean(name = "secondappTransactionManager")
#Primary
public PlatformTransactionManager appTransactionManager(#Qualifier("secondappEntityManagerFactory") EntityManagerFactory
appEntityManagerFactory) {
return new JpaTransactionManager(appEntityManagerFactory);
}
}
}
Files with annotation #DataJpaTest are running successfully
#RunWith(SpringRunner.class)
#DataJpaTest
public class RepositoryTest {
#Autowired
private FirstDataSourceRepository repo;
..........
}
Test cases which are annotated with #SpringBootTest are failing
#RunWith(SpringRunner.class)
#SpringBootTest
#DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class SpringBatchIntegrationTest {
#Autowired
private FirstDataSourceRepository repo;
..........
}
Error stating BeanCreation Exception
firstappEntityManagerFactory.....org.h2.jdbc.JdbcSQLException: Table "TESTING" not found
I have multiple database connections with named EntityManagers:
#Bean(name = "integDB")
#Primary
#ConfigurationProperties(prefix="spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "integEM")
public LocalContainerEntityManagerFactoryBean integDbEntityManagerFactory(EntityManagerFactoryBuilder builder) {
....
}
How do I specify which entity manager to use here?
#Repository
public interface IntControleFilaRepository extends JpaRepository<IntControleFilaEntity, String> {
}
Spring is complaining about it:
Parameter 0 of constructor in ... required a bean named 'entityManagerFactory' that could not be found.
Create a configuration class for each database and specify the entityManager associated with each one:
#Configuration
#EnableJpaRepositories(basePackages = {"..."}, entityManagerFactoryRef = "integEM", transactionManagerRef = "integTM")
public class IntegReposConfig {
}
Despite some fairly clear examples, I'm failing to get a manual configuration of a spring boot application to work. I usually allow it to configure right from the application.properties file but the requirement demands that I use multiple data sources. And, yes, I have tried to recreate the Baeldung example (https://www.baeldung.com/spring-data-jpa-multiple-databases) as recommended by the posts I've seen here. Here is my config:
#Configuration
#EnableJpaRepositories(basePackages = "com.ezcorp.costumerrefresh.db.sqlserver", entityManagerFactoryRef = "sqlserverEntityManagerFactory", transactionManagerRef = "sqlserverTransactionManager")
#EnableTransactionManagement
public class SqlServerConfig {
#Bean(name="sqlserverDataSource")
#ConfigurationProperties(prefix = "spring.datasource")
#Primary
public DataSource sqlserverDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
dataSource.setUrl("jdbc:sqlserver://aswn-tbd-db01:1433;databaseName=DE_RTDS");
dataSource.setUsername("cs_user");
dataSource.setPassword("cs_user");
return dataSource;
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean sqlserverEntityManagerFactory(final EntityManagerFactoryBuilder builder) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.SQLServer2008Dialect");
return builder
.dataSource(sqlserverDataSource())
.properties(properties)
.packages("com.ezcorp.costumerrefresh.domain.sqlserver")
.persistenceUnit("adminPersistenceUnit")
.build();
}
#Bean
#Primary
public JpaTransactionManager sqlserverTransactionManager(#Qualifier("sqlserverEntityManagerFactory") final EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}
Service:
#Service
public class CustomerRefreshService {
#Autowired
private ExistingLoanModelDataRepository existingLoanModelDataRepository;
public void execute() {
System.out.println("show me");
}
}
Repository:
#Repository
public interface ExistingLoanModelDataRepository extends CrudRepository<ExistingLoanModelData, Long> {
ExistingLoanModelData findByCustomerId(Long customerId);
}
error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.ezcorp.customerrefresh.db.sqlserver.ExistingLoanModelDataRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
...
What am I doing wrong? This is about as straight-forward as it gets. I've eliminated the other (mongo) config setup to simplify. This has to be an obvious one...just not to me :-)
Looks like a typo.
#EnableJpaRepositories(basePackages = "com.ezcorp.costumerrefresh.db.sqlserver", entityManagerFactoryRef = "sqlserverEntityManagerFactory", transactionManagerRef = "sqlserverTransactionManager")
I am researching on usage of Spring Data JPA. Appreciated if can help check where is wrong.
I created 2 JPA repositories: APIRepository and ClientRepository in 2 different packages and also created 2 configuration classes to configure these 2 repositories using #EnableJpaRepositories annotation respectively.
When a Spring application calls these 2 repositories' save() methods at the same time, the APIRepository.save() will fail, but without exception. If move #Primiary annotation (this is to avoid NoUniqueBeanDefinitionException) to APIAppConfig class, ClientRepository.save will fail without exception. I opened SQL log, no update SQL was executed for failing method.
did anyone hit such a situation? how to use Spring Data Jpa?
APIRepository
package test.api;
public interface APIRepository extends Repository<API, Long>{
....
}
APIAppConfig
package test.api;
#Configuration
#ComponentScan(basePackages = "test.api")
#EnableJpaRepositories(
basePackages = "test.api.repository",
entityManagerFactoryRef = "apiEntityManagerFactory",
transactionManagerRef="apiTransactionManager",
enableDefaultTransactions=true
)
#EnableTransactionManagement
public class APIAppConfig {
#Bean
public LocalContainerEntityManagerFactoryBean apiEntityManagerFactory(){
...
}
#Bean
public PlatformTransactionManager apiTransactionManager() {
...
}
#Bean
public DataSource apiDataSource() {
...
}
}
APIService
package test.api;
#Service
public class APIService {
#Autowired
private APIRepository apiRepository;
public API findOne(Long id){
return apiRepository.findOne(id);
}
#Transactional("apiTransactionManager")
public void updateOne(API api){
apiRepository.save(api);
}
}
ClientRepository
package test.client;
public interface ClientRepository extends Repository<Client, Long>{
...
}
ClientAppConfig
package test.client;
#Configuration
#ComponentScan(basePackages = "test.client")
#EnableJpaRepositories(
basePackages = "test.client",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef="transactionManager",
enableDefaultTransactions=true
)
#EnableTransactionManagement
public class ClientAppConfig {
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
...
}
#Bean
public PlatformTransactionManager transactionManager() {
...
}
#Bean
#Primary
public DataSource dataSource() {
...
}
}
ClientService
package test.client;
#Service
public class ClientService {
#Autowired
private ClientRepository clientRepository;
public DaoTest findOne(Long id){
return clientRepository.findOne(id);
}
#Transactional("transactionManager")
public void updateOne(Client client){
clientRepository.save(client);
}
}
In your APIAppConfig class you have set
#EnableJpaRepositories(
basePackages = "test.api.repository",
But your APIRepository is in the package test.api and not in test.api.repository, at least as I can see in your APIRepository class source code.
So either change the basePackages value to reflect the correct one, or move your APIRepository inside the test.api.repository package
I have switched my application to use two data sources, the code runs fine and both are picked up, however my unit tests have started to fail, code is below, help much appreciated.
Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.getDriverClassName(DataSourceProperties.java:180)
at org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$NonEmbeddedConfiguration.dataSource(DataSourceAutoConfiguration.java:120)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 71 more
application.properties (in main and in test folders):
datasource.primary.url = <url>
datasource.primary.username = <user>
datasource.primary.password = <password>
datasource.secondary.url = <url>
datasource.secondary.username = <user>
datasource.secondary.password = <pass>
Main program:
#EnableAutoConfiguration
#Configuration
#EntityScan({"com.example.domain","com.example.common.domain"})
#PropertySource(value = "classpath:application.properties")
#EnableScheduling
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Primary Data source config:
#Configuration
#EnableJpaRepositories(basePackages = "com.example.repository",
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager")
#EnableTransactionManagement
public class PrimaryConfiguration {
#Bean
#ConfigurationProperties(prefix = "datasource.primary")
#Primary
public DataSource primaryDataSource()
{
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(final EntityManagerFactoryBuilder builder)
{
return builder
.dataSource(primaryDataSource())
.packages("uk.gov.dwp.pss.roc.domain")
.persistenceUnit("primaryPersistenceUnit")
.build();
}
#Bean
#Primary
public JpaTransactionManager primaryTransactionManager(#Qualifier("primaryEntityManagerFactory") final EntityManagerFactory factory)
{
return new JpaTransactionManager(factory);
}
}
Secondary config class:
#Configuration
#EnableJpaRepositories(basePackages = "com.example.common.repository",
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager")
#EnableTransactionManagement
public class SecondaryConfiguration {
#Bean
#ConfigurationProperties(prefix = "datasource.secondary")
public DataSource secondaryDataSource()
{
return DataSourceBuilder.create().build();
}
#Bean
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(final EntityManagerFactoryBuilder builder)
{
return builder
.dataSource(secondaryDataSource())
.packages("uk.gov.dwp.pss.commons.domain.security")
.persistenceUnit("secondaryPersistenceUnit")
.build();
}
#Bean
public JpaTransactionManager secondaryTransactionManager(#Qualifier("secondaryEntityManagerFactory") final EntityManagerFactory factory)
{
return new JpaTransactionManager(factory);
}
}
Repository class:
public interface MyRepository extends JpaRepository<MyObject, String>,JpaSpecificationExecutor<MyObject> {
}
Unit test class use annotation:
#SpringApplicationConfiguration(classes = MyApplication.class)
A database driver was not found on the classpath for the AutoConfiguration to setup while running your test cases.
As #ndrone stated you need to set your database driver. It is unclear if you are attempting to use AutoConfigureTestDatabase. If so you should reference AutoConfigureTestDatabase from the Spring Boot docs.
If this is the case you could specify the Embedded database to use by using the following in your test (configuration):
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
Otherwise, you could modify your application.properties in your test folder to specify the connection type such as:
datasource.primary.driver-class-name=org.h2.Driver
datasource.secondary.driver-class-name=org.h2.Driver