After upgrading from Spring Boot Version 2.2.7.RELEASE to 2.7.3 we get the error when we try to start our application.
2022-09-22 11:20:31.896 WARN 60031 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController': Unsatisfied dependency expressed through field 'bookApi'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bookApi': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookRepository': Cannot create inner bean '(inner bean)#4b3fe06e' 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)#4b3fe06e': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
2022-09-22 11:20:31.898 INFO 60031 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2022-09-22 11:20:31.908 INFO 60031 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-09-22 11:20:31.941 ERROR 60031 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field repository in com.example.module.api.BookApi required a bean named 'entityManagerFactory' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
We modularized our application with JPMS, and we start our application with the following command:
java --module-path ./mods:./lib -m app/com.example.app.AppApplication
We copy our application jars to ./mods
(with the maven-jar-plugin
) and all runtime dependencies to ./lib
(with the maven-dependency-plugin
).
This works perfectly with Java 11 and with the Spring Boot "2.2.7.RELEASE", but starting with the release "2.2.8.RELEASE" the same project leads to the above error. We get the same error even if we upgrade to the newest Spring Boot Version 2.7.3
To reproduce in a small but running example. I created a jpms application and uploaded a working version (Spring Boot 2.2.7.RELEASE) to the main
branch and the non-working version (Spring Boot 2.2.8.RELEASE) to the spring-boot-2.2.8.RELEASE
branch.
The project URL is: https://github.com/rudolfgrauberger/jpms-multi-modules-example
Edit: I added the new branch spring-boot-2.7.3-java17
to show the issue with the newest version of Spring Boot and the LTS-Version of Java.
Anyone have any idea how I can find out what exactly the problem is or what has changed between the versions (especially with the EntityManager or with @EnableJpaRepositories)?
I have already searched the Announcement for 2.2.8.Release, the Release Notes for changes and also used the search engine very intensively but I don't found anything regarding to this problem/change.
Happy to share more information, just need to know what exactly would be helpful
The issue came with the HikariCP dependency update in Spring Boot 2.2.8.RELEASE. More information about the background of the issue in HikariCP can you found in the HikariCP-Issue here.
With Spring Boot 2.5.0
and Spring Boot JDBC 2.5.0
the HikariCP dependency was already updated to the recommended version for java 8 and that is 4.0.3
. As of Spring Boot 2.5.0, you can only add requires com.zaxxer.hikari;
to module-info.java
of your JPMS "app" project to make it all work.
Add requires com.zaxxer.hikari;
to your module-info.java
.
module app {
requires com.zaxxer.hikari;
}
2.2.8.RELEASE
and < 2.5.0
you can downgrade the HikariCP dependency back to 3.4.3
. <dependencyManagement>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.3</version>
</dependency>
</dependencyManagement>
Or upgrade to 4.0.3
and add requires com.zaxxer.hikari;
to module-info.java
.
<dependencyManagement>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
</dependencyManagement>
module app {
// ...
requires com.zaxxer.hikari;
// ...
}
I also added the fixes for 2.2.8.RELEASE
and 2.7.3
to the new branches spring-boot-2.2.8.RELEASE-fixed
and spring-boot-2.7.3-java17-fixed
.
First I searched for how can I debug the bean loading/instantiation and I found the gread Spring: Framework in Depth video course by Frank P Moley III and I added an own implementation of the BeanFactoryPostProcessor
-Interface and debug a while, after that I logged all defined packages and bean names from the BeanClassLoader for both Spring Boot versions (2.2.7.RELEASE and 2.2.8.RELEASE).
Here is my implementation:
package com.example.app;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Configuration
public static class AppConfig {
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
return new MyBeanFactoryPostProcessor();
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
final ClassLoader beanClassLoader = configurableListableBeanFactory.getBeanClassLoader();
System.out.println("############################################################");
System.out.println("");
System.out.println("Defined packages");
System.out.println("------------------------------------------------------------");
List.of(beanClassLoader.getDefinedPackages()).forEach(System.out::println);
System.out.println("------------------------------------------------------------");
System.out.println("Bean names");
System.out.println("------------------------------------------------------------");
configurableListableBeanFactory.getBeanNamesIterator().forEachRemaining(System.out::println);
System.out.println("------------------------------------------------------------");
System.out.println("");
System.out.println("############################################################");
}
}
Here the packages/beans that are exists in my app with Spring Boot 2.2.7.RELEASE but not exists in my app with Spring Boot 2.2.8.RELEASE:
############################################################
Defined packages
------------------------------------------------------------
package org.springframework.boot.orm.jpa
package com.zaxxer.hikari
package org.springframework.jdbc.core.namedparam
package org.springframework.transaction.interceptor
package org.springframework.boot.jdbc.metadata
package org.springframework.orm.jpa.persistenceunit
package org.aopalliance.intercept
package org.hibernate.boot.model.naming
package org.springframework.transaction.event
package com.zaxxer.hikari.pool
------------------------------------------------------------
Bean names
------------------------------------------------------------
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari
dataSource
org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration$Hikari
org.springframework.boot.autoconfigure.jdbc.DataSourceJmxConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$PooledDataSourceConfiguration
org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration
hikariPoolDataSourceMetadataProvider
org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration$JpaWebConfiguration
openEntityManagerInViewInterceptor
openEntityManagerInViewInterceptorConfigurer
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
transactionManager
jpaVendorAdapter
entityManagerFactoryBuilder
entityManagerFactory
spring.jpa.hibernate-org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties
dataSourceInitializedPublisher
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateConfiguration
jdbcTemplate
org.springframework.boot.autoconfigure.jdbc.NamedParameterJdbcTemplateConfiguration
namedParameterJdbcTemplate
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
spring.jdbc-org.springframework.boot.autoconfigure.jdbc.JdbcProperties
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration$DataSourceTransactionManagerConfiguration
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
org.springframework.transaction.config.internalTransactionAdvisor
transactionAttributeSource
transactionInterceptor
org.springframework.transaction.config.internalTransactionalEventListenerFactory
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration$CglibAutoProxyConfiguration
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$TransactionTemplateConfiguration
transactionTemplate
org.springframework.orm.jpa.SharedEntityManagerCreator#0
I wasn't particularly surprised by the beans, or rather, they didn't provide that much insight, but the information about the packages seemed promising to me.
So I gradually added the missing packages as "requires" to the project "app" until I got the message Module metrics.healthchecks not found, required by com.zaxxer.hikari
.
With this message, I found with Google directly the related issue in HikariCP: https://github.com/brettwooldridge/HikariCP/issues/1582.
For testing I downgraded the HikariCP dependency to version 3.4.3 and it works again (with Spring Boot 2.2.8.RELEASE).
The update to the recommended version 4.0.3 and the upgrade to the recommended version for Java 11+ works after adding requires com.zaxxer.hikari
to the module-info.java
in my app
project.
A good article with an explanation of how you can upgrade/downgrade or unifies the transitive dependency version, you found here.
I hope this background information helps anyone. Even if it's just a suggestion of what you can try when it comes to checking the existence of the beans or if you want to intervene in the bean creation process.