Spring Data: Override save method
I'm considering spring data for a project. Is it possible to override the per default generated save method? And if yes, how?
Simply create your custom interface as usual and declare there the methods you want to ovverride with the same signature of the one exposed by CrudRepository
(or JpaRepository
, etc.). Suppose you have a MyEntity
entity and a MyEntityRepository
repository and you want to override the default auto-generated save
method of MyEntityRepository
which takes an only entity instance, then define:
public interface MyEntityRepositoryCustom {
<S extends MyEntity> S save(S entity);
}
and implement this method as you like in your MyEntityRepositoryImpl
, as usual:
@Transactional
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
public <S extends MyEntity> S save(S entity) {
// your implementation
}
}
And then, as usual, let MyEntityRepository
extend MyEntityRepositoryCustom
.
Doing this, Spring Data JPA will call the save
method of your MyEntityRepositoryImpl
instead of the default implementation.
At least this works for me with the delete
method in Spring Data JPA 1.7.2.
"ambiguous reference" error
As reported by some of the commenters, probably starting from a certain Spring Data JPA version or javac version (I can't say when it started to fail, but I know for sure that it worked before) the javac compiler began to give a compilation error on the overridden method: "ambiguous reference".
Eclipse JDT does not return this error and code works at runtime, in fact I opened Bug 463770 for this reason: either it's a javac bug or a JDT bug that does not conform to javac.
This said, Lucas has posted the workaround below, which at a first sight might seem to be identical to the one described above. Actually, the difference stands on the MyEntityRepositoryCustom
, declaration which must include the generic type <S>
, even if it's apparently useless. So, if you encounter this error change the custom interface declaration as:
public interface MyEntityRepositoryCustom<S> {
<S extends MyEntity> S save(S entity);
}
and let the standard repository interface implement MyEntityRepositoryCustom<MyEntity>
rather than just MyEntityRepositoryCustom
.
However, if you don't want to generify your custom interface, you can extract a separate fragment interface particulary for the save
method 2. Then the solution looks as follows:
public interface MyEntityRepositoryCustom {
// custom methods
}
public interface CustomizedSaveRepository<T> {
<S extends T> S save(S entity);
}
@Transactional
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom,
CustomizedSaveRepository<MyEntity> {
@Override
public MyEntity save(MyEntity entity) {
// your implementation for CustomizedSaveRepository#save
}
// implementations of MyEntityRepositoryCustom
}
To provide override of default generated save method you need to use aggregation of Spring Data repository implementation inside your own custom repository implementation.
Repository interface:
public interface UserRepository extends CrudRepository<User, String>{
}
Your repository implementation:
@Repository("customUserRepository")
public class CustomUserRepository implements UserRepository {
@Autowired
@Qualifier("userRepository") // inject Spring implementation here
private UserRepository userRepository;
public User save(User user) {
User user = userRepository.save(entity);
// Your custom code goes here
return user;
}
// Delegate other methods here ...
@Override
public User findOne(String s) {
return userRepository.findOne(s);
}
}
Then use your custom implementation in your service:
@Autowired
@Qualifier("customUserRepository")
private UserRepository userRepository;