Home > Blockchain >  Hibernate 6 regression with generics
Hibernate 6 regression with generics

Time:01-20

I tried to migrate my application from Hibernate 5.4.30.Final to 6.1.6.Final, database H2 2.1.214. I observed a different behaviour regarding generics when using a CriteriaQuery. I have stripped it down to a testcase (which does not make any sense but shows the problem). In Hibernate 5 the following query to a generic field name runs fine whereas Hibernate 6 throws an Exception.

CriteriaBuilder cb = eMgr.getCriteriaBuilder();
CriteriaQuery<String> cr = cb.createQuery(String.class);
Root<Person> person = cr.from(Person.class);
cr.select(person.<String> get("name"));
TypedQuery<String> query = eMgr.createQuery(cr);

Exception:

Converting `org.hibernate.query.QueryTypeMismatchException` to JPA `PersistenceException` : Specified result type [java.lang.String] did not match Query selection type [java.lang.Object] - multiple selections: use Tuple or array

Here are my sample class definitions:

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class GenericPerson<T>
{
    @Id
    @GeneratedValue(generator = "increment")
    private long id;
    private T name;

    public GenericPerson()  {   }
    public GenericPerson(T name)    { this.name = name;}

    public T getName() { return this.name; }
    public void setName(T name) {   this.name = name;   }

    public long getId() { return this.id;}
    public void setId(long id) { this.id = id; }
}

@Entity
public class Person extends GenericPerson<String>
{
    public Person() { }
    public Person(String name) {    super(name);    }
}

Hibernate 5 seems to handle generics differently to Hibernate 6 but I could not find any hint in the migration document. Why fails the test case with Hibernate 6?

CodePudding user response:

In Hibernate 5, when using a generic field in a CriteriaQuery, the type parameter of the generic field is inferred at runtime. However, in Hibernate 6, the type parameter of the generic field needs to be explicitly specified at compile-time.

One way to fix this issue is to explicitly specify the type of the "name" field in the CriteriaQuery, by using the "as" method on the Root object:

cr.select(person.as(String.class).get("name"));

This tells Hibernate 6 that the "name" field should be considered a String, and it should work as expected.

Alternatively, if you want to keep the generic structure you can use the "get" method with a Class parameter like this:

cr.select(person.<String>get("name", String.class));

This tells Hibernate 6 that you are expecting a String value from the field "name" of the class Person.

  • Related