SpringBoot don't create datasource from yml config - java

In application.yml I defined datasource:
spring:
datasource:
driver-class-name: ru.yandex.clickhouse.ClickHouseDriver
username: default
url: jdbc:clickhouse://localhost:8123/default
I too create some config:
#Configuration
#AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyConfig {
#Getter
private ReportRoutingDataSource dataSourceStorage = new ReportRoutingDataSource();
#Bean("dataSourceStorage")
public DataSource dataSource(#Qualifier("dataSource") DataSource dataSource) {
dataSourceStorage.setDefaultTargetDataSource(dataSource);
dataSourceStorage.setTargetDataSources(resolvedDataSources());
dataSourceStorage.afterPropertiesSet();
return dataSourceStorage;
}
#Bean
public Map<Object, Object> resolvedDataSources() {
//some another logic;
}
}
ReportRoutingDataSource:
public class ReportRoutingDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return RequestContext.getKeyToChoseDataSource();
}
}
I want use auto-configuration to create a default datasource from a yml file and add it to dataSourceStorage.setDefaultTargetDataSource(dataSource) as default datasource.
I set annotation #AutoConfigureAfter(DataSourceAutoConfiguration.class), that my config is created after autoconfiguration of the standard datasource.
But, whent I start my app, I have error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceStorage' defined in class path resource [com/example/spring/MyConfig.class]: Unsatisfied dependency expressed through method 'dataSource' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value=dataSource)}
But, why? How can I fix it?

Replace your 'dataSource' method with
#Bean("dataSourceStorage")
public ReportRoutingDataSource reportRoutingDataSource (#Autowired("dataSource") DataSource dataSource) {
ReportRoutingDataSource dataSourceStorage = new ReportRoutingDataSource();
dataSourceStorage.setDefaultTargetDataSource(dataSource);
dataSourceStorage.setTargetDataSources(resolvedDataSources());
dataSourceStorage.afterPropertiesSet();
return dataSourceStorage;
}
and get rid of the #Getter for ReportRoutingDataSource.

Related

Spring Boot Defining A Bean

I have this funny error, I say it is funny because my project was working and it just crashed.
I believe I have implemented everything I was supposed to implement to achieve the multi data source.
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'quoteController' defined in file [C:\Users\S4\Desktop\S4Projects\wirk-devserv-intranet\source\back-end\target\classes\com\api\controllers\QuoteController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'quoteServiceImpl' defined in file [C:\Users\S4\Desktop\S4Projects\wirk-devserv-intranet\source\back-end\target\classes\com\api\services\implementation\QuoteServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.api.repository.customer.CustomerRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Description:
Parameter 1 of constructor in com.api.services.implementation.QuoteServiceImpl required a bean of type 'com.api.repository.customer.CustomerRepository' that could not be found.
Action:
Consider defining a bean of type 'com.api.repository.customer.CustomerRepository' in your configuration.
#Autowired
private final CustomerRepository customerRepository;
#Autowired
private final QuoteRepository quoteRepository;
#Component
public interface CustomerRepository extends JpaRepository<Customer,
Integer> {
}
Config File
#EnableJpaRepositories(
basePackageClasses = {
QuoteRepository.class,
CustomerConfig.class
},
entityManagerFactoryRef = "quoteEntityManager",
transactionManagerRef = "quoteTransactionManager")
public class QuoteConfig {
#Bean(name = "quoteEntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean quoteEntityManager(EntityManagerFactoryBuilder builder, #Qualifier("quoteDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages(Quote.class)
.persistenceUnit("S4DevservIntranet")
.build();
}
#Primary
#Bean("quoteDataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource quoteDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean("quoteTransactionManager")
public PlatformTransactionManager quoteTransactionManager(#Qualifier("quoteEntityManager") LocalContainerEntityManagerFactoryBean quoteEntityManager) {
return new JpaTransactionManager(Objects.requireNonNull(quoteEntityManager.getObject()));
}
}
You don't need to use #Component annotation since you use the spring-data JpaRepository interface. but if you wouldn't you have to use #Repository annotation.
In this part you add CustomerConfig class instead CustomerRepository in the list of JpaRepositories
#EnableJpaRepositories(
basePackageClasses = {
QuoteRepository.class,
CustomerConfig.class
},
It must be:
#EnableJpaRepositories(
basePackageClasses = {
QuoteRepository.class,
CustomerRepository.class
},
Error Message tells it everything, seems you haven't created bean for CustomerRepository, so annotate the class with #Repository or #Component.

PropertyReferenceException:Spring Data JPA error No property found for type

