1

I know Spring Data uses SimpleJpaRepository as the implementation of JpaRepository. I am looking forward to override its save method for certain Repositories. Is there any way that doesn't imply replacing the default implementation for all my repositories?

I've already tried to extend SimpleJpaRepository in my MyEntityJpaImpl class but it does not provide a default constructor suitable for autowiring.

EDIT:

Here is the class I'm trying to autowire

public class MyEntityJpaImpl<ClientesCentro, ClientesCentroPK extends Serializable> extends SimpleJpaRepository<ClientesCentro, ClientesCentroPK> implements ExtendedRepository<ClientesCentro, ClientesCentroPK>{

    private JpaEntityInformation<ClientesCentro, ClientesCentroPK> entityInformation;
    @PersistenceContext
    private EntityManager em;
    private Class<ClientesCentro> clazz;

    public MyEntityJpaImpl(Class<ClientesCentro> domainClass, EntityManager em) {       

        this((JpaEntityInformation<ClientesCentro, ClientesCentroPK>) JpaEntityInformationSupport.getMetadata(domainClass, em), em);
        this.clazz = domainClass;
    }

    public MyEntityJpaImpl(JpaEntityInformation<ClientesCentro, ClientesCentroPK> jpaEntityInformation, EntityManager entityManager) {
        super((JpaEntityInformation<ClientesCentro, ClientesCentroPK>) jpaEntityInformation, entityManager);
        this.entityInformation =  jpaEntityInformation;
        this.clazz = this.entityInformation.getJavaType();
        this.em = entityManager;
    }

    public void refresh() {

    }

    @Transactional
    @Override
    public <S extends ClientesCentro> S save(S entity) {
            System.out.println("Hello world!");

            if (entityInformation.isNew((ClientesCentro) entity)) {
                em.persist(entity);
                return entity;
            } else {
                return em.merge(entity);
            }
    }   
}

And the most relevant stacktrace part:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.xxxyyy.erp.dal.repository.domain.MyEntityJpaImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.xxxyyy.erp.dal.repository.domain.MyEntityJpaImpl.<init>()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1094)
    ... 55 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.xxxyyy.erp.dal.repository.domain.MyEntityJpaImpl.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
    ... 56 common frames omitted
Computist
  • 145
  • 1
  • 8
  • See this http://stackoverflow.com/a/19784038 may provides you a solution – Guillermo Aug 22 '15 at 06:36
  • Hello, thanks for your answer. That question *almost* solves mine but the problem is I want to override `SimpleJpaRepository` in my `MyEntityJpaImpl`. For this purpose I extend `SimpleJpaRepository`, but Spring cannot autowire this implementantion beause it lacks a default constructor. – Computist Aug 24 '15 at 07:51
  • What are you doing to autowire your repository? Are you defining an repository interface for injection instead of MyEntityJpaImpl's interface, right? Edit the question to add the related code and classes you have at the moment – Guillermo Aug 24 '15 at 11:09
  • Possible duplicate of [Spring Data: Override save method](https://stackoverflow.com/questions/13036159/spring-data-override-save-method) – Mateusz Stefek Aug 09 '18 at 09:54

2 Answers2

0

You Can Provide Custom Implementation by writing your own method inside interface which extends JpaRepository

Two ways to do this :

1 . You can use @Query annotation and write query inside it.

@Query("-----Query here------")
public List<Employee> getEmp();

2 . You can use NamedQuery and give reference to you method.

@Query(name="HQL_GET_ALL_EMPLOYEE_BY_ID")
public List<Employee> getEmpByIdUsingNamedQuery(@Param("empId") Long   
empId); 
ashish
  • 161
  • 1
  • 6
  • 13
  • Hello, thanks for your answer. My goal is to be able to modify the entity's properties before I save it, so I thought the best method is to override the JPA's save() implementation for these particular repositories that require this special behavior. – Computist Aug 21 '15 at 13:45
  • 1
    That looks more like something on the service level and not the repository level, why do you need to modify properties? Instead of a save method you could also use a listener or simply annotate a method in those entities with `@PrePersist` or `@PreUpdate` so have that behavior in your classes rather then the repository. The latter should only be involved in storing the object not change it. – M. Deinum Aug 22 '15 at 09:33
  • Hello, I haven'ttried these annotations. The reason of wanting to override `SimpleJpaRepository` is because I'm are using a legacy database where I do not have access to the source, and after some researching, in order to insert data, I need to provide some default values. Some of them are nulls, other values like zeroes and other just foreign keys. I thought about putting this code in the service layer, but since **almost** of these values have no logic at all, I thought they would fit well in the data access layer. – Computist Aug 24 '15 at 07:56
0

The documentation for spring-data contains examples solving exactly your problem.

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior

Example 30. Fragments overriding save(…)

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

class CustomizedSaveImpl<T> implements CustomizedSave<T> {

  public <S extends T> S save(S entity) {
    // Your custom implementation
  }
}

The following example shows a repository that uses the preceding repository fragment:

Example 31. Customized repository interfaces

interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}

interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> {
}
Mateusz Stefek
  • 3,478
  • 2
  • 23
  • 28