Why do I get when I try to use getDatasource from dependency? - spring

I have a dependency jar that has the following...
#Configuration
#PropertySource("classpath:datasource.properties")
public class DatasourceConfig {
...
#Bean
public DataSource getDatasource() {
try {
PoolDataSource ds = PoolDataSourceFactory.getPoolDataSource();
ds.setConnectionFactoryClassName(OracleDataSource.class.getName());
...
return ds;
} catch (SQLException throwables) {
logger.error(throwables);
System.exit(-1);
}
return null;
}
}
I import this JAR using maven but then when I run java -cp 'JAR_LOCATION:ETC' pkg.Application I get...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

Are you scanning packages as well somewhere in the code?
If not try adding
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.food.bar") <---
#PropertySource("classpath:datasource.properties")
public class DatasourceConfig {

Related

Spring Boot Test doesnt load application context

I created a application-integrationtest.yaml in my src/test/resources path so my test run against a created docker testcontainer. The problem is that my application-integrationtest.yaml is not being loaded.
I am running a SpringBoot 2.x application
This is my DataSource Class
#Configuration
public class IndexModificationDatabaseConfiguration {
#Bean
public JOOQToSpringExceptionTransformer
jooqToSpringExceptionTransformer() {
return new JOOQToSpringExceptionTransformer();
}
#Bean
public DataSourceConnectionProvider connectionProvider(final DataSource
dataSource) {
return new DataSourceConnectionProvider(new
TransactionAwareDataSourceProxy(dataSource));
}
#Bean(name = "indexModification")
#ConfigurationProperties("index-modified.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
#Bean
public DataSource
indexModificationDataSource(#Qualifier("indexModification") final
DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
#Bean
public DSLContext
createIndexModifiedDslContext(#Qualifier("indexModificationDataSource")
final DataSource dataSource) {
final DefaultConfiguration configuration = new DefaultConfiguration();
configuration.set(connectionProvider(dataSource));
configuration.set(new
DefaultExecuteListenerProvider(jooqToSpringExceptionTransformer()));
configuration.set(SQLDialect.POSTGRES);
return new DefaultDSLContext(configuration);
}
}
This is my Test
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {IndexModificationDatabaseConfiguration.class})
#ActiveProfiles("integrationtest")
public class ContainerOrchestrator {
#Test
public void testContainer() {
assertTrue(true);
}
}
And the exception is
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'indexModificationDataSource' threw exception; nested exception is
org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:582)
... 55 more
Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
When i debug i see that my Datasource has null values on Driver, Url, password, etc.
I think you need to add #Profile annotation to your configuration class

Field repository required a bean named 'entityManagerFactory' that could not be found

