HHH-17181 Handle composite user type contributions
This commit is contained in:
parent
3660a62c73
commit
40261547bd
|
@ -84,6 +84,7 @@ import org.hibernate.type.BasicType;
|
|||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.WrapperArrayHandling;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
import org.jboss.jandex.IndexView;
|
||||
|
@ -315,6 +316,11 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
|
|||
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys, getTypeConfiguration() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeType(CompositeUserType<?> type) {
|
||||
options.compositeUserTypes.add( type );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeConfiguration getTypeConfiguration() {
|
||||
return bootstrapContext.getTypeConfiguration();
|
||||
|
@ -597,6 +603,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
|
|||
private BootstrapContext bootstrapContext;
|
||||
|
||||
private final ArrayList<BasicTypeRegistration> basicTypeRegistrations = new ArrayList<>();
|
||||
private final ArrayList<CompositeUserType<?>> compositeUserTypes = new ArrayList<>();
|
||||
|
||||
private ImplicitNamingStrategy implicitNamingStrategy;
|
||||
private PhysicalNamingStrategy physicalNamingStrategy;
|
||||
|
@ -885,6 +892,11 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
|
|||
return basicTypeRegistrations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompositeUserType<?>> getCompositeUserTypes() {
|
||||
return compositeUserTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeConfiguration getTypeConfiguration() {
|
||||
return bootstrapContext.getTypeConfiguration();
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
|
|||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
|
@ -60,6 +61,17 @@ public interface TypeContributions {
|
|||
contributeType( type, type.returnedClass().getName() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link CompositeUserType} as the implicit (auto-applied)
|
||||
* type for values of type {@link CompositeUserType#returnedClass()}.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
default void contributeType(CompositeUserType<?> type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an {@link AttributeConverter} class.
|
||||
*
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.hibernate.boot.jaxb.spi.BindableMappingDescriptor;
|
|||
import org.hibernate.boot.jaxb.spi.Binding;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.boot.model.convert.spi.ConverterRegistry;
|
||||
import org.hibernate.boot.model.process.internal.ManagedResourcesImpl;
|
||||
import org.hibernate.boot.model.process.internal.ScanningCoordinator;
|
||||
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
||||
|
@ -53,6 +52,7 @@ import org.hibernate.boot.spi.AdditionalJaxbMappingProducer;
|
|||
import org.hibernate.boot.spi.AdditionalMappingContributions;
|
||||
import org.hibernate.boot.spi.AdditionalMappingContributor;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
||||
import org.hibernate.boot.spi.MetadataContributor;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
|
@ -80,6 +80,7 @@ import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.internal.NamedBasicTypeImpl;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
||||
import org.jboss.jandex.IndexView;
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -592,7 +593,7 @@ public class MetadataBuildingProcess {
|
|||
private static void handleTypes(
|
||||
BootstrapContext bootstrapContext,
|
||||
MetadataBuildingOptions options,
|
||||
ConverterRegistry converterRegistry) {
|
||||
InFlightMetadataCollector metadataCollector) {
|
||||
final ClassLoaderService classLoaderService = options.getServiceRegistry().getService(ClassLoaderService.class);
|
||||
|
||||
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
|
||||
|
@ -606,7 +607,7 @@ public class MetadataBuildingProcess {
|
|||
|
||||
@Override
|
||||
public void contributeAttributeConverter(Class<? extends AttributeConverter<?, ?>> converterClass) {
|
||||
converterRegistry.addAttributeConverter( converterClass );
|
||||
metadataCollector.getConverterRegistry().addAttributeConverter( converterClass );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -706,6 +707,13 @@ public class MetadataBuildingProcess {
|
|||
|
||||
// add explicit application registered types
|
||||
typeConfiguration.addBasicTypeRegistrationContributions( options.getBasicTypeRegistrations() );
|
||||
for ( CompositeUserType<?> compositeUserType : options.getCompositeUserTypes() ) {
|
||||
//noinspection unchecked
|
||||
metadataCollector.registerCompositeUserType(
|
||||
compositeUserType.returnedClass(),
|
||||
(Class<? extends CompositeUserType<?>>) compositeUserType.getClass()
|
||||
);
|
||||
}
|
||||
|
||||
final JdbcType timestampWithTimeZoneOverride = getTimestampWithTimeZoneOverride( options, jdbcTypeRegistry );
|
||||
if ( timestampWithTimeZoneOverride != null ) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.dialect.TimeZoneSupport;
|
|||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||
import org.hibernate.type.WrapperArrayHandling;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
|
||||
|
@ -78,6 +79,11 @@ public abstract class AbstractDelegatingMetadataBuildingOptions implements Metad
|
|||
return delegate.getBasicTypeRegistrations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompositeUserType<?>> getCompositeUserTypes() {
|
||||
return delegate.getCompositeUserTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeConfiguration getTypeConfiguration() {
|
||||
return delegate.getTypeConfiguration();
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.metamodel.internal.ManagedTypeRepresentationResolverStandar
|
|||
import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
|
||||
import org.hibernate.type.WrapperArrayHandling;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
|
||||
|
@ -102,6 +103,11 @@ public interface MetadataBuildingOptions {
|
|||
*/
|
||||
List<BasicTypeRegistration> getBasicTypeRegistrations();
|
||||
|
||||
/**
|
||||
* Access the list of {@link CompositeUserType} registrations.
|
||||
*/
|
||||
List<CompositeUserType<?>> getCompositeUserTypes();
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#IMPLICIT_NAMING_STRATEGY
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.io.Serializable;
|
|||
|
||||
import org.hibernate.type.CustomType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.UserComponentType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
|
@ -25,19 +26,35 @@ import jakarta.persistence.Id;
|
|||
* @author Christian Beikov
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = ContributedUserTypeTest.StringWrapperTestEntity.class,
|
||||
typeContributors = StringWrapperTypeContributor.class
|
||||
annotatedClasses = {
|
||||
ContributedUserTypeTest.StringWrapperTestEntity.class,
|
||||
ContributedUserTypeTest.MyCompositeValueTestEntity.class,
|
||||
},
|
||||
typeContributors = { StringWrapperTypeContributor.class, MyCompositeValueTypeContributor.class }
|
||||
)
|
||||
@SessionFactory
|
||||
public class ContributedUserTypeTest {
|
||||
|
||||
|
||||
@Test
|
||||
@JiraKey( "HHH-14408" )
|
||||
public void test(SessionFactoryScope scope) {
|
||||
Type type = scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( StringWrapperTestEntity.class )
|
||||
final Type type = scope.getSessionFactory()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( StringWrapperTestEntity.class )
|
||||
.getPropertyType( "stringWrapper" );
|
||||
Assertions.assertTrue( type instanceof CustomType, "Type was initialized too early i.e. before type-contributors were run" );
|
||||
Assertions.assertTrue(
|
||||
type instanceof CustomType,
|
||||
"Type was initialized too early i.e. before type-contributors were run"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@JiraKey( "HHH-17181" )
|
||||
public void testComposite(SessionFactoryScope scope) {
|
||||
final Type type = scope.getSessionFactory()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( MyCompositeValueTestEntity.class )
|
||||
.getPropertyType( "compositeValue" );
|
||||
Assertions.assertInstanceOf( UserComponentType.class, type );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -52,11 +69,29 @@ public class ContributedUserTypeTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Entity(name = "StringWrapperTestEntity")
|
||||
@Test
|
||||
@JiraKey( "HHH-17181" )
|
||||
public void testCompositeParameter(SessionFactoryScope scope) {
|
||||
scope.inSession(
|
||||
session -> {
|
||||
session.createSelectionQuery( "from MyCompositeValueTestEntity e where e.compositeValue = :c" )
|
||||
.setParameter( "c", new MyCompositeValue( 1L, "1" ) )
|
||||
.getResultList();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "StringWrapperTestEntity" )
|
||||
public static class StringWrapperTestEntity implements Serializable {
|
||||
@Id
|
||||
private Integer id;
|
||||
private StringWrapper stringWrapper;
|
||||
}
|
||||
|
||||
@Entity( name = "MyCompositeValueTestEntity" )
|
||||
public static class MyCompositeValueTestEntity implements Serializable {
|
||||
@Id
|
||||
private Integer id;
|
||||
private MyCompositeValue compositeValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.type.contributor.usertype;
|
||||
|
||||
public class MyCompositeValue {
|
||||
protected Long longValue;
|
||||
protected String stringValue;
|
||||
|
||||
public MyCompositeValue() {
|
||||
}
|
||||
|
||||
public MyCompositeValue(Long longValue, String stringValue) {
|
||||
this.longValue = longValue;
|
||||
this.stringValue = stringValue;
|
||||
}
|
||||
|
||||
public Long longValue() {
|
||||
return longValue;
|
||||
}
|
||||
|
||||
public String stringValue() {
|
||||
return stringValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.type.contributor.usertype;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.spi.ValueAccess;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
||||
public class MyCompositeValueType implements CompositeUserType<MyCompositeValue> {
|
||||
public static final MyCompositeValueType INSTANCE = new MyCompositeValueType();
|
||||
|
||||
public static class EmbeddableMapper {
|
||||
Long longValue;
|
||||
String stringValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPropertyValue(MyCompositeValue component, int property) throws HibernateException {
|
||||
switch ( property ) {
|
||||
case 0:
|
||||
return component.longValue();
|
||||
case 1:
|
||||
return component.stringValue();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyCompositeValue instantiate(ValueAccess values, SessionFactoryImplementor sessionFactory) {
|
||||
final Long id = values.getValue( 0, Long.class );
|
||||
final String hash = values.getValue( 1, String.class );
|
||||
return new MyCompositeValue( id, hash );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> embeddable() {
|
||||
return EmbeddableMapper.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MyCompositeValue> returnedClass() {
|
||||
return MyCompositeValue.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(MyCompositeValue x, MyCompositeValue y) {
|
||||
return Objects.equals( x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(MyCompositeValue x) {
|
||||
return Objects.hashCode( x );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyCompositeValue deepCopy(MyCompositeValue value) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
return new MyCompositeValue( value.longValue(), value.stringValue() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(MyCompositeValue value) {
|
||||
return new Object[] { value.longValue(), value.stringValue() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyCompositeValue assemble(Serializable cached, Object owner) {
|
||||
final Object[] parts = (Object[]) cached;
|
||||
return new MyCompositeValue( (Long) parts[0], (String) parts[1] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyCompositeValue replace(MyCompositeValue detached, MyCompositeValue managed, Object owner) {
|
||||
return deepCopy( detached );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.type.contributor.usertype;
|
||||
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* @author Marco Belladelli
|
||||
*/
|
||||
public class MyCompositeValueTypeContributor implements TypeContributor {
|
||||
@Override
|
||||
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
typeContributions.contributeType( MyCompositeValueType.INSTANCE );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue