-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1b602fc
commit 96d6ab7
Showing
15 changed files
with
1,148 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
plugins { | ||
id("framefork.java-public") | ||
} | ||
|
||
dependencies { | ||
api(project(":typed-ids")) | ||
api(libs.hibernate.orm.v62) | ||
api(libs.hypersistence.utils.hibernate62) | ||
api(libs.ateoClassindex) | ||
|
||
compileOnly(libs.jetbrains.annotations) | ||
|
||
compileOnly(libs.autoService.annotations) | ||
annotationProcessor(libs.autoService.processor) | ||
|
||
testImplementation(project(":typed-ids-testing")) | ||
testRuntimeOnly("org.junit.platform:junit-platform-launcher") | ||
} | ||
|
||
project.description = "TypeIds seamless integration into Hibernate ORMs type system" |
127 changes: 127 additions & 0 deletions
127
...hibernate-62/src/main/java/org/framefork/typedIds/uuid/hibernate/ObjectUuidArrayType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package org.framefork.typedIds.uuid.hibernate; | ||
|
||
import io.hypersistence.utils.hibernate.type.array.internal.AbstractArrayType; | ||
import io.hypersistence.utils.hibernate.type.array.internal.AbstractArrayTypeDescriptor; | ||
import io.hypersistence.utils.hibernate.type.array.internal.ArrayUtil; | ||
import io.hypersistence.utils.hibernate.type.util.ParameterizedParameterType; | ||
import org.framefork.typedIds.uuid.ObjectUuid; | ||
import org.hibernate.HibernateException; | ||
import org.hibernate.type.descriptor.WrapperOptions; | ||
import org.hibernate.usertype.DynamicParameterizedType; | ||
|
||
import java.sql.Array; | ||
import java.sql.SQLException; | ||
import java.util.Arrays; | ||
import java.util.Properties; | ||
import java.util.UUID; | ||
|
||
public class ObjectUuidArrayType<T extends ObjectUuid<T>> extends AbstractArrayType<T[]> | ||
{ | ||
|
||
public ObjectUuidArrayType( | ||
final Class<T[]> arrayClass, | ||
final ObjectUuidType objectUuidType | ||
) | ||
{ | ||
super( | ||
new ObjectUUIDArrayTypeDescriptor<>(arrayClass, objectUuidType) | ||
); | ||
var parameters = new Properties(); | ||
parameters.put(DynamicParameterizedType.PARAMETER_TYPE, new ParameterizedParameterType(arrayClass)); | ||
parameters.put(SQL_ARRAY_TYPE, getJavaTypeDescriptor().getSqlArrayType()); | ||
setParameterValues(parameters); | ||
} | ||
|
||
public String[] getRegistrationKeys() | ||
{ | ||
return new String[]{ | ||
returnedClass().getName(), | ||
returnedClass().getTypeName(), | ||
returnedClass().getCanonicalName(), | ||
}; | ||
} | ||
|
||
@Override | ||
public ObjectUUIDArrayTypeDescriptor<T> getJavaTypeDescriptor() | ||
{ | ||
return (ObjectUUIDArrayTypeDescriptor<T>) super.getJavaTypeDescriptor(); | ||
} | ||
|
||
public static <R extends ObjectUuid<R>> ObjectUuidArrayType<R> create( | ||
final Class<R> elementClass, | ||
final ObjectUuidType objectUuidType | ||
) | ||
{ | ||
return new ObjectUuidArrayType<>( | ||
ArrayUtil.toArrayClass(elementClass), | ||
objectUuidType | ||
); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public static final class ObjectUUIDArrayTypeDescriptor<T extends ObjectUuid<T>> extends AbstractArrayTypeDescriptor<T[]> | ||
{ | ||
|
||
private final ObjectUuidJavaType objectUuidJavaType; | ||
|
||
public ObjectUUIDArrayTypeDescriptor( | ||
final Class<T[]> arrayObjectClass, | ||
final ObjectUuidType objectUuidType | ||
) | ||
{ | ||
super(arrayObjectClass); | ||
this.objectUuidJavaType = objectUuidType.getExpressibleJavaType(); | ||
} | ||
|
||
@Override | ||
protected String getSqlArrayType() | ||
{ | ||
return "uuid"; | ||
} | ||
|
||
@Override | ||
public <X> X unwrap( | ||
final T[] value, | ||
final Class<X> type, | ||
final WrapperOptions options | ||
) | ||
{ | ||
if (value.length > 0) { | ||
@SuppressWarnings("unchecked") | ||
var result = (X) Arrays.stream(value) | ||
.map(item -> objectUuidJavaType.unwrap(item, UUID.class, options)) | ||
.toArray(UUID[]::new); | ||
|
||
return result; | ||
} | ||
|
||
return super.unwrap(value, type, options); | ||
} | ||
|
||
@Override | ||
public <X> T[] wrap( | ||
final X value, | ||
final WrapperOptions options | ||
) | ||
{ | ||
if (value instanceof Array array) { | ||
try { | ||
var uuidsArray = ArrayUtil.unwrapArray((Object[]) array.getArray(), Object[].class); | ||
|
||
var objectUuidsArray = Arrays.stream(uuidsArray) | ||
.map(item -> objectUuidJavaType.wrap(item, options)) | ||
.toArray(Object[]::new); | ||
|
||
return ArrayUtil.unwrapArray(objectUuidsArray, getJavaTypeClass()); | ||
|
||
} catch (SQLException e) { | ||
throw new HibernateException(new IllegalArgumentException(e)); | ||
} | ||
} | ||
|
||
return super.wrap(value, options); | ||
} | ||
|
||
} | ||
|
||
} |
183 changes: 183 additions & 0 deletions
183
...-hibernate-62/src/main/java/org/framefork/typedIds/uuid/hibernate/ObjectUuidJavaType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
package org.framefork.typedIds.uuid.hibernate; | ||
|
||
import org.framefork.typedIds.uuid.ObjectUuid; | ||
import org.framefork.typedIds.uuid.ObjectUuidTypeUtils; | ||
import org.hibernate.dialect.Dialect; | ||
import org.hibernate.engine.jdbc.Size; | ||
import org.hibernate.type.SqlTypes; | ||
import org.hibernate.type.descriptor.WrapperOptions; | ||
import org.hibernate.type.descriptor.java.BasicJavaType; | ||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan; | ||
import org.hibernate.type.descriptor.java.MutabilityPlan; | ||
import org.hibernate.type.descriptor.java.UUIDJavaType; | ||
import org.hibernate.type.descriptor.jdbc.AdjustableJdbcType; | ||
import org.hibernate.type.descriptor.jdbc.JdbcType; | ||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; | ||
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; | ||
import org.hibernate.usertype.DynamicParameterizedType; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.io.ObjectInputStream; | ||
import java.io.ObjectOutputStream; | ||
import java.io.Serializable; | ||
import java.lang.invoke.MethodHandle; | ||
import java.lang.reflect.Type; | ||
import java.util.Objects; | ||
import java.util.Properties; | ||
import java.util.UUID; | ||
|
||
public class ObjectUuidJavaType implements BasicJavaType<ObjectUuid<?>>, DynamicParameterizedType, Serializable | ||
{ | ||
|
||
public static final int UUID_BYTE_LENGTH = 16; | ||
|
||
private final UUIDJavaType inner; | ||
|
||
@Nullable | ||
private Class<ObjectUuid<?>> identifierClass; | ||
@Nullable | ||
private MethodHandle constructor; | ||
|
||
public ObjectUuidJavaType() | ||
{ | ||
this.inner = UUIDJavaType.INSTANCE; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public void setParameterValues(final Properties parameters) | ||
{ | ||
@Nullable var parameterType = (ParameterType) parameters.get(PARAMETER_TYPE); | ||
if (parameterType != null) { | ||
this.identifierClass = (Class<ObjectUuid<?>>) parameterType.getReturnedClass(); | ||
|
||
} else { | ||
String entityClass = Objects.requireNonNull(parameters.get(ENTITY), "parameters.get(ENTITY) must not be null").toString(); | ||
String propertyName = Objects.requireNonNull(parameters.get(PROPERTY), "parameters.get(PROPERTY) must not be null").toString(); | ||
|
||
this.identifierClass = ObjectUuidTypeUtils.readIdentifierClass(entityClass, propertyName); | ||
} | ||
|
||
if (!ObjectUuid.class.isAssignableFrom(identifierClass)) { | ||
throw new IllegalArgumentException("Type %s is not a subtype of %s".formatted(identifierClass, ObjectUuid.class)); | ||
} | ||
|
||
this.constructor = ObjectUuidTypeUtils.getMainConstructor(identifierClass); | ||
} | ||
|
||
@Override | ||
public Type getJavaType() | ||
{ | ||
return getJavaTypeClass(); | ||
} | ||
|
||
@Override | ||
public Class<ObjectUuid<?>> getJavaTypeClass() | ||
{ | ||
return Objects.requireNonNull(identifierClass, "identifierClass must not be null"); | ||
} | ||
|
||
@Override | ||
public int extractHashCode(final ObjectUuid<?> value) | ||
{ | ||
return Objects.hashCode(value); | ||
} | ||
|
||
@Override | ||
public boolean areEqual( | ||
final ObjectUuid<?> one, | ||
final ObjectUuid<?> another | ||
) | ||
{ | ||
return Objects.equals(one, another); | ||
} | ||
|
||
@Override | ||
public JdbcType getRecommendedJdbcType(final JdbcTypeIndicators indicators) | ||
{ | ||
final JdbcType descriptor = indicators.getJdbcType(indicators.resolveJdbcTypeCode(SqlTypes.UUID)); | ||
return descriptor instanceof AdjustableJdbcType | ||
? ((AdjustableJdbcType) descriptor).resolveIndicatedType(indicators, this) | ||
: descriptor; | ||
} | ||
|
||
@Override | ||
public long getDefaultSqlLength(final Dialect dialect, final JdbcType jdbcType) | ||
{ | ||
if (jdbcType instanceof VarbinaryJdbcType) { | ||
return UUID_BYTE_LENGTH; | ||
} | ||
|
||
return Size.DEFAULT_LENGTH; | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public <X> X unwrap( | ||
@Nullable final ObjectUuid<?> value, | ||
@NotNull final Class<X> type, | ||
@NotNull final WrapperOptions options | ||
) | ||
{ | ||
if (value == null) { | ||
return null; | ||
} | ||
|
||
return inner.unwrap(value.toNativeUuid(), type, options); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public <X> ObjectUuid<?> wrap( | ||
@Nullable final X value, | ||
@NotNull final WrapperOptions options | ||
) | ||
{ | ||
if (value == null) { | ||
return null; | ||
} | ||
|
||
return wrapUuidToIdentifier(inner.wrap(value, options)); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public ObjectUuid<?> fromString(@Nullable final CharSequence string) | ||
{ | ||
return (string == null) ? null : wrapUuidToIdentifier(UUID.fromString(string.toString())); | ||
} | ||
|
||
@Override | ||
public MutabilityPlan<ObjectUuid<?>> getMutabilityPlan() | ||
{ | ||
return ImmutableMutabilityPlan.instance(); | ||
} | ||
|
||
private ObjectUuid<?> wrapUuidToIdentifier(final UUID uuid) | ||
{ | ||
return ObjectUuidTypeUtils.wrapUuidToIdentifier( | ||
uuid, | ||
Objects.requireNonNull(constructor, "constructor was not yet initialized") | ||
); | ||
} | ||
|
||
@Override | ||
public String toString() | ||
{ | ||
return "object-uuid(%s)".formatted(identifierClass != null ? identifierClass.getName() : "???"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
private void writeObject(final ObjectOutputStream stream) | ||
{ | ||
throw new UnsupportedOperationException("Serialization not supported"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
private void readObject(final ObjectInputStream stream) | ||
{ | ||
throw new UnsupportedOperationException("Serialization not supported"); | ||
} | ||
|
||
} |
Oops, something went wrong.