I have spent some days trying to solve this error but without success. I am trying to configure two databases and write in both of them.
I looked at:
https://medium.com/#joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7
https://www.baeldung.com/spring-data-jpa-multiple-databases
https://www.devglan.com/spring-boot/spring-boot-multiple-database-configuration
https://raymondhlee.wordpress.com/2015/10/31/configuring-multiple-jpa-entity-managers-in-spring-boot/
https://github.com/igormukhin/spring-boot-sample-data-jpa-multiple/blob/master/src/main/java/sample/data/jpa/Database1Configuration.java
And a loot more links from SO for the errors or similar examples.
Here is my code:
fromDB.datasource.url=jdbc:h2:file:D:/test1/db1
fromDB.datasource.username=sa
fromDB.datasource.password=
fromDB.datasource.platform=h2
fromDB.datasource.driverClassName=org.h2.Driver
toDB.datasource.url=jdbc:h2:file:D:/test2/db2
toDB.datasource.username=sa
toDB.datasource.password=
toDB.datasource.platform=h2
toDB.datasource.driverClassName=org.h2.Driver
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.h2.console.settings.trace=true
spring.h2.console.settings.web-allow-others=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Hibernate Settings -hibernate.properties
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.initialization-mode=always
spring.datasource.initialize=true
spring.jpa.generate-ddl=true
ConfigClasses
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "toEntityManager",
transactionManagerRef = "toTransactionManager",
basePackages = "leadTime.service"
)
public class ToDBConfig {
#Bean
#ConfigurationProperties(prefix = "toDB.datasource")
public DataSource toDataSource() {
return DataSourceBuilder
.create()
.build();
}
#Bean(name = "toEntityManager")
public LocalContainerEntityManagerFactoryBean toEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(toDataSource())
.properties(hibernateProperties())
.packages(TestDataTo.class)
.persistenceUnit("to")
.build();
}
#Bean(name = "toTransactionManager")
public PlatformTransactionManager toTransactionManager(#Qualifier("toEntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map hibernateProperties() {
Resource resource = new ClassPathResource("hibernate.properties");
try {
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
return properties.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue())
);
} catch (IOException e) {
return new HashMap();
}
}
}
Second configClass
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "fromEntityManager",
transactionManagerRef = "fromTransactionManager",
basePackages = "leadTime.service"
)
public class FromDBConfig {
#Primary
#Bean
#ConfigurationProperties(prefix = "fromDB.datasource")
public DataSource fromDataSource() {
return DataSourceBuilder
.create()
.build();
}
#Primary
#Bean(name = "fromEntityManager")
public LocalContainerEntityManagerFactoryBean fromEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(fromDataSource())
.properties(hibernateProperties())
.packages(TestDataFrom.class)
.persistenceUnit("from")
.build();
}
#Primary
#Bean(name = "fromTransactionManager")
public PlatformTransactionManager fromTransactionManager(#Qualifier("fromEntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map hibernateProperties() {
Resource resource = new ClassPathResource("hibernate.properties");
try {
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
return properties.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue())
);
} catch (IOException e) {
return new HashMap();
}
}}
Repository:
public interface ToRepository extends CrudRepository<TestDataTo, Integer>
{
#Override
TestDataTo save(TestDataTo testDataTo);
}
DataInit:
#Component
public class DataInit {
#Autowired
ToRepository toRepository;
#Autowired
FromRepository fromRepository;
#Transactional("fromTransactionManager")
public void insertDataIntoFromDB() throws SQLException {
TestDataFrom testDataFrom = new TestDataFrom();
testDataFrom.setId(1);
testDataFrom.setName("Test");
fromRepository.save(testDataFrom);
}
//
#Transactional("toTransactionManager")
public void insertDataIntoToDB() throws SQLException {
TestDataTo testDataTo = new TestDataTo();
testDataTo.setId(1);
testDataTo.setName("Ale");
toRepository.save(testDataTo);
}
}
MainClass:
#EnableTransactionManagement
#SpringBootApplication
public class LeadTimeApplication {
private Logger LOG = LoggerFactory.getLogger("LeadTimeApplication");
#Autowired
ToRepository toRepository;
#Autowired
FromRepository fromRepository;
public static void main(String[] args) {
SpringApplication.run(LeadTimeApplication.class, args);
}
#Autowired DataInit initializer;
#PostConstruct
public void init() throws SQLException{
initializer.insertDataIntoFromDB();
initializer.insertDataIntoToDB();
}
Error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field toRepository in leadTime.LeadTimeApplication
required a bean named 'entityManagerFactory' that could not be found.
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
I tried:
Using
#EnableAutoConfiguration(exclude = { JpaRepositoriesAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
Honestly, I don't know what else to do, I re-wrote this code so many times using different approaches but without success. If I let spring to his job, without configuring new entityManagers and transactions and without using #Transactional, the application is working (2 DBs are created), but both tables are created in the sameDB (of course)
Added gradle config
//Spring dependencies
compile "org.springframework.boot:spring-boot-starter-
actuator:${springBootVersion}"
compile "org.springframework.boot:spring-boot-starter-
web:${springBootVersion}"
compile "org.springframework.boot:spring-boot-starter-
logging:${springBootVersion}"
compile "org.springframework.boot:spring-boot-configuration-
processor:${springBootVersion}"
//JPA dependency
compile "org.springframework.boot:spring-boot-starter-data-
jpa:${springBootVersion}"
testCompile "com.oracle:ojdbc7:12.1.0.2"
testCompile 'com.h2database:h2:1.4.194'
runtime 'com.h2database:h2:1.4.194'
// compile group: 'h2', name: 'h2', version: '0.2.0'
compile group: 'org.hibernate', name: 'hibernate-entitymanager'
//compile group: 'org.hibernate', name: 'hibernate-gradle-plugin', version:
'5.3.6.Final'
// https://mvnrepository.com/artifact/org.hibernate/hibernate-core
compile group: 'org.hibernate', name: 'hibernate-core'
According to what you have pasted
https://medium.com/#joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7
One of the darasource is configured as "default" and another one is named. You are creating two "named" beans with from and to prefixes.
Change eg from database definitions entityManager insteed of fromEntityManager and it should be fine.
I don't know the internals, but as for common sense, what you try should work, in practice some default datasource is required by app configurator thus the error.

Spring boot test wrong configuration classes

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) {
// ...
}

Spring 5.0.5 #Value doesn't resolve to correct type

