Home > other >  JpaRepository mistakes custom interface as property
JpaRepository mistakes custom interface as property

Time:04-29

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());
    }


}

yelds enter image description here

  • Related