Spring Data: Override save method

前端 未结 11 1227
温柔的废话
温柔的废话 2020-11-27 05:30

I\'m considering spring data for a project. Is it possible to override the per default generated save method? And if yes, how?

相关标签:
11条回答
  • 2020-11-27 05:39

    In order to properly override the save method, you have to create a interface with the proper signature of the original method declared on CrudRepository, including the generics

    public interface MyCustomRepository<T> {
        <S extends T> S save(S entity);
    }
    

    Then, create your implementation ( the suffix Impl is important at the name of the class)

    public class MyCustomRepositoryImpl implements MyCustomRepository<MyBean> {
    
        @Autowired
        private EntityManager entityManager;
    
    
        @Override
        public <S extends MyBean> S save(S entity) {
           /**
             your custom implementation comes here ...
             i think the default one is just        
            return this.entityManager.persist(entity);
           */
        }
    
    }
    

    Finally, extend your repository with the previously created interface

    @RepositoryRestResource
    @Repository
    public interface MyBeanRepository extends PagingAndSortingRepository<MyBean, Long>, MyCustomRepository<MyBean> {}
    
    0 讨论(0)
  • 2020-11-27 05:40

    If you are using interfaces only you can use default methods to do simple overrides of the CrudRepository or JpaRepository:

    
    public interface MyCustomRepository extends CrudRepository<T, ID> {
    
      @Override
      default <S extends T> S save(S entity)
      {
        throw new UnsupportedOperationException("writes not allowed");
      }
    }
    
    0 讨论(0)
  • 2020-11-27 05:41

    Use JPA Event listeners like @PrePersist, @PreUpdate. This will work if the underlying JPA provider supports this features. This is JPA 2 feature so the latest Hibernate, EclipseLink etc should support it.

    0 讨论(0)
  • 2020-11-27 05:42

    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.

    0 讨论(0)
  • I am using Spring Boot 2.1.4 on OpenJDK 11 and also keep getting the ambiguous reference error from the compiler (although the Eclipse JDT compiler that my IDE is using has no problem with it, so I didn't discover this issue until I tried to build it outside my IDE).

    I basically ended up defining a method with a different name in my extension interface, and then used a default override in my main repository interface to call it when the normal save() was called.

    Here is an example:

    Define the interface for your custom logic as usual:

    public interface MyEntityRepositoryCustomSaveAction {
        public MyEntity saveSafely(MyEntity entity);
    }
    

    Make your repository extend that interface:

    public interface MyEntityRepository extends JpaRepository<MyEntity, MyEntityId>,
      MyEntityRepositoryCustomSaveAction {
    
        @Override
        @SuppressWarnings("unchecked")
        default MyEntity save(MyEntity entity)
        {
            return saveSafely(entity);
        }
    }
    

    Note that we have overridden save() from JpaRepository (well, really CrudRepository which JpaRepository extends) to call our custom method. The compiler warns about the unchecked conversion, so up to you if you want to silence it with @SuppressWarnings .

    Follow the convention for the Impl class with your custom logic

    public class MyEntityRepositoryCustomSaveActionImpl implements 
      MyEntityRepositoryCustomSaveAction {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        @Override
        public MyEntity saveSafely(MyEntity entity) {
           //whatever custom logic you need
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 05:43

    This could be helpful if you are going to reuse the original method. Just inject EntityManager in the implementing class.

    public interface MyEntityRepositoryCustom {
      <S extends MyEntity> S save(S entity);
    }
    
    public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
    
        // optionally specify unitName, if there are more than one
        @PersistenceContext(unitName = PRIMARY_ENTITY_MANAGER_FACTORY)
        private EntityManager entityManager;
    
        /**
         * @see org.springframework.data.jpa.repository.support.SimpleJpaRepository
         */
        @Transactional
        public <S extends MyEntity> S save(S entity) {
            // do your logic here
            JpaEntityInformation<MyEntity, ?> entityInformation = JpaEntityInformationSupport.getMetadata(MyEntity.class, entityManager);
            if (entityInformation.isNew(entity)) {
                entityManager.persist(entity);
                return entity;
            } else {
                return entityManager.merge(entity);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题