Cosium / spring-data-jpa-entity-graph

Spring Data JPA extension allowing full dynamic usage of EntityGraph on repositories
MIT License
482 stars 49 forks source link

spring-data-jpa-entity-graph is incompatible with spring-data-envers #180

Open federicotg opened 6 months ago

federicotg commented 6 months ago

What steps will reproduce the problem ?

Steps to reproduce the behavior:

  1. Set up a project using envers using @EnableEnversRepositories
  2. Set repositoryFactoryBeanClass = EntityGraphJpaRepositoryFactoryBean.class
  3. Spring context does not start: Error is Caused by: org.springframework.data.mapping. PropertyReferenceException: No property 'findRevisions' found for type 'CashCost'

What is the expected output ?

Spring context should start and the Envers repositories should work normally.

What happens instead ?

Spring context fails to start.

Environment

Additional context

The problem is @EnableEnversRepositories uses its own repositoryFactoryBeanClass that is EnversRevisionRepositoryFactoryBean and EntityGraphJpaRepositoryFactoryBean does not extend that one. I can't create my own EnversRevisionRepositoryFactoryBean subclass adding the RepositoryEntityManagerEntityGraphInjector because it is package private. Envers is a popular hibernate audit log implementation and spring-data-envers is a spring-data module to deal with envers in a spring-data way.

federicotg commented 6 months ago

There's a workaround. Don't use @EnableEnversRepositories, just keep @EnableJpaRepositories and define manually each RevisionRepository like this

public @Bean
    RevisionRepository<MyEntity, Integer, Long> myEntityRevisions() {
        final JpaEntityInformation<MyEntity, ?> entityInformation = JpaEntityInformationSupport.getEntityInformation(MyEntity.class, entityManager);
        final RevisionEntityInformation revisionEntityInformation = new ReflectionRevisionEntityInformation(MyCustomRevision.class);
        return new EnversRevisionRepositoryImpl<>(entityInformation, revisionEntityInformation, entityManager);
    }

or like this:

public @Bean
    RevisionRepository<MyEntity, String, Integer> myEntityRevisionRepository() {
        final JpaEntityInformation<MyEntity, ?> entityInformation = JpaEntityInformationSupport.getEntityInformation(MyEntity.class, entityManager);
        final RevisionEntityInformation revisionEntityInformation = new DefaultRevisionEntityInformation();
        return new EnversRevisionRepositoryImpl<>(entityInformation, revisionEntityInformation, entityManager);
    }

As explained here:

https://stackoverflow.com/questions/65940151/dynamically-creating-spring-enversrevisionrepository-from-a-java-class

dima-bzz commented 6 months ago

Alternative, your can create two different repository and configure annotation @EnableJpaRepositories and @EnableEnversRepositories like annotation filter or use different package

@HistoryRepository
public interface MyEntityHistoryRepository extend RevisionRepository<MyEntity, Long, Long> {}

and

public interface MyEntityRepository extend JpaRepository<MyEntity, Long> {}

configure JpaRepository

@Configuration
@EnableJpaRepositories(excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = HistroyRepository.class))
public class JpaConfiguration {}

configure EnversRepository

@Configuration
@EnableEnversRepositories(includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = HistroyRepository.class))
public class JpaHistoryConfiguration {}

Or you can create custom repository factory bean like this