Home > Mobile >  Spring JPA Hibernate uses old @Column names in Pageable requests: PropertyReferenceException
Spring JPA Hibernate uses old @Column names in Pageable requests: PropertyReferenceException

Time:05-27

I've encountered a problem where Spring doesn't see new @Column names of @Entity

Exact example which I run:

package pckg;

import javax.persistence.*;

@Entity 
@Table(name = "example")
class Example {
    
    @Column(name = "id")
    public int id;
    
    @Column(name = "old")
    public int old;
}
package repo;

import org.springframework.data.jpa.repository.JpaRepository;
import pckg.Example;

public interface ExampleRepository extends JpaRepository<Example, Int> {
    Example findById(long id);
}

Rest code is Scala, which, I hope, is fine enough to read

package controller;

import repo.ExampleRepository
import pckg.Example

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.{Page, PageRequest, Sort}
import org.springframework.web.bind.annotation.{GetMapping, RequestParam, RestController}

class ExampleController {

  @Autowired
  private var repo: ExampleRepository = _

  @GetMapping(value = Array("/example"))
  def getPage(@RequestParam(value = "page",   defaultValue = "0")  page:   String,
              @RequestParam(value = "size",   defaultValue = "10") size:   String,
              @RequestParam(value = "sort",   defaultValue = "id") sortBy: String) Array[Example] = try {
    val pageNumber = page.toInt
    val requestedSize = size.toInt
    val sort = Sort.by(sortBy)
    
    val pageable = PageRequest.of(pageNumber, requestedSize, sort)
    val resultPage: Page[Example] = repo.findAll(pageable)

    resultPage.getContent.asScala.toArray
  } catch {
    case e: Throwable => Array.empty
  }
}
import org.springframework.boot.{CommandLineRunner, SpringApplication}
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
class App {}

object App {
  def main(args: Array[String]): Unit = {
    SpringApplication.run(classOf[App], args: _*)
  }
}

application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/example
spring.datasource.username=example
spring.datasource.password=example
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create

I build and run this code, testing with browser, making requests on localhost:8080/example endpoint with parameter sort="old" like this: localhost:8080/example?sort=old

And then I change @Column name from "old" to "bnew" like this:

package pckg;

import javax.persistence.*;

@Entity 
@Table(name = "example)
class Example {

    @Column(name = "id")
    public int id;


//    @Column(name = "old")
    @Column(name = "bold")
    public int old;
}

Fully rebuild project, run app, hibernate logs seems fine as they show that old table was dropped, new table created, fields are named correctly but... Using localhost:8080/example?sort=bold leads to

org.springframework.data.mapping.PropertyReferenceException: No property 'bold' found for type 'Example'! Did you mean ''old''?

If you have an idea what's going on or at least have a tip where the issue comes from I would gladly listen and dive in answer

UPD

After renaming field "old" to "bold" I found out that there is a problem with naming strategy, so I considered defining

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

in my application.properties, hoping it would help, but it didn't

Is there any way?

UPD 2 Warning: in order to achieve results I achieved while debugging you need Hibernate 5.6.9, Spring 2.7.0, blank started app (you haven't made any requests involving your test-request yet, so there is nothing in request cache (except for id field)) .......... In short, you can directly jump to PropertyPath(String name, TypeInformation<?> owningType, List base), which is a constructor for PropertyPath class, executing logic of our program, in which we will fall in CachedIntrospectionResults::getPropertyDescriptor(String name) which checks that descriptor of our class has a corresponding field (this field's name equals to the sortBy parameter in our case), and, if field's name not same as sortBy parameter, we will not get our sorting or get it wrong (since it's another, not mentioned by us field)

Thus question is closed, no hope here

CodePudding user response:

    package pckg;

import javax.persistence.*;

@Entity 
@Table(name = "example)
class Example {

    @Column(name = "id")
    public int id;


//    @Column(name = "old")
    @Column(name = "bold")
    public int old;
}

You missed a colon " in the @Table(name = "example).

CodePudding user response:

Answer is actual for Hibernate 5.6.9, didn't check what's going on in another versions.

Let us debug while executing our page request (repo.findAll(pageable))

Skipping all wrapper, calls and checks: in short, you can directly jump to PropertyPath(String name, TypeInformation<?> owningType, List base), which is a constructor for PropertyPath class, executing logic of our program, in which we will fall in CachedIntrospectionResults::getPropertyDescriptor(String name) which checks that descriptor of our class has a corresponding field (this field's name equals to the sortBy parameter in our case), and, if field's name not same as sortBy parameter, we will not get our sorting or get it wrong (since it's another, not mentioned by us field)

Thus question is closed, no hope here

  • Related