I'm getting the following error in spring 5, and have read all of the posts regarding this issue with no luck. I just refactored the app to use the #Configuration via the PropertiesConfig class instead of appliationContext.xml for the property placeholder definitions
Unsatisfied dependency expressed through field 'secureExpirationHours'; nested
exception is org.springframework.beans.TypeMismatchException: Failed to convert
value of type 'java.lang.String' to required type 'int'; nested exception is
java.lang.NumberFormatException: For input string: "${asset.href.expiration.hours.secure}
Referencing the var:
public class TestRepository {
#Value("${asset.href.expiration.hours.secure}")
private int secureExpirationHours;
}
Mixed Configuration:
#Configuration
#ComponentScan
#Import({PropertiesConfig.class})
#ImportResource({
"classpath:META-INF/spring/applicationContext-assets.xml",
"classpath:META-INF/spring/applicationContext-mongo.xml",
"classpath:META-INF/spring/applicationContext-security.xml",
"classpath:META-INF/spring/applicationContext.xml"})
public class CoreConfig {
}
PropertiesConfig.class:
#Configuration
public class PropertiesConfig {
public static PropertySourcesPlaceholderConfigurer commonEnvConfig;
#Bean(name="commonConfig")
public static PropertiesFactoryBean commonConfig() {
PropertiesFactoryBean commonConfig = new PropertiesFactoryBean();
commonConfig.setLocation(new ClassPathResource("META-INF/spring/config.properties"));
return commonConfig;
}
#Bean(name="envProperties")
public static YamlPropertiesFactoryBean yamlProperties() {
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application-dev.yaml"));
return yaml;
}
#Bean(name="commonConfigPropertyPlaceholder")
public static PropertySourcesPlaceholderConfigurer commonConfigPropertyPlaceholder() throws IOException {
if (commonEnvConfig == null) {
commonEnvConfig = new PropertySourcesPlaceholderConfigurer();
}
PropertiesFactoryBean commonConfig = PropertiesConfig.commonConfig();
try {
commonEnvConfig.setProperties(commonConfig.getObject());
} catch (IOException e) {
e.printStackTrace();
throw e;
}
YamlPropertiesFactoryBean yaml = PropertiesConfig.yamlProperties();
commonEnvConfig.setProperties(yaml.getObject());
commonEnvConfig.setIgnoreUnresolvablePlaceholders(true);
return commonEnvConfig;
}
}
Please and thanks for any help!
Figured out the problem(s) - there are two.
First off, you must call .afterPropertiesSet(); on the PropertiesFactoryBean, otherwise the .getObject() returns null.
#Bean(name="commonConfig")
public static PropertiesFactoryBean commonConfig() throws IOException {
PropertiesFactoryBean commonConfig = new PropertiesFactoryBean();
commonConfig.setLocation(new ClassPathResource("META-INF/spring/config.properties"));
try {
commonConfig.afterPropertiesSet();
}
catch (IOException e) {
e.printStackTrace();
throw e;
}
return commonConfig;
}
Second, you must call "setPropertiesArray()" on the PropertySourcesPlaceholderConfigurer with both of the properties:
PropertySourcesPlaceholderConfigurer commonEnvConfig = new PropertySourcesPlaceholderConfigurer();
commonEnvConfig.setPropertiesArray(commonConfig().getObject(), yamlProperties().getObject());

Spring: Cannot get bean by using #Component and #Bean

I'm new in Spring framework.
I try to config 2 beans with #Bean annotation within #Component.
After that, I try to getBean (by name), I got a NoSuchBeanDefinitionException.
Please help me to resolve it.
Here is my code:
- The component:
package com.example.component;
#Component
public class FactoryMethodComponent {
private static int i;
#Bean
#Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
#Bean
#Qualifier("tb1")
public TestBean1 publicInstanceTB1() {
return new TestBean1(publicInstance());
}
}
-The xml configuration file: app-context.xml.
<beans ...>
<context:component-scan base-package="com.example.*" />
</beans>
-The test code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:app-context.xml" })
public class ComponentBeanTest {
#Test
public void test() {
System.out.println(((TestBean1)context.getBean("tb1")).getTestBean().getMethodName());
System.out.println(publicTestBean.getMethodName());
}
}
-Exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean
named 'tb1' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:577)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1111)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
at com.example.proxy.ComponentBeanTest.test(ComponentBeanTest.java:38)
Replace #Component with #Configuration which indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
#Configuration
public class FactoryMethodComponent {
private static int i;
#Bean
#Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
#Bean
#Qualifier("tb1")
public TestBean1 publicInstanceTB1() {
return new TestBean1(publicInstance());
}
}

Resources