I am working on an upgrade of a spring boot application from JDK 1.8 to 11 and moving to Spring boot version: 2.4.9 from 2.0.3.RELEASE.
Application build is successful but the application is failing to run due to the following exception. Please note that this application is running successfully on JDK 1.8 and Spring boot version:2.0.3.RELEASE.
Can you please help me here?
Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'databaseServiceController': Unsatisfied dependency expressed through field 'posPdmOperationServiceImpl'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'posPdmOperationServiceImpl': Unsatisfied dependency expressed through field 'transactionBusinessService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'transactionBusinessServiceImpl': Unsatisfied dependency expressed through field 'populateRptTablesService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'populateRptTablesServiceImpl': Unsatisfied dependency expressed through field 'storedProcedureRepo'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'storedProcedureRepo' defined in com.client.databaseservice.repositories.StoredProcedureRepo defined in #EnableJpaRepositories declared on OracleDbConfig: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract boolean com.client.databaseservice.rptmaster.repository.OracleTypeRepository.insertStrOpenDataForRebellion(java.util.List,java.util.List)! No property insertStrOpenDataForRebellion found for type StoredProcedureModel!
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:660)
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property insertStrOpenDataForRebellion found for type StoredProcedureModel!
Attaching each file mentioned in the error trace below:
OracleDbConfig:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "oracleEntityManager", transactionManagerRef = "oracleTransactionManager", basePackages = "com.client.databaseservice.repositories")
public class OracleDbConfig {
#Bean
#ConfigurationProperties(prefix = "spring.oracle.datasource")
public DataSource postgresqlDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "oracleEntityManager")
public LocalContainerEntityManagerFactoryBean postgresqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(postgresqlDataSource()).properties(hibernateProperties())
.packages("com.client.databaseservice.transaction.models").persistenceUnit("oraclePU").build();
}
#Bean(name = "oracleTransactionManager")
public PlatformTransactionManager postgresqlTransactionManager(
#Qualifier("oracleEntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map hibernateProperties() {
Resource resource = new ClassPathResource("hibernate.properties");
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
return properties.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue()));
}
}
OracleTypeRepositoryImpl
#Autowired
#Qualifier("oracleEntityManager")
private EntityManager em;
#Override
#Transactional
public boolean insertStrOpenDataForRebellion(List<RPTMasterData> rptMasterDataArrayList,
List<RPTTenderData> rptTenderDataArrayList) {
final String sql = "{call REBELLION_STORE_OPERATIONS.ADDSTROPENREBELLIONDATA(?,?,?)}";
Session session = em.unwrap(Session.class);
boolean result = session.doReturningWork(new ReturningWork<Boolean>() {//Logic to call procedure});
return result;
}
}

run #Component after #Repository in Spring Framework

I'm using Redis in a spring project and I define a #Component class that uses Redis repository with #Autowire, but when debugging the application, #Component class constructor runs before bean to connect to Redis, therefore the application exits with this error :
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataManager' defined in file [/mnt/D/ms/projects/EventDetection/out/production/classes/ir/rahati/data/datamanager/DataManager.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'ir.rahati.data.messagegraph.redis.RedisMessageGraphRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
DataManager class
#Component
public class DataManager {
private final RedisMessageGraph messageGraph;
#Autowired
public DataManager( RedisMessageGraphRepository redisMessageGraphRepository) {
this.messageGraph=new RedisMessageGraph(redisMessageGraphRepository);
}
}
Redis repository interface
#Repository
public interface RedisMessageGraphRepository extends CrudRepository<MessageGraphModel, String> {
}
Configuration Class
#Configuration
#EnableRedisRepositories("ir.rahati.data.messagegraph")
public class RedisMessageGraphConfig {
#Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration("localhost", 6379);
redisStandaloneConfiguration.setDatabase(3);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
#Bean(name = "redis15")
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}

Spring-Boot create bean with out name will cause "NoSuchBeanDefinitionException, No qualifying bean of type[]found for dependency "

I Create the bean by configuration with out name
#Configuration
#ConfigurationProperties(prefix = "mysql")
public class DbConfiguration extends BaseDbConfiguration {
#Bean//(name = "fix")
#Override
public DbClient createClient() {
return super.createClient();
}
}
usage:
#Autowired
private DbClient dbClient;
when I running application it can't start up
And throw NoSuchBeanDefinitionException:
No qualifying bean of type [DbClient] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
But I fix it by add name, why??
#Bean(name = "fix")
I also add a test such like this:
public class TestCreate {
#NotNull
private int test;
public Test createTest() {
return new Test(this.test);
}
}
it configuration like this:
#Configuration
#ConfigurationProperties(prefix = "test")
public class TestConfiguration extends TestCreate {
#Override
#Bean
public Test createTest() {
return super.createTest();
}
}
And autowired like this:
#Autowired
private Test test;
However, this test may work well
It also create Bean without name and Autowired with out Qualifier
Please Tell me why....thanks
Sorry.
I have found the results:
Overriding bean definition for bean 'createClient': replacing ...
So Spring-Boot will create Bean by FunctionName rather than returning ObjectName.

Using 2 beans of the same type: javax.sql.DataSource in Spring

I am developing a Spring Boot based application in which I would like to create 2 beans: One will point to 'Oracle' database; the other will point to Hive. I've declared them as follows:
public #Bean
BoneCPDataSource metadataDataSource() {
BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
boneCPDataSource.setDriverClass(getDriver());
boneCPDataSource.setJdbcUrl(getJdbcUrl());
boneCPDataSource.setUser(getUser());
boneCPDataSource.setPassword(getPassword());
boneCPDataSource.setMaxConnectionsPerPartition(5);
boneCPDataSource.setPartitionCount(5);
return boneCPDataSource;
}
public #Bean
BasicDataSource hiveDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
// Note: In a separate command window, use port forwarding like this:
//
// ssh -L 127.0.0.1:9996:<server>:<port> -l <userid> <server>
//
// and then login as the generic user.
basicDataSource.setDriverClassName("org.apache.hadoop.hive.jdbc.HiveDriver");
basicDataSource.setUrl("jdbc:hive://127.0.0.1:9996:10000/mytable");
return basicDataSource;
}
Problem is at the startup I am getting this:
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration':
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private javax.sql.DataSource
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration.dataSource;
nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type [javax.sql.DataSource] is defined: expected
single matching bean but found 2: metadataDataSource,hiveDataSource
Mainly because both of them inherit from javax.sql.DataSource. What's the best way to fix this?
EDIT:
Now I've declared them as follows:
public #Bean (name="metadataDataSource")
BoneCPDataSource metadataDataSource() {
BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
boneCPDataSource.setDriverClass(getDriver());
boneCPDataSource.setJdbcUrl(getJdbcUrl());
boneCPDataSource.setUser(getUser());
boneCPDataSource.setPassword(getPassword());
boneCPDataSource.setMaxConnectionsPerPartition(5);
boneCPDataSource.setPartitionCount(5);
return boneCPDataSource;
}
public #Bean (name="hiveDataSource")
BasicDataSource hiveDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
// Note: In a separate command window, use port forwarding like this:
//
// ssh -L 127.0.0.1:9996:<server>:<port> -l <userid> <server>
//
// and then login as the generic user.
basicDataSource.setDriverClassName("org.apache.hadoop.hive.jdbc.HiveDriver");
basicDataSource.setUrl("jdbc:hive://127.0.0.1:9996:10000/mytable");
return basicDataSource;
}
And got this exception:
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration':
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private javax.sql.DataSource
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration.dataSource;
nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type [javax.sql.DataSource] is defined: expected
single matching bean but found 2: metadataDataSource,hiveDataSource
The other classes are referring to these beans as follows:
public class MetadataProcessorImpl implements MetadataProcessor {
#Autowired
#Qualifier("metadataDataSource")
BoneCPDataSource metadataDataSource;
#Controller
public class HiveController {
#Autowired
#Qualifier("hiveDataSource")
BasicDataSource hiveDataSource;
Set one of the beam as #Primary
as described in the section 67.2 Configure Two DataSources
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-two-datasources
Give different names to your beans when using #Bean:
#Bean(name="bonecpDS")
public BoneCPDataSource metadataDataSource() {
//...
}
#Bean(name="hiveDS")
public BasicDataSource hiveDataSource() {
//...
}
Then, when injecting the bean, use #Qualifier and specify the name of the bean:
#Component
public class FooComponent {
#Autowired
#Qualifier("bonecpDS")
DataSource boneCPDataSource;
}
If you want to use two data sources at the same time and they are not primary and secondary, you should disable DataSourceAutoConfiguration on your application annotated by #SpringBootApplication(excludes = {DataSourceAutoConfiguration.class}).
Since the DataSourceAutoConfiguration will init the DataSourceInitializer class. The init method in DataSourceInitializer class needs to get DataSource. When there is more than one DataSource, the system gets confused by getting which DataSource.
#SpringBootApplication(excludes = {DataSourceAutoConfiguration.class}) means that system won't load the DataSourceAutoConfiguration.class when run the application.
I faced similar issue. Added #SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
and added manual configuration. It worked!

Categories

Resources