Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,9 @@ else if ( aggregateComponent != null ) {
}

public void fillSimpleValue() {

basicValue.setMemberDetails( memberDetails );

basicValue.setExplicitTypeParams( explicitLocalCustomTypeParams );

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
76 changes: 64 additions & 12 deletions hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
import java.util.function.Consumer;
import java.util.function.Function;

import org.hibernate.AnnotationException;
import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.models.spi.MemberDetails;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.TimeZoneStorageStrategy;
import org.hibernate.annotations.SoftDelete;
import org.hibernate.annotations.SoftDeleteType;
Expand Down Expand Up @@ -65,13 +68,15 @@
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware;
import org.hibernate.usertype.AnnotationBasedUserType;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.UserType;

import com.fasterxml.classmate.ResolvedType;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.EnumType;
import jakarta.persistence.TemporalType;
import org.hibernate.usertype.UserTypeCreationContext;

import static java.lang.Boolean.parseBoolean;
import static org.hibernate.boot.model.convert.spi.ConverterDescriptor.TYPE_NAME_PREFIX;
Expand All @@ -85,6 +90,7 @@

/**
* @author Steve Ebersole
* @author Yanming Zhou
*/
public class BasicValue extends SimpleValue
implements JdbcTypeIndicators, Resolvable, JpaAttributeConverterCreationContext {
Expand Down Expand Up @@ -1080,9 +1086,10 @@ public void setExplicitCustomType(Class<? extends UserType<?>> explicitCustomTyp
else {
final var typeProperties = getCustomTypeProperties();
final var typeAnnotation = getTypeAnnotation();
final var memberDetails = getMemberDetails();
resolution = new UserTypeResolution<>(
new CustomType<>(
getConfiguredUserTypeBean( explicitCustomType, typeProperties, typeAnnotation ),
getConfiguredUserTypeBean( explicitCustomType, typeProperties, typeAnnotation, memberDetails ),
getTypeConfiguration()
),
null,
Expand All @@ -1104,8 +1111,33 @@ private Properties getCustomTypeProperties() {
}

private UserType<?> getConfiguredUserTypeBean(
Class<? extends UserType<?>> explicitCustomType, Properties properties, Annotation typeAnnotation) {
final var typeInstance = instantiateUserType( explicitCustomType, properties, typeAnnotation );
Class<? extends UserType<?>> explicitCustomType, Properties properties, Annotation typeAnnotation, MemberDetails memberDetails) {
final var typeInstance = instantiateUserType( explicitCustomType, properties, typeAnnotation, memberDetails );

if ( typeInstance instanceof AnnotationBasedUserType<?, ?> ) {
if ( typeAnnotation == null ) {
throw new AnnotationException( String.format( "'UserType' implementation '%s' implements '%s' but no custom annotation present,"
+ " please refer to the Javadoc of '%s'.",
typeInstance.getClass().getName(), AnnotationBasedUserType.class.getName(), UserType.class.getName() ) );
}
AnnotationBasedUserType<Annotation, ?> annotationBased = (AnnotationBasedUserType<Annotation, ?>) typeInstance;
annotationBased.initialize( typeAnnotation, new UserTypeCreationContext() {
@Override
public MetadataBuildingContext getBuildingContext() {
return BasicValue.this.getBuildingContext();
}

@Override
public ServiceRegistry getServiceRegistry() {
return BasicValue.this.getServiceRegistry();
}

@Override
public MemberDetails getMemberDetails() {
return memberDetails;
}
} );
}

if ( typeInstance instanceof TypeConfigurationAware configurationAware ) {
configurationAware.setTypeConfiguration( getTypeConfiguration() );
Expand All @@ -1127,21 +1159,41 @@ private UserType<?> getConfiguredUserTypeBean(
}

private <T extends UserType<?>> T instantiateUserType(
Class<T> customType, Properties properties, Annotation typeAnnotation) {
if ( typeAnnotation != null ) {
// attempt to instantiate it with the annotation as a constructor argument
Class<T> customType, Properties properties, Annotation typeAnnotation, MemberDetails memberDetails ) {
try {
// attempt to instantiate it with the member as a constructor argument
try {
final var constructor = customType.getDeclaredConstructor( typeAnnotation.annotationType() );
final var constructor = customType.getDeclaredConstructor( MemberDetails.class );
constructor.setAccessible( true );
return constructor.newInstance( typeAnnotation );
return constructor.newInstance( memberDetails );
}
catch ( NoSuchMethodException ignored ) {
// no such constructor, instantiate it the old way
catch (NoSuchMethodException ignored) {
}
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new org.hibernate.InstantiationException( "Could not instantiate custom type", customType, e );

if ( typeAnnotation != null ) {
// attempt to instantiate it with the annotation as a constructor argument
try {
final var constructor = customType.getDeclaredConstructor( typeAnnotation.annotationType() );
constructor.setAccessible( true );
return constructor.newInstance( typeAnnotation );
}
catch (NoSuchMethodException ignored) {
// attempt to instantiate it with the annotation and member as constructor arguments
try {
final var constructor = customType.getDeclaredConstructor( typeAnnotation.annotationType(),
MemberDetails.class );
constructor.setAccessible( true );
return constructor.newInstance( typeAnnotation, memberDetails );
}
catch (NoSuchMethodException ignored_) {
// no such constructor, instantiate it the old way
}
}
}
}
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new org.hibernate.InstantiationException( "Could not instantiate custom type", customType, e );
}

return getBuildingContext().getBuildingOptions().isAllowExtensionsInCdi()
? getUserTypeBean( customType, properties ).getBeanInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public abstract class SimpleValue implements KeyValue {
private String typeName;
private Properties typeParameters;
private Annotation typeAnnotation;
private MemberDetails memberDetails;
private boolean isVersion;
private boolean isNationalized;
private boolean isLob;
Expand Down Expand Up @@ -135,6 +136,7 @@ protected SimpleValue(SimpleValue original) {
this.typeName = original.typeName;
this.typeParameters = original.typeParameters == null ? null : new Properties( original.typeParameters );
this.typeAnnotation = original.typeAnnotation;
this.memberDetails = original.memberDetails;
this.isVersion = original.isVersion;
this.isNationalized = original.isNationalized;
this.isLob = original.isLob;
Expand Down Expand Up @@ -809,6 +811,10 @@ public void setTypeAnnotation(Annotation typeAnnotation) {
this.typeAnnotation = typeAnnotation;
}

public void setMemberDetails(MemberDetails memberDetails) {
this.memberDetails = memberDetails;
}

public Properties getTypeParameters() {
return typeParameters;
}
Expand All @@ -817,6 +823,10 @@ public Annotation getTypeAnnotation() {
return typeAnnotation;
}

public MemberDetails getMemberDetails() {
return memberDetails;
}

public void copyTypeFrom(SimpleValue sourceValue ) {
setTypeName( sourceValue.getTypeName() );
setTypeParameters( sourceValue.getTypeParameters() );
Expand All @@ -840,6 +850,7 @@ public boolean isSame(SimpleValue other) {
&& Objects.equals( typeName, other.typeName )
&& Objects.equals( typeParameters, other.typeParameters )
&& Objects.equals( typeAnnotation, other.typeAnnotation )
&& Objects.equals( memberDetails, other.memberDetails )
&& Objects.equals( table, other.table )
&& Objects.equals( foreignKeyName, other.foreignKeyName )
&& Objects.equals( foreignKeyDefinition, other.foreignKeyDefinition );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.usertype;

import org.hibernate.Incubating;

import java.lang.annotation.Annotation;


/**
* A {@link UserType} which receives parameters from a custom annotation.
*
* @param <A> The user type annotation type supported by an implementation
* @param <J> The java type
*
* @author Yanming Zhou
*
* @since 7.3
*/
@Incubating
public interface AnnotationBasedUserType<A extends Annotation, J> extends UserType<J> {
/**
* Initializes this generation strategy for the given annotation instance.
*
* @param annotation an instance of the user type annotation type. Typically,
* implementations will retrieve the annotation's attribute
* values and store them in fields.
* @param context a {@link UserTypeCreationContext}.
* @throws org.hibernate.HibernateException in case an error occurred during initialization, e.g. if
* an implementation can't create a value for the given property type.
*/
void initialize(A annotation, UserTypeCreationContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.models.spi.MemberDetails;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.jdbc.JdbcType;

Expand Down Expand Up @@ -214,8 +215,9 @@
* }
* </pre>
* <p>
* Every implementor of {@code UserType} must be immutable and must
* declare a public default constructor.
* Every implementor of {@code UserType} must be immutable and could
* declare a constructor accepts the {@link MemberDetails},
* or the annotation type, or the annotation type and the {@link MemberDetails}.
* <p>
* A custom type implemented as a {@code UserType} is treated as a
* non-composite value, and does not have persistent attributes which
Expand All @@ -242,6 +244,7 @@
*
* @see org.hibernate.type.Type
* @see org.hibernate.type.CustomType
* @see org.hibernate.usertype.AnnotationBasedUserType
*
* @see org.hibernate.annotations.Type
* @see org.hibernate.annotations.TypeRegistration
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.usertype;

import org.hibernate.Incubating;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.models.spi.MemberDetails;
import org.hibernate.service.ServiceRegistry;

/**
* Access to information useful during {@linkplain UserType} creation and initialization.
*
* @author Yanming Zhou
* @see AnnotationBasedUserType
*
* @since 7.3
*/
@Incubating
public interface UserTypeCreationContext {
/**
* Access to the {@link MetadataBuildingContext}.
*/
MetadataBuildingContext getBuildingContext();

/**
* Access to available services.
*/
ServiceRegistry getServiceRegistry();

/**
* Access to the {@link MemberDetails}.
*/
MemberDetails getMemberDetails();

}
Loading