Let's say we have three JPA objects with name and id. I made an interface with getters+setters for name and id.
class Car implements MetadataObject
class Bus implements MetadataObject
class Train implements MetadataObject
We also have three repositories for these JPA objects:
interface CarRepository extends CrudRepository<Car, Long>
interface BusRepository extends CrudRepository<Bus, Long>
interface TrainRepository extends CrudRepository<Train, Long>
For each of these objects we want to run the same method in an spring service. (highly simplified)
private void importMetadata(CrudRepository<? extends MetadataObject, String> mRepository) {
Optional<? extends MetadataObject> currentOptional = mRepository.findById(1);
if (currentOptional.isPresent()) {
MetadataObject current = (MetadataObject) currentOptional.get();
current.setName("a1");
mRepository.save(current);
}
}
Which is callable by the same spring service by
@Autowired
private CarRepository carRepository;
...
importMetadata(carRepository);
This results in the error:
The method save(S) in the type CrudRepository<capture#4-of ? extends MetadataObject, Long> is not applicable for the arguments (MetadataObject)
Which is odd if I look at Springs CRUD Repository: CrudRepository<T, ID>
and its save method: <S extends T> S save(S entity);
.
In our example we have T = ? extends MetadataObject
T = ? extends MetadataObject
and S = ? extends ? extends MetadataObjects
S = ? extends ? extends MetadataObjects
S = ? extends ? extends MetadataObjects
.
If we change my function to private void importMetadata(CrudRepository<MetadataObject, String> bdbRepository)
the save method is correct but I can't call the method with my carRepository anymore
The method importMetadata(CrudRepository<MetadataObject,String>) in the type <...> is not applicable for the arguments (CarRepository)
Be aware: I highly simplified the example. I know that in this example Interfaces for these JPA classes makes no sense. I also know that my method makes no sense but it highlights the problem perfectly.
My question would be: What to pass to save or how to rewrite this function that it works? What exactly is the issue here?
You can use this method definition:
private void <T extends MetadataObject>importMetadata(CrudRepository<T, String> mRepository) {
Optional<T> currentOptional = mRepository.findById(1);
if (currentOptional.isPresent()) {
T current = currentOptional.get();
current.setName("a1");
mRepository.save(current);
}
}
I will try the explain the reason the method save
of CrudRepository<? extends MetadataObject, String> mRepository
CrudRepository<? extends MetadataObject, String> mRepository
fails.
Suppose we have a generic class:
class C<T> {
public void save (T t) {
// .. whatever
}
}
When we write something like:
void f (C<? extends Object> c) {
c.save(new Object());
}
the compiler complains about the c.save
line.
That's because, when applying the type restriction, the compile doesn't know whether the c
reference points, in fact, to C<Object>
or C<Number>
or whatever, since both C<Object>
and C<Number>
are accepted as arguments for f
.
Because of that, the compiler doesn't know whether the save
method's argument is allowed or not, hence the error.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.