Skip to content

Commit beddb1a

Browse files
committed
Add support for TSID #526
1 parent 8ef1d34 commit beddb1a

File tree

15 files changed

+900
-20
lines changed

15 files changed

+900
-20
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,9 @@ Or, if you prefer reading books, you are going to love my [High-Performance Java
408408

409409
#### Contributing Guide
410410

411-
The project uses [Maven Toolchains](https://maven.apache.org/guides/mini/guide-using-toolchains.html) as different modules are compiled and tested using different Java versions. Hypersistence Utils 6 requires Java 17 while the other modules are compiled with either Java 1.8 or 1.6.
411+
The project uses [Maven Toolchains](https://maven.apache.org/guides/mini/guide-using-toolchains.html) as different modules are compiled and tested using different Java versions.
412+
413+
Hypersistence Utils 6 requires Java 11 while the other modules are compiled with Java 8.
412414

413415
To see how to configure Maven Toolchains, check out [this article](https://vladmihalcea.com/maven-and-java-multi-version-modules/).
414416

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.hypersistence.utils.hibernate.id;
2+
3+
import io.hypersistence.tsid.TSID;
4+
import io.hypersistence.utils.hibernate.util.ReflectionUtils;
5+
import org.hibernate.HibernateException;
6+
import org.hibernate.MappingException;
7+
import org.hibernate.engine.spi.SessionImplementor;
8+
import org.hibernate.id.Configurable;
9+
import org.hibernate.id.IdentifierGenerator;
10+
import org.hibernate.internal.util.config.ConfigurationHelper;
11+
import org.hibernate.service.ServiceRegistry;
12+
import org.hibernate.type.Type;
13+
14+
import java.io.Serializable;
15+
import java.util.Properties;
16+
import java.util.function.Supplier;
17+
18+
/**
19+
* @author Vlad Mihalcea
20+
*/
21+
public class TsidGenerator implements IdentifierGenerator, Configurable {
22+
23+
private TSID.Factory DEFAULT_TSID_FACTORY = TSID.Factory.builder()
24+
.withRandomFunction(TSID.Factory.THREAD_LOCAL_RANDOM_FUNCTION)
25+
.build();
26+
27+
/**
28+
* Indicates the name of the TSID.Factory Supplier.
29+
*/
30+
public static final String TSID_FACTORY_SUPPLIER_PARAM = "tsid_factory_supplier";
31+
32+
private TSID.Factory tsidFactory = DEFAULT_TSID_FACTORY;
33+
34+
private AttributeType idType;
35+
36+
@Override
37+
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry)
38+
throws MappingException {
39+
idType = AttributeType.valueOf(type.getReturnedClass());
40+
41+
String tsidSupplierClass = ConfigurationHelper.getString(TSID_FACTORY_SUPPLIER_PARAM, params);
42+
if (tsidSupplierClass != null) {
43+
Supplier<TSID.Factory> factorySupplier = ReflectionUtils.newInstance(tsidSupplierClass);
44+
tsidFactory = factorySupplier.get();
45+
}
46+
}
47+
48+
@Override
49+
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
50+
return idType.cast(tsidFactory.generate());
51+
}
52+
53+
enum AttributeType {
54+
LONG {
55+
@Override
56+
public Serializable cast(TSID tsid) {
57+
return tsid.toLong();
58+
}
59+
},
60+
STRING {
61+
@Override
62+
public Serializable cast(TSID tsid) {
63+
return tsid.toString();
64+
}
65+
},
66+
TSID {
67+
@Override
68+
public Serializable cast(TSID tsid) {
69+
return tsid;
70+
}
71+
};
72+
73+
public abstract Serializable cast(TSID tsid);
74+
75+
static AttributeType valueOf(Class clazz) {
76+
if(Long.class.isAssignableFrom(clazz)) {
77+
return LONG;
78+
} else if (String.class.isAssignableFrom(clazz)) {
79+
return STRING;
80+
} else if (TSID.class.isAssignableFrom(clazz)) {
81+
return TSID;
82+
} else {
83+
throw new HibernateException(
84+
String.format(
85+
"The @Tsid annotation on [%s] can only be placed on a Long or String entity attribute!",
86+
clazz
87+
)
88+
);
89+
}
90+
}
91+
}
92+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package io.hypersistence.utils.hibernate.id;
2+
3+
import io.hypersistence.tsid.TSID;
4+
import io.hypersistence.utils.hibernate.util.AbstractTest;
5+
import io.hypersistence.utils.hibernate.util.transaction.JPATransactionVoidFunction;
6+
import org.hibernate.annotations.GenericGenerator;
7+
import org.hibernate.annotations.Parameter;
8+
import org.junit.Test;
9+
10+
import javax.persistence.*;
11+
import java.util.function.Supplier;
12+
13+
public class TsidIdentifierTest extends AbstractTest {
14+
15+
@Override
16+
protected Class<?>[] entities() {
17+
return new Class<?>[] {
18+
Post.class,
19+
Tag.class
20+
};
21+
}
22+
23+
@Test
24+
public void test() {
25+
doInJPA(new JPATransactionVoidFunction() {
26+
@Override
27+
public void accept(EntityManager entityManager) {
28+
entityManager.persist(
29+
new Post()
30+
.setTitle("High-Performance Java Persistence")
31+
);
32+
entityManager.flush();
33+
entityManager.merge(
34+
new Post()
35+
.setTitle("High-Performance Java Persistence")
36+
);
37+
}
38+
});
39+
}
40+
41+
@Entity(name = "Post")
42+
@Table(name = "post")
43+
public static class Post {
44+
45+
@Id
46+
@GeneratedValue(generator = "tsid")
47+
@GenericGenerator(
48+
name = "tsid",
49+
strategy = "io.hypersistence.utils.hibernate.id.TsidGenerator"
50+
)
51+
private Long id;
52+
53+
private String title;
54+
55+
public Long getId() {
56+
return id;
57+
}
58+
59+
public Post setId(Long id) {
60+
this.id = id;
61+
return this;
62+
}
63+
64+
public String getTitle() {
65+
return title;
66+
}
67+
68+
public Post setTitle(String title) {
69+
this.title = title;
70+
return this;
71+
}
72+
}
73+
74+
@Entity(name = "Tag")
75+
@Table(name = "tag")
76+
public static class Tag {
77+
78+
@Id
79+
@GeneratedValue(generator = "tsid")
80+
@GenericGenerator(
81+
name = "tsid",
82+
strategy = "io.hypersistence.utils.hibernate.id.TsidGenerator",
83+
parameters = @Parameter(
84+
name = TsidGenerator.TSID_FACTORY_SUPPLIER_PARAM,
85+
value = "io.hypersistence.utils.hibernate.id.TsidIdentifierTest$CustomTsidSupplier"
86+
)
87+
)
88+
private Long id;
89+
90+
private String name;
91+
92+
public Long getId() {
93+
return id;
94+
}
95+
96+
public Tag setId(Long id) {
97+
this.id = id;
98+
return this;
99+
}
100+
101+
public String getName() {
102+
return name;
103+
}
104+
105+
public Tag setName(String name) {
106+
this.name = name;
107+
return this;
108+
}
109+
}
110+
111+
public static class CustomTsidSupplier implements Supplier<TSID.Factory> {
112+
113+
@Override
114+
public TSID.Factory get() {
115+
return TSID.Factory.builder()
116+
.withNodeBits(1)
117+
.build();
118+
}
119+
}
120+
}

hypersistence-utils-hibernate-5/src/test/java/io/hypersistence/utils/hibernate/util/AbstractTest.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@
4343
import javax.sql.DataSource;
4444
import java.io.Closeable;
4545
import java.io.IOException;
46-
import java.sql.Connection;
47-
import java.sql.SQLException;
4846
import java.util.*;
4947
import java.util.concurrent.ExecutorService;
5048
import java.util.concurrent.Executors;
@@ -467,12 +465,7 @@ protected <T> T doInJDBC(final ConnectionCallable<T> callable) {
467465
try {
468466
session = sessionFactory().openSession();
469467
txn = session.beginTransaction();
470-
session.doWork(new Work() {
471-
@Override
472-
public void execute(Connection connection) throws SQLException {
473-
result.set(callable.execute(connection));
474-
}
475-
});
468+
session.doWork(connection -> result.set(callable.execute(connection)));
476469
if (txn.getStatus() == TransactionStatus.ACTIVE) {
477470
txn.commit();
478471
} else {
@@ -505,12 +498,7 @@ protected void doInJDBC(final ConnectionVoidCallable callable) {
505498
try {
506499
session = sessionFactory().openSession();
507500
txn = session.beginTransaction();
508-
session.doWork(new Work() {
509-
@Override
510-
public void execute(Connection connection) throws SQLException {
511-
callable.execute(connection);
512-
}
513-
});
501+
session.doWork(connection -> callable.execute(connection));
514502
if (txn.getStatus() == TransactionStatus.ACTIVE) {
515503
txn.commit();
516504
} else {

hypersistence-utils-hibernate-52/pom.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,6 @@
162162
</dependencies>
163163

164164
<properties>
165-
<jdk.version>8</jdk.version>
166-
167165
<hibernate.version>5.4.33.Final</hibernate.version>
168166
<!--<hibernate.version>5.2.18.Final</hibernate.version>-->
169167

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.hypersistence.utils.hibernate.id;
2+
3+
import io.hypersistence.tsid.TSID;
4+
import io.hypersistence.utils.hibernate.util.ReflectionUtils;
5+
import org.hibernate.HibernateException;
6+
import org.hibernate.MappingException;
7+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
8+
import org.hibernate.id.Configurable;
9+
import org.hibernate.id.IdentifierGenerator;
10+
import org.hibernate.internal.util.config.ConfigurationHelper;
11+
import org.hibernate.service.ServiceRegistry;
12+
import org.hibernate.type.Type;
13+
14+
import java.io.Serializable;
15+
import java.util.Properties;
16+
import java.util.function.Supplier;
17+
18+
/**
19+
* @author Vlad Mihalcea
20+
*/
21+
public class TsidGenerator implements IdentifierGenerator, Configurable {
22+
23+
private TSID.Factory DEFAULT_TSID_FACTORY = TSID.Factory.builder()
24+
.withRandomFunction(TSID.Factory.THREAD_LOCAL_RANDOM_FUNCTION)
25+
.build();
26+
27+
/**
28+
* Indicates the name of the TSID.Factory Supplier.
29+
*/
30+
public static final String TSID_FACTORY_SUPPLIER_PARAM = "tsid_factory_supplier";
31+
32+
private TSID.Factory tsidFactory = DEFAULT_TSID_FACTORY;
33+
34+
private AttributeType idType;
35+
36+
@Override
37+
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry)
38+
throws MappingException {
39+
idType = AttributeType.valueOf(type.getReturnedClass());
40+
41+
String tsidSupplierClass = ConfigurationHelper.getString(TSID_FACTORY_SUPPLIER_PARAM, params);
42+
if (tsidSupplierClass != null) {
43+
Supplier<TSID.Factory> factorySupplier = ReflectionUtils.newInstance(tsidSupplierClass);
44+
tsidFactory = factorySupplier.get();
45+
}
46+
}
47+
48+
@Override
49+
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
50+
return idType.cast(tsidFactory.generate());
51+
}
52+
53+
enum AttributeType {
54+
LONG {
55+
@Override
56+
public Serializable cast(TSID tsid) {
57+
return tsid.toLong();
58+
}
59+
},
60+
STRING {
61+
@Override
62+
public Serializable cast(TSID tsid) {
63+
return tsid.toString();
64+
}
65+
},
66+
TSID {
67+
@Override
68+
public Serializable cast(TSID tsid) {
69+
return tsid;
70+
}
71+
};
72+
73+
public abstract Serializable cast(TSID tsid);
74+
75+
static AttributeType valueOf(Class clazz) {
76+
if(Long.class.isAssignableFrom(clazz)) {
77+
return LONG;
78+
} else if (String.class.isAssignableFrom(clazz)) {
79+
return STRING;
80+
} else if (TSID.class.isAssignableFrom(clazz)) {
81+
return TSID;
82+
} else {
83+
throw new HibernateException(
84+
String.format(
85+
"The @Tsid annotation on [%s] can only be placed on a Long or String entity attribute!",
86+
clazz
87+
)
88+
);
89+
}
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)