Enum Literals in Hibernate and JPA: A Surprisingly Astonishing Difference
Enum Literals in Hibernate and JPA: A Surprisingly Astonishing Difference
This is another case of code review teaching something new. During a code review, a colleague asked me if it was possible to use a static import for an enum and use them in JPA queries (using Spring JPA).
'Well ... no!'. IntelliJ flags it as an error. Everybody on Stack Overflow uses the full class path, and the AI says that I cannot.
But ... let's try. Surprisingly, it worked ... astonishment. Why is it working? Is it a bug in IntelliJ flagging as error the enum?
The reason is a subtle difference between Hibernate and JPA.
Hibernate allows using just the enum type name, while JPA requires the fully qualified class path of the enum.
Enum Persistence in JPA and Hibernate
JPA provides two standard ways to persist enums:
- ORDINAL (default) – Stores enums as their ordinal values (integer indexes).
- STRING – Stores enums as their string names.
Example Enum
Here a simple example to illustrate the issue:
public enum BookType {
PHYSICAL, ELECTRONIC;
}
Now, let's create a Spring Boot entity that uses this enum.
JPA Entity with Enum
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING) // Persisting as STRING
private BookType type;
...
}
Querying Enum Literals in JPA vs. Hibernate
Repository
@Query("select b from Book b where b.type = ELECTRONIC")
List<Book> findEBooks();
According to the internet 'consensus' this request should not work. IntelliJ complains about it:
IntelliJ would like something like:
If we run the first request with (no full path), hibernate generates the following request:
All good for Hibernate, but who is right? Why is it working?
The solution as usual is in the source code or, easier in this case, in the specifications and documentation.
2. JPA’s Fully Qualified Enum Requirement
With JPA and JPQL, we need to use the fully qualified class name of the enum in the query.
This is clearly stated in the specifications of the current edition of the specs and the draft of the next (version 4.0):
JPA latest draft: https://jakartaee.github.io/persistence/latest-nightly/nightly.html#literals
Enum literals support the use of Java enum literal syntax. The fully qualified enum class name must be specified.
This requires that my query should be:
@Query("select b from Book b where b.type = dev.marmo.book.db.BookType.ELECTRONIC")
List<Book> findEBooks();
2. Hibernate-Specific Behavior
Hibernate, that is the default implementation of JPA and it's much more powerful, allows using the simple enum name:
Hibernate 6.6 documentation: https://docs.jboss.org/hibernate/orm/6.6/querylanguage/html_single/Hibernate_Query_Language.html#enum-literals
Literal values of a Java enumerated type may be written without needing to specify the enum class name
The enum class is inferred from the type of the expression on the left of the comparison.
In this case, IntelliJ is not correct showing an error, because we are using the Hibernate implementation of JPA.
I don't know the origin of the difference and I won't investigate in the mailing list of the working group. I guess that JPA wanted to avoid to add more complexities to the already difficult implementation of the specifications, or mayne Hibernate added this behavior after the release of the specifications.
In the real world, Hibernate is the default implementation and I didn't see (in the last 10 years) projects using different libraries (OpenJPA, EclipseLink).
The JakartaEE specification should maybe align on this feature of Hibernate.
What to choose
- Code Readability – Hibernate’s approach makes queries cleaner and easier to read.
- Refactoring Issues – In JPA, if the package name of the enum changes, all queries using the full path could break.
- IDE and Community - JPA requirements is accepted everywhere, Hibernate feature is flagged by the IDE.
- JPA strict rule - If you adopt JPA repositories it make sense to follow the strict rules of JPA to avoid confusion, even if Hibernate allows you more freedom.
Do you have any Hibernate vs. JPA quirks that you’ve encountered? Share them!