When using a generic identifier in a @MappedSuperclass (e.g. via Spring Data’s AbstractPersistable<PK extends Serializable>), Hibernate 7.x does not consistently resolve the concrete type parameter provided by subclasses.
Instead, during model building, the identifier type is treated as the generic upper bound: java.io.Serializable rather than the actual concrete type bound in the subclass (e.g. Long, UUID).
Impact
This results in a behavioral change compared to previous Hibernate versions, specifically affecting identifier generator resolution.
Before Hibernate 7.x
In earlier versions (e.g. Hibernate 5.x / early 6.x), generator selection was straightforward and effectively used the resolved concrete type.
Example reference:
- Generation strategy interpreter logic
hibernate-orm/hibernate-core/src/main/java/org/hibernate/boot/internal/GenerationStrategyInterpreter.java at 29333239d333e4b6ae730356fd412e0f4900309a · hibernate/hibernate-orm · GitHub
Behavior:
-
If subclass specifies:
class Entity extends AbstractPersistable<UUID> -
Hibernate correctly resolves ID type as
UUID -
Appropriate generator (e.g.
UUIDGenerator) is selected
After Hibernate 7.x
In Hibernate 7.x, generator resolution happens through:
IdGeneratorResolverSecondPass
Reference:
Behavior:
-
Identifier type is resolved as:
Serializable -
Since the type is not recognized as a specific concrete type (e.g.
UUID) -
Hibernate falls back to a default generator, typically:
SequenceStyleGenerator