Skip to content

Commit 05c9dbc

Browse files
committed
upgrade testing-hibernate-native-alternatives to hibernate 7.0+
1 parent 2d4d378 commit 05c9dbc

File tree

12 files changed

+310
-4
lines changed

12 files changed

+310
-4
lines changed

.claude/settings.local.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(./gradlew:*)",
5+
"Bash(GRADLE_OPTS=\"-Dorg.gradle.console=plain -Dorg.gradle.stacktrace=always\" ./gradlew:*)",
6+
"Bash(find:*)",
7+
"Bash(grep:*)",
8+
"Bash(cat:*)",
9+
"Bash(mv:*)",
10+
"Bash(git --no-pager log -n 1 --stat -p)",
11+
"WebFetch(domain:hibernate.org)",
12+
"WebFetch(domain:docs.hibernate.org)",
13+
"WebFetch(domain:github.com)",
14+
"WebFetch(domain:docs.jboss.org)",
15+
"Bash(../../gradlew build)",
16+
"WebFetch(domain:docs.hypersistence.io)"
17+
],
18+
"deny": []
19+
},
20+
"enableAllProjectMcpServers": false
21+
}

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@ hibernate-orm-v63 = { group = "org.hibernate.orm", name = "hibernate-core", vers
3333
hibernate-orm-v64 = { group = "org.hibernate.orm", name = "hibernate-core", version = "6.4.10.Final" }
3434
hibernate-orm-v65 = { group = "org.hibernate.orm", name = "hibernate-core", version = "6.5.3.Final" }
3535
hibernate-orm-v66 = { group = "org.hibernate.orm", name = "hibernate-core", version = "6.6.26.Final" }
36+
hibernate-orm-v70 = { group = "org.hibernate.orm", name = "hibernate-core", version = "7.0.10.Final" }
37+
hibernate-orm-v71 = { group = "org.hibernate.orm", name = "hibernate-core", version = "7.1.0.Final" }
3638
hypersistence-utils-hibernate61 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-60", version = "3.9.4" }
3739
hypersistence-utils-hibernate62 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-62", version = "3.9.4" }
3840
hypersistence-utils-hibernate63 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-63", version = "3.10.3" }
41+
hypersistence-utils-hibernate70 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-70", version = "3.10.3" }
3942
hypersistence-tsid = { module = "io.hypersistence:hypersistence-tsid", version = "2.1.4" }
4043
kotlinx-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.7.0" }
4144
swagger-v3-core-jakarta = { module = "io.swagger.core.v3:swagger-core-jakarta", version = "2.2.35" }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
plugins {
2+
id("framefork.java")
3+
}
4+
5+
dependencies {
6+
api(project(":typed-ids-testing"))
7+
8+
api(libs.hibernate.orm.v70)
9+
api(libs.hypersistence.utils.hibernate70)
10+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.framefork.typedIds.hibernate.tests;
2+
3+
import io.hypersistence.utils.test.providers.DataSourceProvider;
4+
import org.testcontainers.containers.JdbcDatabaseContainer;
5+
6+
import javax.sql.DataSource;
7+
import java.util.Objects;
8+
import java.util.concurrent.atomic.AtomicReference;
9+
10+
public abstract class AbstractContainerDataSourceProvider implements DataSourceProvider
11+
{
12+
13+
private final AtomicReference<JdbcDatabaseContainer<?>> container = new AtomicReference<>();
14+
15+
public JdbcDatabaseContainer<?> getContainer()
16+
{
17+
if (container.get() == null) {
18+
synchronized (container) {
19+
if (container.get() == null) {
20+
container.set(initContainer());
21+
}
22+
}
23+
}
24+
25+
return Objects.requireNonNull(container.get(), "database container must not be null");
26+
}
27+
28+
private JdbcDatabaseContainer<?> initContainer()
29+
{
30+
var newContainer = (JdbcDatabaseContainer<?>) newJdbcDatabaseContainer();
31+
32+
if (supportsDatabaseName()) {
33+
newContainer.withDatabaseName(databaseName());
34+
}
35+
if (supportsCredentials()) {
36+
newContainer.withUsername(username()).withPassword(password());
37+
}
38+
39+
newContainer.withReuse(true).start();
40+
41+
return newContainer;
42+
}
43+
44+
@Override
45+
public final DataSource dataSource()
46+
{
47+
getContainer(); // force init
48+
return newDataSource();
49+
}
50+
51+
@Override
52+
public final String url()
53+
{
54+
return getContainer().getJdbcUrl();
55+
}
56+
57+
public String databaseName()
58+
{
59+
return "framefork";
60+
}
61+
62+
protected abstract DataSource newDataSource();
63+
64+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.framefork.typedIds.hibernate.tests;
2+
3+
import io.hypersistence.utils.test.AbstractHibernateTest;
4+
import io.hypersistence.utils.test.providers.DataSourceProvider;
5+
import org.junit.jupiter.api.AfterEach;
6+
import org.junit.jupiter.api.BeforeEach;
7+
8+
public abstract class AbstractMySQLIntegrationTest extends AbstractHibernateTest
9+
{
10+
11+
@BeforeEach
12+
@Override
13+
public void init()
14+
{
15+
super.init();
16+
}
17+
18+
@AfterEach
19+
@Override
20+
public void destroy()
21+
{
22+
super.destroy();
23+
}
24+
25+
@Override
26+
protected DataSourceProvider dataSourceProvider()
27+
{
28+
return MySQLDataSourceProvider.V8;
29+
}
30+
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.framefork.typedIds.hibernate.tests;
2+
3+
import io.hypersistence.utils.test.AbstractHibernateTest;
4+
import io.hypersistence.utils.test.providers.DataSourceProvider;
5+
import org.junit.jupiter.api.AfterEach;
6+
import org.junit.jupiter.api.BeforeEach;
7+
8+
public abstract class AbstractPostgreSQLIntegrationTest extends AbstractHibernateTest
9+
{
10+
11+
@BeforeEach
12+
@Override
13+
public void init()
14+
{
15+
super.init();
16+
}
17+
18+
@AfterEach
19+
@Override
20+
public void destroy()
21+
{
22+
super.destroy();
23+
}
24+
25+
@Override
26+
protected DataSourceProvider dataSourceProvider()
27+
{
28+
return PostgreSQLDataSourceProvider.V16;
29+
}
30+
31+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.framefork.typedIds.hibernate.tests;
2+
3+
import com.mysql.cj.jdbc.MysqlDataSource;
4+
import org.hibernate.dialect.Database;
5+
import org.hibernate.dialect.MySQLDialect;
6+
import org.testcontainers.containers.JdbcDatabaseContainer;
7+
import org.testcontainers.containers.MySQLContainer;
8+
9+
import javax.sql.DataSource;
10+
import java.util.Map;
11+
12+
public final class MySQLDataSourceProvider extends AbstractContainerDataSourceProvider
13+
{
14+
15+
public static final MySQLDataSourceProvider V8 = new MySQLDataSourceProvider("8.4");
16+
17+
private final String version;
18+
19+
private MySQLDataSourceProvider(final String version)
20+
{
21+
this.version = version;
22+
}
23+
24+
@Override
25+
public Database database()
26+
{
27+
return Database.MYSQL;
28+
}
29+
30+
@Override
31+
public String hibernateDialect()
32+
{
33+
return MySQLDialect.class.getName();
34+
}
35+
36+
@Override
37+
protected DataSource newDataSource()
38+
{
39+
var dataSource = new MysqlDataSource();
40+
dataSource.setURL(url());
41+
dataSource.setUser(username());
42+
dataSource.setPassword(password());
43+
return dataSource;
44+
}
45+
46+
@Override
47+
public String username()
48+
{
49+
return "mysql";
50+
}
51+
52+
@Override
53+
public String password()
54+
{
55+
return "admin";
56+
}
57+
58+
@SuppressWarnings({"rawtypes", "unchecked"})
59+
@Override
60+
public JdbcDatabaseContainer newJdbcDatabaseContainer()
61+
{
62+
var container = new MySQLContainer("mysql:" + version);
63+
container.withTmpFs(Map.of("/var/lib/mysql", "rw"));
64+
return container;
65+
}
66+
67+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package org.framefork.typedIds.hibernate.tests;
2+
3+
import org.hibernate.dialect.Database;
4+
import org.hibernate.dialect.PostgreSQLDialect;
5+
import org.postgresql.ds.PGSimpleDataSource;
6+
import org.testcontainers.containers.JdbcDatabaseContainer;
7+
import org.testcontainers.containers.PostgreSQLContainer;
8+
9+
import javax.sql.DataSource;
10+
import java.util.Map;
11+
12+
public final class PostgreSQLDataSourceProvider extends AbstractContainerDataSourceProvider
13+
{
14+
15+
public static final PostgreSQLDataSourceProvider V16 = new PostgreSQLDataSourceProvider("16.4");
16+
17+
private final String version;
18+
19+
private PostgreSQLDataSourceProvider(final String version)
20+
{
21+
this.version = version;
22+
}
23+
24+
@Override
25+
public Database database()
26+
{
27+
return Database.POSTGRESQL;
28+
}
29+
30+
@Override
31+
public String hibernateDialect()
32+
{
33+
return PostgreSQLDialect.class.getName();
34+
}
35+
36+
@Override
37+
protected DataSource newDataSource()
38+
{
39+
var dataSource = new PGSimpleDataSource();
40+
dataSource.setURL(url());
41+
dataSource.setUser(username());
42+
dataSource.setPassword(password());
43+
44+
return dataSource;
45+
}
46+
47+
@Override
48+
public String username()
49+
{
50+
return "postgres";
51+
}
52+
53+
@Override
54+
public String password()
55+
{
56+
return "admin";
57+
}
58+
59+
@SuppressWarnings({"rawtypes", "unchecked"})
60+
@Override
61+
public JdbcDatabaseContainer newJdbcDatabaseContainer()
62+
{
63+
var container = new PostgreSQLContainer("postgres:" + version);
64+
container.withCommand("postgres", "-c", "fsync=off", "-c", "random_page_cost=1.0", "-c", "synchronous_commit=off", "-c", "full_page_writes=off");
65+
container.withEnv(Map.of("PGDATA", "/var/lib/postgresql/data"));
66+
container.withTmpFs(Map.of("/var/lib/postgresql/data", "rw"));
67+
return container;
68+
}
69+
70+
}

testing/testing-hibernate-native-alternatives/README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The `framefork/typed-ids` library provides a comprehensive solution for strongly
2929

3030
## Alternative Approaches Analysis
3131

32-
### 1. @EmbeddedId with Java Records
32+
### 1. @EmbeddedId with Java Records (Not viable with Hibernate 7.0+)
3333

3434
**What it solves:**
3535
- ✅ Compile-time Type Safety
@@ -52,7 +52,7 @@ The `framefork/typed-ids` library provides a comprehensive solution for strongly
5252
- ✅ JPQL Querying: Both `WHERE e.id = :embeddableObject` and `WHERE e.id.value = :primitiveValue` work
5353
- ✅ SELECT NEW Constructor: Supports both direct embedded object mapping and inline constructor calls
5454

55-
### 2. @IdClass with Java Records
55+
### 2. @IdClass with Java Records (Not viable with Hibernate 7.0+)
5656

5757
**What it solves:**
5858
- ✅ Compile-time Type Safety
@@ -110,6 +110,11 @@ Hibernate treats both approaches as **composite identifiers** even when using si
110110

111111
The error message is identical: `"Identity generation isn't supported for composite ids"`
112112

113+
### Hibernate Version Regression
114+
**Note:** These native approaches that previously worked with Hibernate 6.6.x now fail consistently with Hibernate 7.0+ due to stricter composite identifier validation.
115+
This represents a regression in functionality where previously working code now fails at runtime,
116+
further emphasizing the value of the `framefork/typed-ids` library which maintains consistent behavior across Hibernate versions.
117+
113118
## Conclusion
114119

115120
This empirical analysis demonstrates that **native JPA/Hibernate approaches fail** when combining strongly-typed identifiers with database-generated keys.

testing/testing-hibernate-native-alternatives/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ plugins {
44

55
dependencies {
66
// Need Hibernate for JPA annotations, but not the typed-ids implementations
7-
implementation(libs.hibernate.orm.v66)
7+
implementation(libs.hibernate.orm.v71)
88
compileOnly(libs.jetbrains.annotations)
99

1010
// Only the testing infrastructure, not the actual typed-ids implementations
11-
testImplementation(project(":typed-ids-hibernate-63-testing"))
11+
testImplementation(project(":typed-ids-hibernate-70-testing"))
1212
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
1313
}

0 commit comments

Comments
 (0)