Skip to content

Conversation

@jarda182
Copy link

@jarda182 jarda182 commented Nov 5, 2025

Summary

Fixes Java 25 compatibility issue in typed-ids-hibernate-63 library where Hibernate 6.6 throws HibernateException when using custom ID generators with ObjectBigIntId types.

Problem

On Java 25, Hibernate 6.6 changed how it wraps custom types, causing ID generators to fail with:

org.hibernate.HibernateException: The given type is expected to be a CustomType wrapper over a ObjectBigIntIdType, but was 'basicType@146(cz.rohlik.referrer.persistence.ReferrerUserId,-3)' instead

Root Cause

Different type wrapping behavior between Java versions:

Java 21:
CustomType wrapper
└─> ObjectBigIntIdType (recognized custom UserType)

Java 25:
BasicTypeImpl wrapper
└─> SerializableJavaType (treats ObjectBigIntId as generic Serializable)
└─> ReferrerUserId.class (concrete ID class exteding ObjectBigIntId)

Hibernate 6.6 on Java 25 no longer recognizes the registered ObjectBigIntIdType and falls back to treating ObjectBigIntId subclasses as generic Serializable types wrapped in BasicTypeImpl.

Solution

Updated both ID generators to handle both wrapping strategies:

Changes

Modified Files:

  • ObjectBigIntIdSequenceStyleGenerator.java
  • ObjectBigIntIdIdentityGenerator.java

Key Changes:

  1. Added BasicType wrapper detection for Java 25 compatibility
  2. Extract concrete ID class from SerializableJavaType wrapper
  3. Dynamically create ObjectBigIntIdType with the extracted class and JDBC type
  4. Maintain backward compatibility with Java 21's CustomType wrapper

Code Example

// Java 21 path (existing)
if (type instanceof CustomType<?> customType) {
    var userType = customType.getUserType();
    if (userType instanceof ObjectBigIntIdType objectBigIntIdType) {
        return objectBigIntIdType;
    }
}

// Java 25 path (new)
if (type instanceof BasicType<?> basicType) {
    var javaTypeClass = basicType.getExpressibleJavaType().getJavaTypeClass();
    if (ObjectBigIntId.class.isAssignableFrom(javaTypeClass)) {
        return new ObjectBigIntIdType(javaTypeClass, basicType.getJdbcType());
    }
}

TestingAll 40 existing integration tests pass on Java 25 (OpenJDK 25 LTS)
✅ Backward compatibility verified on Java 21Backward compatibility verified on Java 17

Integration tests cover all ID generation strategies:
- App-generated IDs
- DB Auto-generated IDs
- IDENTITY strategy (ObjectBigIntIdIdentityGenerator)
- SEQUENCE strategy (ObjectBigIntIdSequenceStyleGenerator)

Tested with both PostgreSQL and MySQL databases.

Environment

- Java 25: OpenJDK 25 2025-09-16 LTS (Temurin-25+36)
- Hibernate: 6.6.33.Final
- Spring Boot: 3.5.7

Impact

- ✅ No breaking changes - fully backward compatible
- ✅ No API changes - internal implementation only
- ✅ Enables Java 25 LTS support for the library

Notes

This issue appears to be a Hibernate 6.6 behavior change when running on Java 25, possibly related to:
- JEP 507: Primitive Types in Patterns, instanceof, and switch
- Java 25 type system or reflection changes
- Hibernate's type resolution logic on newer JDKs

Consider reporting to Hibernate project as a potential compatibility issue.

On Java 25, Hibernate 6.6 wraps ObjectBigIntId in BasicTypeImpl with SerializableJavaType instead of CustomType wrapper used on Java 21.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant