6
votes

I have a Spring boot 1.4.2 application with Hibernate 5.2.6 and Spring data Envers 1.0.5. I am auditing my entities and the audit records are persisted properly.

My application config class is annotated to use the EnversRevisionRepositoryFactoryBean.class as the JPA repository factory.

Application config

@Configuration
@EnableAutoConfiguration
@ComponentScan
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
@EnableTransactionManagement
public class ApplicationConfig {}

I am trying to read the revisions for an audited entity. The entity repository extends RevisionRepository.

Entity Models

@Entity(name = "Base")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER)
@Table(name = "BASE")
@Audited
public abstract class Base {

  @Id
  @GeneratedValue(generator = "baseSeq", strategy = GenerationType.SEQUENCE)
  @SequenceGenerator(name = "baseSeq", sequenceName = "BASE_SEQ", allocationSize = 1)
  @Column(name = "id", updatable = false, nullable = false)
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;

  @Column(name = "name", nullable = false)
  private long barId;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public long getBarId() {
    return barId;
  }

  public void setBarId(long barId) {
    this.barId = barId;
  }

  public abstract String getType();

}

@Entity
@DiscriminatorValue("1")
@Audited
@NamedQueries({
    @NamedQuery(
        name = "Foo.findById",
        query = "select f from Base b where b.id = ?1"),
    @NamedQuery(
        name = "Foo.findByBarId",
        query = "select f from Base b where b.barId = ?1")})
public class Foo extends Base {
    private String type = "Foo";

    @Override
    public String getType() {
      return type;
    }
}

Entity repository

interface FooRepository extends JpaRepository<Foo, Long>,
    JpaSpecificationExecutor<Foo>, RevisionRepository<Foo, Long, Integer> {

  foo findById(Long Id);

  foo findByBarId(Long barId);

}

The application start up fails as the repository cannot be initialized due to a PropertyReferenceException.

Caused by: org.springframework.data.mapping.PropertyReferenceException: No property findRevisions found for type Foo! at org.springframework.data.mapping.PropertyPath.(PropertyPath.java:77) at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329) at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243) at org.springframework.data.repository.query.parser.Part.(Part.java:76) at org.springframework.data.repository.query.parser.PartTree$OrPart.(PartTree.java:235) at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:373) at org.springframework.data.repository.query.parser.PartTree$Predicate.(PartTree.java:353) at org.springframework.data.repository.query.parser.PartTree.(PartTree.java:84) at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.(PartTreeJpaQuery.java:63) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:103) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:214) at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.(RepositoryFactorySupport.java:435) at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:220) at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:266) at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:252) at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)

From what I understand, this should work out of the box. It seems like the repository is being bound to a different implementation than the desired one. Any ideas?

Relevant snippets from the gradle build script

buildscript {
    ext {
        springBootVersion = "1.4.2.RELEASE"
        verifier_version = "1.0.0.RELEASE"
    }
    repositories {
        maven {url "https://plugins.gradle.org/m2/"}
        maven {url "http://repo.spring.io/plugins-release"}
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7") // this enables optional dependencies
        classpath("io.spring.gradle:dependency-management-plugin:0.6.1.RELEASE")
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("se.transmode.gradle:gradle-docker:1.2")
        classpath("com.commercehub:gradle-cucumber-jvm-plugin:0.7")
        classpath("org.ajoberstar:grgit:1.1.0")
        classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.1-rc3")
        classpath("gradle.plugin.org.detoeuf:swagger-codegen-plugin:1.6.3")
        classpath("org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}")
        classpath "net.linguica.gradle:maven-settings-plugin:0.5"
    }
}
...
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.SR7"
        mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifier_version}"
        mavenBom 'org.springframework.cloud:spring-cloud-stream-dependencies:Brooklyn.SR1'
    }
}
...
compile(
        "org.springframework.boot:spring-boot-starter-data-jpa",
        'org.springframework.data:spring-data-commons',       
        'org.springframework.cloud:spring-cloud-starter-config',
        'org.springframework.cloud:spring-cloud-starter-eureka',
        'org.springframework.cloud:spring-cloud-starter-sleuth',
        'org.springframework.cloud:spring-cloud-sleuth-zipkin', 
        'com.netflix.hystrix:hystrix-javanica',                 
        'org.springframework.boot:spring-boot-starter-aop',     
        "org.springframework.boot:spring-boot-starter-web",
        "io.swagger:swagger-annotations:1.5.9",
        "com.google.code.gson:gson:2.7",
        "gradle.plugin.org.detoeuf:swagger-codegen-plugin:1.6.3",
        "org.springframework:spring-orm",
        "com.oracle.jdbc:ojdbc7:12.1.0.2",
        'org.springframework.cloud:spring-cloud-stream',
        'org.springframework.cloud:spring-cloud-stream-test-support',
        'org.springframework.cloud:spring-cloud-stream-binder-test',
        "org.springframework.boot:spring-boot-starter-hateoas",
        "com.fasterxml.jackson.module:jackson-module-parameter-names",
        "com.fasterxml.jackson.datatype:jackson-datatype-jdk8",
        "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.1",
        "org.hibernate:hibernate-core:5.2.6.Final",
        "org.hibernate:hibernate-envers:5.2.6.Final",
        "org.springframework.data:spring-data-envers:1.0.6.RELEASE"
)

Thanks in advance.

1
Can include your Foo entity model please?Naros
@Naros, I have edited my post to add the entity model. It seems like Spring is interpreting the RevisionRepository methods to be auto generated query candidates for entity properties instead of binding the interface implementation methods?golfradio
Can you confirm that you have version 5.2.6.Final of the hibernate-envers artifact on the classpath and not an older one?Naros
Yes. You set me straight on that a couple of weeks ago :)golfradio
Have you tried not overriding the versions of Hibernate and Envers used and let it use the default versions to see if it works? Perhaps there is a compatibility issue but this afaict looks to be some type of spring-data or spring-data-envers issue.Naros

1 Answers

13
votes

You need to add an attribute @EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) to your application class (the class annotated with @SpringBootApplication)

As shown in this answer: https://stackoverflow.com/a/36416266