Skip to content

Commit 96d6ab7

Browse files
committed
add typed-ids-hibernate-62
1 parent 1b602fc commit 96d6ab7

File tree

15 files changed

+1148
-5
lines changed

15 files changed

+1148
-5
lines changed

gradle/libs.versions.toml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ hibernate-orm-v63 = { group = "org.hibernate.orm", name = "hibernate-core", vers
3737
hibernate-orm-v64 = { group = "org.hibernate.orm", name = "hibernate-core", version = "6.4.10.Final" }
3838
hibernate-orm-v65 = { group = "org.hibernate.orm", name = "hibernate-core", version = "6.5.3.Final" }
3939
hibernate-orm-v66 = { group = "org.hibernate.orm", name = "hibernate-core", version = "6.6.2.Final" }
40-
hypersistence-utils-hibernate55 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-63", version = "3.8.3" }
41-
hypersistence-utils-hibernate60 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-63", version = "3.8.3" }
42-
hypersistence-utils-hibernate62 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-63", version = "3.8.3" }
40+
hypersistence-utils-hibernate55 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-55", version = "3.8.3" }
41+
hypersistence-utils-hibernate60 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-60", version = "3.8.3" }
42+
hypersistence-utils-hibernate62 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-62", version = "3.8.3" }
4343
hypersistence-utils-hibernate63 = { group = "io.hypersistence", name = "hypersistence-utils-hibernate-63", version = "3.8.3" }
44-
45-
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
plugins {
2+
id("framefork.java-public")
3+
}
4+
5+
dependencies {
6+
api(project(":typed-ids"))
7+
api(libs.hibernate.orm.v62)
8+
api(libs.hypersistence.utils.hibernate62)
9+
api(libs.ateoClassindex)
10+
11+
compileOnly(libs.jetbrains.annotations)
12+
13+
compileOnly(libs.autoService.annotations)
14+
annotationProcessor(libs.autoService.processor)
15+
16+
testImplementation(project(":typed-ids-testing"))
17+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
18+
}
19+
20+
project.description = "TypeIds seamless integration into Hibernate ORMs type system"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package org.framefork.typedIds.uuid.hibernate;
2+
3+
import io.hypersistence.utils.hibernate.type.array.internal.AbstractArrayType;
4+
import io.hypersistence.utils.hibernate.type.array.internal.AbstractArrayTypeDescriptor;
5+
import io.hypersistence.utils.hibernate.type.array.internal.ArrayUtil;
6+
import io.hypersistence.utils.hibernate.type.util.ParameterizedParameterType;
7+
import org.framefork.typedIds.uuid.ObjectUuid;
8+
import org.hibernate.HibernateException;
9+
import org.hibernate.type.descriptor.WrapperOptions;
10+
import org.hibernate.usertype.DynamicParameterizedType;
11+
12+
import java.sql.Array;
13+
import java.sql.SQLException;
14+
import java.util.Arrays;
15+
import java.util.Properties;
16+
import java.util.UUID;
17+
18+
public class ObjectUuidArrayType<T extends ObjectUuid<T>> extends AbstractArrayType<T[]>
19+
{
20+
21+
public ObjectUuidArrayType(
22+
final Class<T[]> arrayClass,
23+
final ObjectUuidType objectUuidType
24+
)
25+
{
26+
super(
27+
new ObjectUUIDArrayTypeDescriptor<>(arrayClass, objectUuidType)
28+
);
29+
var parameters = new Properties();
30+
parameters.put(DynamicParameterizedType.PARAMETER_TYPE, new ParameterizedParameterType(arrayClass));
31+
parameters.put(SQL_ARRAY_TYPE, getJavaTypeDescriptor().getSqlArrayType());
32+
setParameterValues(parameters);
33+
}
34+
35+
public String[] getRegistrationKeys()
36+
{
37+
return new String[]{
38+
returnedClass().getName(),
39+
returnedClass().getTypeName(),
40+
returnedClass().getCanonicalName(),
41+
};
42+
}
43+
44+
@Override
45+
public ObjectUUIDArrayTypeDescriptor<T> getJavaTypeDescriptor()
46+
{
47+
return (ObjectUUIDArrayTypeDescriptor<T>) super.getJavaTypeDescriptor();
48+
}
49+
50+
public static <R extends ObjectUuid<R>> ObjectUuidArrayType<R> create(
51+
final Class<R> elementClass,
52+
final ObjectUuidType objectUuidType
53+
)
54+
{
55+
return new ObjectUuidArrayType<>(
56+
ArrayUtil.toArrayClass(elementClass),
57+
objectUuidType
58+
);
59+
}
60+
61+
@SuppressWarnings("unchecked")
62+
public static final class ObjectUUIDArrayTypeDescriptor<T extends ObjectUuid<T>> extends AbstractArrayTypeDescriptor<T[]>
63+
{
64+
65+
private final ObjectUuidJavaType objectUuidJavaType;
66+
67+
public ObjectUUIDArrayTypeDescriptor(
68+
final Class<T[]> arrayObjectClass,
69+
final ObjectUuidType objectUuidType
70+
)
71+
{
72+
super(arrayObjectClass);
73+
this.objectUuidJavaType = objectUuidType.getExpressibleJavaType();
74+
}
75+
76+
@Override
77+
protected String getSqlArrayType()
78+
{
79+
return "uuid";
80+
}
81+
82+
@Override
83+
public <X> X unwrap(
84+
final T[] value,
85+
final Class<X> type,
86+
final WrapperOptions options
87+
)
88+
{
89+
if (value.length > 0) {
90+
@SuppressWarnings("unchecked")
91+
var result = (X) Arrays.stream(value)
92+
.map(item -> objectUuidJavaType.unwrap(item, UUID.class, options))
93+
.toArray(UUID[]::new);
94+
95+
return result;
96+
}
97+
98+
return super.unwrap(value, type, options);
99+
}
100+
101+
@Override
102+
public <X> T[] wrap(
103+
final X value,
104+
final WrapperOptions options
105+
)
106+
{
107+
if (value instanceof Array array) {
108+
try {
109+
var uuidsArray = ArrayUtil.unwrapArray((Object[]) array.getArray(), Object[].class);
110+
111+
var objectUuidsArray = Arrays.stream(uuidsArray)
112+
.map(item -> objectUuidJavaType.wrap(item, options))
113+
.toArray(Object[]::new);
114+
115+
return ArrayUtil.unwrapArray(objectUuidsArray, getJavaTypeClass());
116+
117+
} catch (SQLException e) {
118+
throw new HibernateException(new IllegalArgumentException(e));
119+
}
120+
}
121+
122+
return super.wrap(value, options);
123+
}
124+
125+
}
126+
127+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package org.framefork.typedIds.uuid.hibernate;
2+
3+
import org.framefork.typedIds.uuid.ObjectUuid;
4+
import org.framefork.typedIds.uuid.ObjectUuidTypeUtils;
5+
import org.hibernate.dialect.Dialect;
6+
import org.hibernate.engine.jdbc.Size;
7+
import org.hibernate.type.SqlTypes;
8+
import org.hibernate.type.descriptor.WrapperOptions;
9+
import org.hibernate.type.descriptor.java.BasicJavaType;
10+
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
11+
import org.hibernate.type.descriptor.java.MutabilityPlan;
12+
import org.hibernate.type.descriptor.java.UUIDJavaType;
13+
import org.hibernate.type.descriptor.jdbc.AdjustableJdbcType;
14+
import org.hibernate.type.descriptor.jdbc.JdbcType;
15+
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
16+
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
17+
import org.hibernate.usertype.DynamicParameterizedType;
18+
import org.jetbrains.annotations.NotNull;
19+
import org.jetbrains.annotations.Nullable;
20+
21+
import java.io.ObjectInputStream;
22+
import java.io.ObjectOutputStream;
23+
import java.io.Serializable;
24+
import java.lang.invoke.MethodHandle;
25+
import java.lang.reflect.Type;
26+
import java.util.Objects;
27+
import java.util.Properties;
28+
import java.util.UUID;
29+
30+
public class ObjectUuidJavaType implements BasicJavaType<ObjectUuid<?>>, DynamicParameterizedType, Serializable
31+
{
32+
33+
public static final int UUID_BYTE_LENGTH = 16;
34+
35+
private final UUIDJavaType inner;
36+
37+
@Nullable
38+
private Class<ObjectUuid<?>> identifierClass;
39+
@Nullable
40+
private MethodHandle constructor;
41+
42+
public ObjectUuidJavaType()
43+
{
44+
this.inner = UUIDJavaType.INSTANCE;
45+
}
46+
47+
@SuppressWarnings("unchecked")
48+
@Override
49+
public void setParameterValues(final Properties parameters)
50+
{
51+
@Nullable var parameterType = (ParameterType) parameters.get(PARAMETER_TYPE);
52+
if (parameterType != null) {
53+
this.identifierClass = (Class<ObjectUuid<?>>) parameterType.getReturnedClass();
54+
55+
} else {
56+
String entityClass = Objects.requireNonNull(parameters.get(ENTITY), "parameters.get(ENTITY) must not be null").toString();
57+
String propertyName = Objects.requireNonNull(parameters.get(PROPERTY), "parameters.get(PROPERTY) must not be null").toString();
58+
59+
this.identifierClass = ObjectUuidTypeUtils.readIdentifierClass(entityClass, propertyName);
60+
}
61+
62+
if (!ObjectUuid.class.isAssignableFrom(identifierClass)) {
63+
throw new IllegalArgumentException("Type %s is not a subtype of %s".formatted(identifierClass, ObjectUuid.class));
64+
}
65+
66+
this.constructor = ObjectUuidTypeUtils.getMainConstructor(identifierClass);
67+
}
68+
69+
@Override
70+
public Type getJavaType()
71+
{
72+
return getJavaTypeClass();
73+
}
74+
75+
@Override
76+
public Class<ObjectUuid<?>> getJavaTypeClass()
77+
{
78+
return Objects.requireNonNull(identifierClass, "identifierClass must not be null");
79+
}
80+
81+
@Override
82+
public int extractHashCode(final ObjectUuid<?> value)
83+
{
84+
return Objects.hashCode(value);
85+
}
86+
87+
@Override
88+
public boolean areEqual(
89+
final ObjectUuid<?> one,
90+
final ObjectUuid<?> another
91+
)
92+
{
93+
return Objects.equals(one, another);
94+
}
95+
96+
@Override
97+
public JdbcType getRecommendedJdbcType(final JdbcTypeIndicators indicators)
98+
{
99+
final JdbcType descriptor = indicators.getJdbcType(indicators.resolveJdbcTypeCode(SqlTypes.UUID));
100+
return descriptor instanceof AdjustableJdbcType
101+
? ((AdjustableJdbcType) descriptor).resolveIndicatedType(indicators, this)
102+
: descriptor;
103+
}
104+
105+
@Override
106+
public long getDefaultSqlLength(final Dialect dialect, final JdbcType jdbcType)
107+
{
108+
if (jdbcType instanceof VarbinaryJdbcType) {
109+
return UUID_BYTE_LENGTH;
110+
}
111+
112+
return Size.DEFAULT_LENGTH;
113+
}
114+
115+
@Nullable
116+
@Override
117+
public <X> X unwrap(
118+
@Nullable final ObjectUuid<?> value,
119+
@NotNull final Class<X> type,
120+
@NotNull final WrapperOptions options
121+
)
122+
{
123+
if (value == null) {
124+
return null;
125+
}
126+
127+
return inner.unwrap(value.toNativeUuid(), type, options);
128+
}
129+
130+
@Nullable
131+
@Override
132+
public <X> ObjectUuid<?> wrap(
133+
@Nullable final X value,
134+
@NotNull final WrapperOptions options
135+
)
136+
{
137+
if (value == null) {
138+
return null;
139+
}
140+
141+
return wrapUuidToIdentifier(inner.wrap(value, options));
142+
}
143+
144+
@Nullable
145+
@Override
146+
public ObjectUuid<?> fromString(@Nullable final CharSequence string)
147+
{
148+
return (string == null) ? null : wrapUuidToIdentifier(UUID.fromString(string.toString()));
149+
}
150+
151+
@Override
152+
public MutabilityPlan<ObjectUuid<?>> getMutabilityPlan()
153+
{
154+
return ImmutableMutabilityPlan.instance();
155+
}
156+
157+
private ObjectUuid<?> wrapUuidToIdentifier(final UUID uuid)
158+
{
159+
return ObjectUuidTypeUtils.wrapUuidToIdentifier(
160+
uuid,
161+
Objects.requireNonNull(constructor, "constructor was not yet initialized")
162+
);
163+
}
164+
165+
@Override
166+
public String toString()
167+
{
168+
return "object-uuid(%s)".formatted(identifierClass != null ? identifierClass.getName() : "???");
169+
}
170+
171+
@SuppressWarnings("unused")
172+
private void writeObject(final ObjectOutputStream stream)
173+
{
174+
throw new UnsupportedOperationException("Serialization not supported");
175+
}
176+
177+
@SuppressWarnings("unused")
178+
private void readObject(final ObjectInputStream stream)
179+
{
180+
throw new UnsupportedOperationException("Serialization not supported");
181+
}
182+
183+
}

0 commit comments

Comments
 (0)