For general spring JpaRepository DAO (no spring-boot) , if the interface extends a custom interface , spring will mistake the interface methods as object's properties .
For example
interface ILocalDateTime {
fun getLocalDateTime() : LocalDateTime
}
interface UserDaoCustom : ILocalDateTime {
// query functions skipped
}
interface UserDao : JpaRepository<User, Long>, UserDaoCustom
class UserImpl : UserDaoCustom {
@PersistenceContext
private lateinit var em: EntityManager
override fun getLocalDateTime(): LocalDateTime {
return LocalDateTime.now()
}
// query functions skipped
}
This is a simplified UserDao
. UserDaoCustom
extends ILocalDateTime
which contains a method getLocalDateTime
.
Note : localDateTime
is not a field of User
.
At runtime, JpaRepository
will mistake getLocalDateTime
(or localDateTime
?) as User
's field , and throws such exception :
Caused by: org.springframework.data.repository.query.QueryCreationException:
Could not create query for public abstract java.time.LocalDateTime foo.ILocalDateTime.getLocalDateTime()!
Reason: Failed to create query for method public abstract java.time.LocalDateTime foo.ILocalDateTime.getLocalDateTime()!
No property getLocalDateTime found for type User!;
nested exception is java.lang.IllegalArgumentException:
Failed to create query for method public abstract java.time.LocalDateTime foo.ILocalDateTime.getLocalDateTime()!
No property getLocalDateTime found for type User!
Environment :
Kotlin 1.6.20
Spring 5.3.19
spring-data-jpa 2.5.11
How to solve this problem ? (with able or unable to modify ILocalDateTime
's code)
Thanks.
CodePudding user response:
I think it is about naming and how Spring pick up implementations of repository extensions.
TLDR;
Change name of your implementation from UserImpl
to UserDaoCustomImpl
.
I have checked a similar setup and using your naming fails with the exact same error, but naming it "right" makes it work as expected
public interface ILocalDateTime {
LocalDateTime getLocalDateTime();
}
@Repository
public interface UserDao extends UserDaoCustom, JpaRepository<User, Long> {
}
public interface UserDaoCustom extends ILocalDateTime{
}
@Repository
public class UserDaoCustomImpl implements UserDaoCustom {
@Override
public LocalDateTime getLocalDateTime() {
return LocalDateTime.now();
}
}
and tests
@ExtendWith(SpringExtension.class)
@DataJpaTest
class UserRepositoryTest {
@Autowired
private UserDao userDao;
@Test
public void savesUser() {
userDao.save(new User());
}
@Test
public void bazzinga() {
assert userDao.getLocalDateTime() != null;
System.out.println("Bazzinga!" userDao.getLocalDateTime());
}
}