I am stuck on an issue that involves generics. I understand the problem, but I do not know how call methods for JpaRepository. For instance, when I call existsById and pass a Long number value, I get capture of ? is required.
Below lies a snippet of the code:
private JpaRepository<?, ?> getRepository(Object repository) {
if (repository instanceof JpaRepository<?, ?> repo) {
return repo;
}
return null;
}
The repository:
@Repository
public interface IStatusRepository extends JpaRepository<Status, Long> {
}
The issue come here, when I try to call most methods from getRepository(...):
public void test(IStatusRepository statusRepository) {
...
var data = getRepository(statusRepository).findById(1L);
...
}
The code above results in a compilation error. The findById(1L); now takes a "capture of ?" and passing a long does not satisfy the compiler.
How can I call findById with no compilation error?
Generic parameters don't exist at runtime.
At runtime, the type of JpaRepository<Status, Long>
is simply JpaRepository
.
When you check if (repository instanceof JpaRepository<?, ?> repo)
the check that is actually made is if it's an instance of JpaRepository
, and that's it.
So what it returns can be a JpaRepository
with any type arguments, hence the ?
wildcards to say that the type is unknown. From a type perspective, it doesn't mean that the returned type has the same type arguments as repository
.
As for how to satisfy this... Do you actually need to call getRepository
? This function seems very hacky, and in your example, is not even needed, as you can call statusRepository.findById(1L)
directly.
For the sake of providing a solution, I'll give you one, but I strongly suggest against doing this.
You could get rid of the compilation error by using raw type of JpaRepository
:
// DO NOT DO THIS
private JpaRepository getRepository(Object repository) {
if (repository instanceof JpaRepository repo) {
return repo;
}
return null;
}
This would get rid of the compilation error (you'll likely get a warning), but then you open the way of having runtime errors (ClassCastException
s) because you can assign the result to any type (JpaRepository<String, String> data = getRepository(statusRepository);
would compile for example), which is way more dangerous than compile errors. You basically remove type safety here.