It's my first question here. I'll try to be as specific as possible.
First of all, I know there are a lot of topics regarding this error, some with solutions, but my case is different because I have this error not every time and it goes away for some time after I type ipconfig /renew in cmd. So, now to detail.
I work in Windows 7.
This is my datasource config:
package ...;
import ...;
#Configuration
public class DataSourceConfig {
#Value("${db.url}") private String url;
#Value("${db.user}") private String user;
#Value("${db.pass}") private String pass;
#Value("${db.poolSize.init}") private int initPoolSize;
#Value("${db.poolSize.min}") private int minPoolSize;
#Value("${db.poolSize.max}") private int maxPoolSize;
#Value("${db.statements.max}") private int maxStatements;
#Value("${db.idleTime.max}") private int maxIdleTime;
#Value("${db.checkoutTimeout}") private int checkoutTimeout;
#Bean
public DataSource oracleDataSource() throws SQLException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(url);
dataSource.setUser(user);
dataSource.setPassword(pass);
dataSource.setInitialPoolSize(initPoolSize);
dataSource.setMaxPoolSize(maxPoolSize);
dataSource.setMinPoolSize(minPoolSize);
dataSource.setMaxIdleTime(maxIdleTime);
dataSource.setMaxStatements(maxStatements);
dataSource.setCheckoutTimeout(checkoutTimeout);
return dataSource;
}
}
JPA config:
package ...;
import ...;
#Configuration
#EnableJpaRepositories
#EnableTransactionManagement
public class JpaConfig {
#Autowired
private DataSource dataSource;
#Value("${is.ddl.enabled}")
private String isDDLenabled ;
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(Boolean.valueOf(isDDLenabled));
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("...");
factory.setDataSource(dataSource);
factory.setJpaDialect(new HibernateJpaDialect());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager Here() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
}
I run in with Jetty. When I run it for the first several times, it's ok. But after 8-15 runs I get the following:
Failed startup of context ...
org.springframework.beans.factory.BeanCreationException:
...
org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'entityManagerFactory' threw exception; nested exception is org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
And after that if I try to run the project I get the same error until I run ipconfig /renew command in the command line. After that it runs again without problem for another 8-15 times.
Have anyone here encountered anything like this? How can ipconfig affect the running of the project like this? Please help.
You are using org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter you should use this org.springframework.orm.jpa.vendor.HibernateJpaDialect
HibernateJpaDialect hibernateJpaDialect =new HibernateJpaDialect();
And set factory object as below:
factory.setJpaVendorAdapter(hibernateJpaDialect);
Related
I'm trying to configure two datasources in my spring batch application. One for batch metadata tables, and another for the business tables.
Snippet from my application.properties file:
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=
spring.batchdatasource.url=
spring.batchdatasource.username=
spring.batchdatasource.password=
spring.batchdatasource.driver-class-name=
My batch config file:
#Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{
#Autowired
private JobBuilderFactory jobs;
#Autowired
private StepBuilderFactory steps;
// #Autowired
// private DataSource dataSource;
#Autowired
private PlatformTransactionManager transactionManager;
#Bean(name = "batchDatasource")
#ConfigurationProperties(prefix="spring.batchdatasource")
public DataSource batchDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "primaryDatasource")
#ConfigurationProperties(prefix="spring.datasource")
#Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Override
public JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource());
// factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setTablePrefix("schema1"+ ".BATCH_");
factory.afterPropertiesSet();
return factory.getObject();
}
/* Job and step bean definitions here */
My main class is the one annotated with #EnableBatchProcessing
#SpringBootApplication
#EnableBatchProcessing
public class SpringBatchExample1Application {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
I'm getting this Requested bean is currently in creation: Is there an unresolvable circular reference? when trying to configure two datasources. It works fine when using a single datasource by autowiring(refer the commented out lines of code) instead of creating multiple beans.
Following is the exception snippet:
Error creating bean with name 'springBatchConfig': Unsatisfied dependency expressed through method 'setDataSource' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'batchDatasource': Requested bean is currently in creation: Is there an unresolvable circular reference?
I looked up and found out this occurs when there's a dependency on a bean which is still not created or is being created. I just see it in the createJobRepository method where datasource is being plugged. I still face the error even if I don't have the createJobRepository method.
It seems like the requirement is for the datasource beans to be created before others. I tried using the #Order annotation, but no luck.
EDIT:
I tried the solution from #Mykhailo Skliar's Accepted answer below, and serparated the Datasource beans into a new Configuration class. Though it resolved the initial Unresolveble circular reference issue anymore, it led me to the following error:
Error creating bean with name 'springBatchConfig': Invocation of init method failed; nested exception is org.springframework.batch.core.configuration.BatchConfigurationException: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
Based on this answer, I changed my url property names as follows:
spring.datasource.jdbc-url=
spring.datasource.jdbc-url=
Though it solved the jdbcUrl error, it posed another issue:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Reference to database and/or server name in 'sample-sql-server.schema1.MY_TABLE_NAME' is not supported in this version of SQL Server.
Both my data sources are Azure SQL server instances.
I looked up and found it was not possible to use multiple Azure SQL databases years ago, but based on this answer it should not be the case anymore.
The issue is most probably because of
factory.setDataSource(batchDataSource());
You should use autowired bean here, instead of calling batchDataSource()
I would split SpringBatchConfig in two beans:
#Configuration
public class DataSourceConfig {
#Bean(name = "batchDatasource")
#ConfigurationProperties(prefix="spring.batchdatasource")
public DataSource batchDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "primaryDatasource")
#ConfigurationProperties(prefix="spring.datasource")
#Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
#Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{
#Autowired
private JobBuilderFactory jobs;
#Autowired
private StepBuilderFactory steps;
#Qualifier("batchDataSource")
#Autowired
private DataSource batchDataSource;
#Autowired
private PlatformTransactionManager transactionManager;
#Override
public JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource);
factory.setTransactionManager(transactionManager);
factory.setTablePrefix("schema1"+ ".BATCH_");
factory.afterPropertiesSet();
return factory.getObject();
}
}
I have two DataSources in my application, which work as expected when connecting to the databases in a live environment. However, when writing unit tests for this application, I'm encountering problems with my bean definitions.
This is my primary DataSource configuration:
#Configuration
#EnableJpaRepositories(
basePackages = "foo.bar.repository.primary",
entityManagerFactoryRef = "primaryEntityManager",
transactionManagerRef = "primaryTransactionManager")
public class PrimaryDataSourceConfig {
#Bean
#Primary
#ConfigurationProperties("primary.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan("foo.bar.domain.entity");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
Map<String, String> properties = new HashMap<>();
properties.put("hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
properties.put("hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
em.setJpaPropertyMap(properties);
return em;
}
#Bean
#Primary
public PlatformTransactionManager primaryTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(primaryEntityManager().getObject());
return transactionManager;
}
}
I have a test where all I want to do is spin up the entire application context, looking like this.
#AutoConfigureTestDatabase
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ErpApplicationTest {
#Test
public void test() {
// Application started
}
}
However, when I run this test, I get the following error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primaryEntityManager' defined in class path resource [foo/bar/primaryDataSourceConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'primaryEntityManager' threw exception; nested exception is java.lang.IllegalArgumentException: No visible constructors in class org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean
What is causing this error, and what can I do to rectify it? Flyway is able to connect to the embedded H2 instance the annotation generates and run its migrations, but the primary DataSource, alongside its EntityManager fail at creation.
I resolved the issue by doing the following:
First I changed the AutoConfigureTestDatabase-annotation to not replace any DataSource:
#AutoConfigureTestDatabase(
replace = AutoConfigureTestDatabase.Replace.NONE)
I was now experiencing an error where I would timeout against the database. Since the AutoConfig defaults to an in-memory h2, I figured the previous database connection settings were incorrect. I changed my application.properties-file to contain the following:
primary.datasource.driver-class-name=org.h2.Driver
primary.datasource.jdbc-url=jdbc:h2:~;MODE=MYSQL
primary.datasource.username=
primary.datasource.password=
secondary.datasource.driver-class-name=org.h2.Driver
secondary.datasource.jdbc-url=jdbc:h2:~;MODE=MYSQL
secondary.datasource.username=
secondary.datasource.password=
Presumably this error occurred because the auto configuration couldn't properly replace the entityManager for my custom datasource. By ensuring the DataSource wasn't replaced, and ensuring the connection url was correct, the test went through as expected.
I have tried for literally hours to get this working, looking at the docs:
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html
...various stackoverflow questions and as much other stuff as I can find. But, this is proving elusive (read, making me want to bash my head against a wall). Any help would be so, so welcome!
I need to connect to two different databases (sounds simple enough?) and I have a Spring Boot web application using the spring-boot-starter-data-jpa dependency which got things off the ground very nicely with a single data source. Now I need to talk to a second database and things have not been working. I thought I had it working for a while, but it turned out that everything was going to the primary database.
I'm currently trying to get this working on a separate 'cut down' project to try and reduce the number of moving parts, still not working though.
I have two #Configuration classes - one for each data source, here's the first:
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "firstEntityManagerFactory",
transactionManagerRef = "firstTransactionManager",
basePackages = {"mystuff.jpaexp.jpatest"})
public class DataConfiguration {
#Bean
#Primary
#ConfigurationProperties(prefix = "app.datasource1")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("app.datasource1")
public DataSource firstDataSource() {
return firstDataSourceProperties().initializeDataSourceBuilder().
driverClassName("org.postgresql.Driver").
url("jdbc:postgresql://localhost:5432/experiment1").
username("postgres").
password("postgres").
build();
}
#Primary
#Bean
public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("mystuff.jpaexp.jpatest");
factory.setDataSource(firstDataSource());
factory.setPersistenceUnitName("ds1");
return factory;
}
#Primary
#Bean
public PlatformTransactionManager firstTransactionManager() {
return new JpaTransactionManager();
}
}
and here's the second:
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "secondEntityManagerFactory",
transactionManagerRef = "secondTransactionManager",
basePackages = {"mystuff.jpaexp.jpatest2"})
public class Otherconfiguration {
#Bean
#ConfigurationProperties(prefix = "app.datasource2")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("app.datasource2")
public DataSource secondDataSource() {
return secondDataSourceProperties().initializeDataSourceBuilder().
driverClassName("org.postgresql.Driver").
url("jdbc:postgresql://localhost:5432/experiment2").
username("postgres").
password("postgres").
build();
}
#Bean
public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("mystuff.jpaexp.jpatest2");
factory.setDataSource(secondDataSource());
factory.setPersistenceUnitName("ds2");
return factory;
}
#Bean
public PlatformTransactionManager secondTransactionManager() {
return new JpaTransactionManager();
}
}
In each of the two packages mystuff.jpaexp.jpatest and mystuff.jpaexp.jpatest2 I have a simple #Entity and CrudRepository that should go together with the first and second datasources respectively.
I then have a main() to test things out:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {WebMvcAutoConfiguration.class})
#ComponentScan("mystuff.jpaexp.*")
public class SpringbootCommandLineApp implements CommandLineRunner {
private final MyRepository myRepository;
private final OtherRepo otherRepo;
#Autowired
public SpringbootCommandLineApp(MyRepository myRepository, OtherRepo otherRepo) {
this.myRepository = myRepository;
this.otherRepo = otherRepo;
}
public static void main(String[] args) {
new SpringApplicationBuilder(SpringbootCommandLineApp.class)
.web(false)
.run(args);
}
#Override
public void run(String... args) throws Exception {
myRepository.save(new MyEntity("Goodbye or hello"));
myRepository.save(new MyEntity("What?"));
myRepository.save(new MyEntity("1,2,3..."));
myRepository.findAll().forEach(System.out::println);
otherRepo.save(new MyEntity2("J Bloggs"));
otherRepo.save(new MyEntity2("A Beecher"));
otherRepo.save(new MyEntity2("C Jee"));
otherRepo.findAll().forEach(x -> {
System.out.println("Name:" + x.getName() + ", ID: " + x.getId());
});
}
}
And lastly, some props in application.properties:
app.datasource1.driver-class-name=org.postgresql.Driver
app.datasource1.url=jdbc:postgresql://localhost:5432/experiment1
app.datasource1.username=postgres
app.datasource1.password=postgres
app.datasource2.driver-class-name=org.postgresql.Driver
app.datasource2.url=jdbc:postgresql://localhost:5432/experiment2
app.datasource2.username=postgres
app.datasource2.password=postgres
These have absolutely no effect -- things appear to still be configured by spring.datasource.* instead, which is obviously no use.
Final output:
2018-05-25 17:04:00.797 WARN 29755 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is 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).
2018-05-25 17:04:00.800 INFO 29755 --- [ main] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2018-05-25 17:04:00.803 ERROR 29755 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Cannot determine embedded database driver class for database type NONE
Action:
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).
Process finished with exit code 1
I know there's a lot of code here, sorry and thanks!
Well, it took a long time, I think there were multiple subtle problems and also some bits that could be simplified a little:
Only one DataSourceProperties was required - both datasources can use it
#ConfigurationProperties is needed on the DataSource bean definition, not the DataSourceProperties bean
I think the #ComponentScan("mystuff.jpaexp.*") annotation was incorrect, and replacing this with simply #ComponentScan seemed to fix picking up of some of the bean definitions
I had to inject an EntityManagerFactor into the JpaTransactionManager definition: return new JpaTransactionManager(secondEntityManagerFactory().getObject());
I added a JpaProperties bean, and explicity pulled those properties into a VendorAdapter
The VendorAdapter/JpaProperties changes looked like this (it seems odd that JpaProperties is vendor-independent yet it has a hibernateProperties on it?!):
#Bean
public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("...entity-package...");
factory.setDataSource(secondDataSource());
Map<String, String> props = new HashMap<>();
props.putAll(secondJpaProperties().getProperties());
props.putAll(secondJpaProperties().getHibernateProperties(secondDataSource()));
factory.setJpaPropertyMap(props);
factory.setPersistenceUnitName("ds2");
return factory;
}
#Bean
#ConfigurationProperties(prefix = "jpa.datsource2")
public JpaProperties secondJpaProperties() {
return new JpaProperties();
}
I think this was enough to get things going. In addition, the ever-so-clever defaulting of various properties to make an embedded H2 instance spring to life, no longer worked, so I also had to be explicit about all the DB properties:
jpa.datasource1.hibernate.ddl-auto=create
app.datasource1.driver-class-name=org.h2.Driver
app.datasource1.url=jdbc:h2:mem:primary
app.datasource1.username=
app.datasource1.password=
jpa.datasource2.hibernate.ddl-auto=create
app.datasource2.driver-class-name=org.h2.Driver
app.datasource2.url=jdbc:h2:mem:view
app.datasource2.username=
app.datasource2.password=
I am new to the programming world so what I say may seem silly.
I am trying to run a spring-boot test as JUnit under Eclipse but I just can't figure out how to use the spring-boot annotations... I have read several guides and browsed this website but didn't find anything that resolved my problem.
I am trying to run the JUnit test-class below :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={CBusiness.class,CService.class,CDao.class}, loader = AnnotationConfigContextLoader.class)
#SpringBootTest
public class CalculTest {
#Autowired
CBusiness business;
#Test
public void testCalcul() throws TechnicalException {
Object object= new Object();
object.setId1("00");
object.setId2("01");
object.setNombrePlacesMaximum(new BigInteger("50"));
Long result=business.calcul(object);
assertTrue(result>0);
}
Running this as a JUnit test gives me the following exception :
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cDao': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available
The EntityManager parameter from the CDao class has the annotation #PersistenceContext, I thought this meant it was automatically generated by Hibernate but apparently it isn't... How can I instanciate the EntityManager using only java code? I don't have any .xml or .properties file...
FYI here are the classes called by the test :
Business Layer :
#Component("cBusiness")
public class CBusiness {
#Autowired
CService cService;
public long calcul(Object object) throws TechnicalException {
//Code (calls a method from CService class)
}
Service layer :
#Service
public class CService {
#Autowired
CDao cDao;
Dao Layer
#Repository
#Transactional(rollbackFor = {TechnicalException.class})
public class CDao {
#PersistenceContext
EntityManager entityManager;
I tried testing the method inside a webservice using only the #autowire annotation on the Business layer and if worked fine, however I just cannot instanciate it in the JUnit tests. I tried several ways of running this test and I am not sure this is the right way of doing it, so I'm open to any suggestion.
Thanks in advance.
#Configuration
#EnableTransactionManagement
public class PersistenceJPAConfig{
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "\\your package here" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("\\Driver");
dataSource.setUrl("\\URL");
dataSource.setUsername( "\\userName" );
dataSource.setPassword( "\\password" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
EDIT 1:
I'm currently calling this from a Main class like so:
public class Main
{
public static void main(String[] args)
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringAppConfig.class);
DataSource dSource = ctx.getBean(DataSource.class);
System.out.println(dSource.getClass().toString());
if (dSource instanceof Log4jdbcProxyDataSource)
{
Log4jdbcProxyDataSource log4jdbcProxyDataSource = (Log4jdbcProxyDataSource) dSource;
Object lf = log4jdbcProxyDataSource.getLogFormatter();
System.out.println(lf.getClass().toString());
}
System.exit(0);
}
}
Original:
Code follows after explanation:
I have a Spring application with a JavaConfig, call it the primary app, that imports another Spring JavaConfig class from a library. This imported JavaConfig is supposed to wrap any DataSource created in the primary app with an Aspect, which has an autowired LogDelegator.
As long as the primary app contains only a DataSource, everything works. But as soon as I add an EntityManager to the primary app, I get a nested IllegalArgumentException saying that the LogDelegator is null.
Primary App's Config:
#Configuration
#Import(MonitoringConfig.class)
public class SpringAppConfig
{
#Bean
public DataSource dataSource()
{
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.H2).build();
return db;
}
}
Imported Library Config:
#Configuration
#EnableSpringConfigured
public class MonitoringConfig extends WebMvcConfigurerAdapter
{
#Bean
public LogDelegator logDelegator()
{
return new LogDelegator();
}
#Bean
public ConfigurationAspect configurationAspect()
{
return Aspects.aspectOf(ConfigurationAspect.class);
}
}
The Aspect:
#Configurable
public aspect ConfigurationAspect
{
#Autowired
LogDelegator logDelegator;
Object around() : execution(public DataSource (#Configuration *).*(..)) {
Object ret = proceed();
if (ret instanceof DataSource) {
Log4jdbcProxyDataSource dataSource = new Log4jdbcProxyDataSource((DataSource) ret);
dataSource.setLogFormatter(logDelegator);
return dataSource;
} else {
return ret;
}
}
This code works great until I add the following,
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setDatabase(Database.H2);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setJpaVendorAdapter(vendorAdapter);
return factory;
}
#Bean
public EntityManager entityManager()
{
return entityManagerFactory().getObject().createEntityManager();
}
#Bean
public PlatformTransactionManager transactionManager()
{
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
and then I get:
java.lang.reflect.InvocationTargetException at java.lang.Thread.run(Thread.java:722)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class SpringAppConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [publ
ic org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean com.fl.sas.configurable.config.SpringAppConfig.entityManagerFactory()] threw exception; ne
sted exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class SpringAppConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public
javax.sql.DataSource SpringAppConfig.dataSource()] threw exception; nested exception is java.lang.IllegalArgumentException: log4j
dbc: logDelegator cannot be null.
Can anyone help?
I needed to add
#Depends(value="configurationAspect") on dataSource()
Luca Basso Ricci answered the question. If he ever adds the answer, I'll give him the credit. :)