I was studying Spring Data JPA recently, and I faced a weird circular dependency error.
Previously, I often used MyBatis
as shown below.
// I often declare mapper first, and inject it to my persistence.
@Mapper
public interface MyBatisMapper {/* ... */}
/* ------------ */
@Repository
public class MyBatisRepo {
private final MyBatisMapper mapper;
public MyBatisRepo(MyBatisMapper mapper) {
this.mapper = mapper;
}
/* ... */
}
So I tried JPA
on this way, and faced a circular dependency.
Here's the code on JPA
TestEntity
// entity just for test
@Entity
public class TestEntity {
@Id
private Long id;
}
// Persistence contracts
public interface TestRepo {
}
JPA DAO
//
public interface JPATestRepo extends JpaRepository<TestEntity, Long> {
}
@Repository
public class JPATestRepoImpl implements TestRepo {
private final JPATestRepo jpaRepo;
public JPATestRepoImpl(JPATestRepo jpaRepo) {
this.jpaRepo = jpaRepo;
}
}
2024-10-19T19:46:00.760+09:00 WARN 66384 --- [testing] [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'JPATestRepoImpl' defined in file [/~~~/Desktop/Coding/testing/build/classes/java/main/core/testing/JPATestRepoImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'JPATestRepoImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?
2024-10-19T19:46:00.761+09:00 INFO 66384 --- [testing] [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-10-19T19:46:00.762+09:00 INFO 66384 --- [testing] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2024-10-19T19:46:00.807+09:00 INFO 66384 --- [testing] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2024-10-19T19:46:00.811+09:00 INFO 66384 --- [testing] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-10-19T19:46:00.825+09:00 ERROR 66384 --- [testing] [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌──->──┐
| JPATestRepoImpl defined in file [/~~~/Desktop/Coding/testing/build/classes/java/main/core/testing/JPATestRepoImpl.class]
└──<-──┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Process finished with exit code 1
In console, it says JPATestRepoImpl
has a cycle to itself.
But in JPATestRepoImpl
on above, it doesn't. (at least on my thought)
I've treid restart, claen & rebuild application, but it's all the same.
HOWEVER, if I rename JPATestRepoImpl
to another (like TestRepoJPAImpl)
, the circular dependency disapper like magic...
It seems like Spring or JPA conflicts its' bean names to each other, but I have no idea why it has.
So I wanted to ask whether there is really a circular dependency in my source code or where it comes from if there isn't. If there is any policy coming from JPA, is there any documentation on it?
You can see full source code on here
The default repositoryImplementationPostfix
is Impl
so Spring is assuming that your JPATestRepoImpl
is a custom implementation of JPATestRepo
.
If you want to use Impl for another purpose, you can change the repositoryImplementationPostfix
with the following setting:
@EnableJpaRepositories(repositoryImplementationPostfix = "CustomImpl")