I\'m considering spring data for a project. Is it possible to override the per default generated save method? And if yes, how?
The solution from @ytterrr works but for older Spring Data versions, for Spring Data 2.1 at least, this is the way to not just override any repository method but also access to the underlying features (access to the entity manager to persist, delete, find...):
public interface MyEntityRepositoryCustom {
<S extends MyEntity> S save(S entity);
}
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
final JpaEntityInformation<MyEntity, ?> entityInformation;
EntityManager em;
public MyEntityRepositoryImpl(EntityManager entityManager) {
this.entityInformation = JpaEntityInformationSupport.getEntityInformation(MyEntity.class, entityManager);
this.em = entityManager;
}
/**
* @see org.springframework.data.jpa.repository.support.SimpleJpaRepository
*/
@Transactional
public <S extends MyEntity> S save(S entity) {
// do your logic here
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
}
Didn't get this to work nicely so I put my required logic into a service class and left the repositories save method untouched.
What works for me (Spring boot 2.x Java 11), even if not perfectly clean. It compiles with IDE and Maven and Gradle. The above solution by Lucas does not work for me for the JpaRepository.
public interface MyRepo extends JpaRepository<MyType, Long>, MyRepoCustom{
//Implemented in MyRepoCustom
public MyType save(MyType mytypeEntity);
}
The custom interface (repeats the declaration, which is not nice):
public interface MyRepoCustom{
public MyType save(MyType mytypeEntity);
}
The custom Impl:
@Repository
public class MyRepoImpl implements MyRepoCustom{
@PersistenceContext
private EntityManager em;
@Transactional
public MyType save(MyType mytypeEntity) {
//type safe implementation
}
}
I guess you extend SimpleJpaRepository :
public class **CustomSimpleJpaRepository** extends SimpleJpaRepository {
@Transactional
public <S extends T> S save(S entity) { //do what you want instead }
}
Then make sure this is used instead of the default SimpleJpaRepository by extending:
public class CustomJpaRepositoryFactory extends JpaRepositoryFactory {
protected <T, ID extends Serializable> JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager entityManager) {
Class<?> repositoryInterface = metadata.getRepositoryInterface();
JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
SimpleJpaRepository<?, ?> repo = isQueryDslExecutor(repositoryInterface) ? new QueryDslJpaRepository(
entityInformation, entityManager) : new CustomSimpleJpaRepository(entityInformation, entityManager);
repo.setLockMetadataProvider(lockModePostProcessor.getLockMetadataProvider());
return repo;
}
}
Not done yet, we also need to have your own factory bean to use it in the config xml:
public class CustomRepositoryFactoryBean <T extends JpaRepository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new **CustomJpaRepositoryFactory**(entityManager);
}
}
the config:
<jpa:repositories base-package="bla.bla.dao" factory-class="xxxx.**CustomRepositoryFactoryBean**"/>
Hope it helps.
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;