HHH-17504 - Ongoing JPA 32 work
HHH-17350 - Work on hibernate-models, XSD and JAXB HHH-16114 - Improve boot metamodel binding HHH-15996 - Develop an abstraction for Annotation in annotation processing HHH-16012 - Develop an abstraction for domain model Class refs HHH-15997 - Support for dynamic models in orm.xml HHH-15698 - Support for entity-name in mapping.xsd
This commit is contained in:
parent
b3241be1f0
commit
cf69c2683d
|
@ -16,8 +16,6 @@ import org.hibernate.annotations.OptimisticLock;
|
||||||
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
import org.hibernate.boot.models.AnnotationPlacementException;
|
import org.hibernate.boot.models.AnnotationPlacementException;
|
||||||
import org.hibernate.boot.models.bind.internal.binders.BasicValueBinder;
|
|
||||||
import org.hibernate.boot.models.bind.internal.binders.ColumnBinder;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
import org.hibernate.boot.models.bind.spi.BindingContext;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
import org.hibernate.boot.models.bind.spi.BindingState;
|
||||||
|
@ -93,41 +91,38 @@ public class AttributeBinding extends Binding {
|
||||||
final BasicValue basicValue = new BasicValue( bindingState.getMetadataBuildingContext() );
|
final BasicValue basicValue = new BasicValue( bindingState.getMetadataBuildingContext() );
|
||||||
|
|
||||||
final MemberDetails member = attributeMetadata.getMember();
|
final MemberDetails member = attributeMetadata.getMember();
|
||||||
bindImplicitJavaType( member, property, basicValue );
|
BasicValueHelper.bindImplicitJavaType( member, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
bindMutability( member, property, basicValue );
|
bindMutability( member, property, basicValue );
|
||||||
bindOptimisticLocking( member, property, basicValue );
|
bindOptimisticLocking( member, property, basicValue );
|
||||||
bindConversion( member, property, basicValue );
|
bindConversion( member, property, basicValue );
|
||||||
|
|
||||||
processColumn( member, property, basicValue, primaryTable, Column.class );
|
processColumn( member, property, basicValue, primaryTable, Column.class );
|
||||||
|
|
||||||
BasicValueBinder.bindJavaType( member, property, basicValue, bindingOptions, bindingState, bindingContext );
|
BasicValueHelper.bindJavaType( member, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
BasicValueBinder.bindJdbcType( member, property, basicValue, bindingOptions, bindingState, bindingContext );
|
BasicValueHelper.bindJdbcType( member, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
BasicValueBinder.bindLob( member, property, basicValue, bindingOptions, bindingState, bindingContext );
|
BasicValueHelper.bindLob( member, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
BasicValueBinder.bindNationalized(
|
BasicValueHelper.bindNationalized(
|
||||||
member,
|
member,
|
||||||
property,
|
|
||||||
basicValue,
|
basicValue,
|
||||||
bindingOptions,
|
bindingOptions,
|
||||||
bindingState,
|
bindingState,
|
||||||
bindingContext
|
bindingContext
|
||||||
);
|
);
|
||||||
BasicValueBinder.bindEnumerated(
|
BasicValueHelper.bindEnumerated(
|
||||||
member,
|
member,
|
||||||
property,
|
|
||||||
basicValue,
|
basicValue,
|
||||||
bindingOptions,
|
bindingOptions,
|
||||||
bindingState,
|
bindingState,
|
||||||
bindingContext
|
bindingContext
|
||||||
);
|
);
|
||||||
BasicValueBinder.bindTemporalPrecision(
|
BasicValueHelper.bindTemporalPrecision(
|
||||||
member,
|
member,
|
||||||
property,
|
|
||||||
basicValue,
|
basicValue,
|
||||||
bindingOptions,
|
bindingOptions,
|
||||||
bindingState,
|
bindingState,
|
||||||
bindingContext
|
bindingContext
|
||||||
);
|
);
|
||||||
BasicValueBinder.bindTimeZoneStorage(
|
BasicValueHelper.bindTimeZoneStorage(
|
||||||
member,
|
member,
|
||||||
property,
|
property,
|
||||||
basicValue,
|
basicValue,
|
||||||
|
@ -156,13 +151,6 @@ public class AttributeBinding extends Binding {
|
||||||
return getProperty();
|
return getProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void bindImplicitJavaType(
|
|
||||||
MemberDetails member,
|
|
||||||
@SuppressWarnings("unused") Property property,
|
|
||||||
BasicValue basicValue) {
|
|
||||||
basicValue.setImplicitJavaTypeAccess( (typeConfiguration) -> member.getType().toJavaClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindMutability(MemberDetails member, Property property, BasicValue basicValue) {
|
private void bindMutability(MemberDetails member, Property property, BasicValue basicValue) {
|
||||||
final var mutabilityAnn = member.getAnnotationUsage( Mutability.class );
|
final var mutabilityAnn = member.getAnnotationUsage( Mutability.class );
|
||||||
final var immutableAnn = member.getAnnotationUsage( Immutable.class );
|
final var immutableAnn = member.getAnnotationUsage( Immutable.class );
|
||||||
|
@ -236,9 +224,18 @@ public class AttributeBinding extends Binding {
|
||||||
BasicValue basicValue,
|
BasicValue basicValue,
|
||||||
Table primaryTable,
|
Table primaryTable,
|
||||||
Class<A> annotation) {
|
Class<A> annotation) {
|
||||||
|
BasicValueHelper.bindColumn(
|
||||||
|
member,
|
||||||
|
property::getName,
|
||||||
|
basicValue,
|
||||||
|
primaryTable,
|
||||||
|
bindingOptions,
|
||||||
|
bindingState,
|
||||||
|
bindingContext
|
||||||
|
);
|
||||||
// todo : implicit column
|
// todo : implicit column
|
||||||
final var columnAnn = member.getAnnotationUsage( annotation );
|
final var columnAnn = member.getAnnotationUsage( annotation );
|
||||||
final var column = ColumnBinder.bindColumn( columnAnn, property::getName );
|
final var column = ColumnHelper.bindColumn( columnAnn, property::getName );
|
||||||
|
|
||||||
var tableName = BindingHelper.getValue( columnAnn, "table", "" );
|
var tableName = BindingHelper.getValue( columnAnn, "table", "" );
|
||||||
if ( "".equals( tableName ) || tableName == null ) {
|
if ( "".equals( tableName ) || tableName == null ) {
|
||||||
|
|
|
@ -0,0 +1,411 @@
|
||||||
|
/*
|
||||||
|
* 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.boot.models.bind.internal;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.annotations.JavaType;
|
||||||
|
import org.hibernate.annotations.JdbcType;
|
||||||
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
|
import org.hibernate.annotations.Nationalized;
|
||||||
|
import org.hibernate.annotations.TimeZoneColumn;
|
||||||
|
import org.hibernate.annotations.TimeZoneStorage;
|
||||||
|
import org.hibernate.annotations.TimeZoneStorageType;
|
||||||
|
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
||||||
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
|
import org.hibernate.boot.models.AnnotationPlacementException;
|
||||||
|
import org.hibernate.boot.models.bind.spi.BindingContext;
|
||||||
|
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
||||||
|
import org.hibernate.boot.models.bind.spi.BindingState;
|
||||||
|
import org.hibernate.boot.models.bind.spi.TableReference;
|
||||||
|
import org.hibernate.boot.models.categorize.spi.AttributeMetadata;
|
||||||
|
import org.hibernate.boot.models.categorize.spi.EntityTypeMetadata;
|
||||||
|
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||||
|
import org.hibernate.engine.spi.FilterDefinition;
|
||||||
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.mapping.BasicValue;
|
||||||
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.hibernate.mapping.RootClass;
|
||||||
|
import org.hibernate.mapping.Table;
|
||||||
|
import org.hibernate.models.ModelsException;
|
||||||
|
import org.hibernate.models.spi.AnnotationUsage;
|
||||||
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
|
import org.hibernate.models.spi.MemberDetails;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.descriptor.java.BasicJavaType;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import jakarta.persistence.AttributeConverter;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Convert;
|
||||||
|
import jakarta.persistence.Enumerated;
|
||||||
|
import jakarta.persistence.Lob;
|
||||||
|
import jakarta.persistence.Temporal;
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
|
import static jakarta.persistence.EnumType.ORDINAL;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static org.hibernate.annotations.TimeZoneStorageType.AUTO;
|
||||||
|
import static org.hibernate.annotations.TimeZoneStorageType.COLUMN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class BasicValueHelper {
|
||||||
|
|
||||||
|
public static final String TENANT_FILTER_NAME = "_tenantId";
|
||||||
|
public static final String TENANT_PARAMETER_NAME = "tenantId";
|
||||||
|
|
||||||
|
public static void bindImplicitJavaType(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
basicValue.setImplicitJavaTypeAccess( (typeConfiguration) -> member.getType().toJavaClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindJavaType(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
// todo : do we need to account for JavaTypeRegistration here?
|
||||||
|
final var javaTypeAnn = member.getAnnotationUsage( JavaType.class );
|
||||||
|
if ( javaTypeAnn == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
basicValue.setExplicitJavaTypeAccess( (typeConfiguration) -> {
|
||||||
|
final var classDetails = javaTypeAnn.getClassDetails( "value" );
|
||||||
|
final Class<BasicJavaType<?>> javaClass = classDetails.toJavaClass();
|
||||||
|
try {
|
||||||
|
return javaClass.getConstructor().newInstance();
|
||||||
|
}
|
||||||
|
catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||||
|
final ModelsException modelsException = new ModelsException( "Error instantiating local @JavaType - " + member.getName() );
|
||||||
|
modelsException.addSuppressed( e );
|
||||||
|
throw modelsException;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindJdbcType(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
// todo : do we need to account for JdbcTypeRegistration here?
|
||||||
|
final var jdbcTypeAnn = member.getAnnotationUsage( JdbcType.class );
|
||||||
|
final var jdbcTypeCodeAnn = member.getAnnotationUsage( JdbcTypeCode.class );
|
||||||
|
|
||||||
|
if ( jdbcTypeAnn != null ) {
|
||||||
|
if ( jdbcTypeCodeAnn != null ) {
|
||||||
|
throw new AnnotationPlacementException(
|
||||||
|
"Illegal combination of @JdbcType and @JdbcTypeCode - " + member.getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
basicValue.setExplicitJdbcTypeAccess( (typeConfiguration) -> {
|
||||||
|
final var classDetails = jdbcTypeAnn.getClassDetails( "value" );
|
||||||
|
final Class<org.hibernate.type.descriptor.jdbc.JdbcType> javaClass = classDetails.toJavaClass();
|
||||||
|
try {
|
||||||
|
return javaClass.getConstructor().newInstance();
|
||||||
|
}
|
||||||
|
catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||||
|
final ModelsException modelsException = new ModelsException( "Error instantiating local @JdbcType - " + member.getName() );
|
||||||
|
modelsException.addSuppressed( e );
|
||||||
|
throw modelsException;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
else if ( jdbcTypeCodeAnn != null ) {
|
||||||
|
final Integer typeCode = jdbcTypeCodeAnn.getInteger( "value" );
|
||||||
|
basicValue.setExplicitJdbcTypeCode( typeCode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindNationalized(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
if ( member.getAnnotationUsage( Nationalized.class ) != null ) {
|
||||||
|
basicValue.makeNationalized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindLob(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
if ( member.getAnnotationUsage( Lob.class ) != null ) {
|
||||||
|
basicValue.makeLob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindEnumerated(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
final AnnotationUsage<Enumerated> enumerated = member.getAnnotationUsage( Enumerated.class );
|
||||||
|
if ( enumerated == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
basicValue.setEnumerationStyle( enumerated.getEnum( "value", ORDINAL ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindTemporalPrecision(
|
||||||
|
MemberDetails member,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
final AnnotationUsage<Temporal> temporalAnn = member.getAnnotationUsage( Temporal.class );
|
||||||
|
if ( temporalAnn == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection deprecation
|
||||||
|
final TemporalType precision = temporalAnn.getEnum( "value" );
|
||||||
|
basicValue.setTemporalPrecision( precision );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindTimeZoneStorage(
|
||||||
|
MemberDetails member,
|
||||||
|
Property property,
|
||||||
|
BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
final AnnotationUsage<TimeZoneStorage> storageAnn = member.getAnnotationUsage( TimeZoneStorage.class );
|
||||||
|
final AnnotationUsage<TimeZoneColumn> columnAnn = member.getAnnotationUsage( TimeZoneColumn.class );
|
||||||
|
if ( storageAnn != null ) {
|
||||||
|
final TimeZoneStorageType strategy = storageAnn.getEnum( "value", AUTO );
|
||||||
|
if ( strategy != COLUMN && columnAnn != null ) {
|
||||||
|
throw new AnnotationPlacementException(
|
||||||
|
"Illegal combination of @TimeZoneStorage(" + strategy.name() + ") and @TimeZoneColumn"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
basicValue.setTimeZoneStorageType( strategy );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( columnAnn != null ) {
|
||||||
|
final org.hibernate.mapping.Column column = (org.hibernate.mapping.Column) basicValue.getColumn();
|
||||||
|
column.setName( columnAnn.getString( "name", property.getName() + "_tz" ) );
|
||||||
|
column.setSqlType( columnAnn.getString( "columnDefinition", (String) null ) );
|
||||||
|
|
||||||
|
final var tableName = columnAnn.getString( "table", (String) null );
|
||||||
|
TableReference tableByName = null;
|
||||||
|
if ( tableName != null ) {
|
||||||
|
final Identifier identifier = Identifier.toIdentifier( tableName );
|
||||||
|
tableByName = bindingState.getTableByName( identifier.getCanonicalName() );
|
||||||
|
basicValue.setTable( tableByName.table() );
|
||||||
|
}
|
||||||
|
|
||||||
|
property.setInsertable( columnAnn.getBoolean( "insertable", true ) );
|
||||||
|
property.setUpdateable( columnAnn.getBoolean( "updatable", true ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindConversion(
|
||||||
|
MemberDetails member,
|
||||||
|
@SuppressWarnings("unused") BasicValue basicValue,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
@SuppressWarnings("unused") BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
// todo : do we need to account for auto-applied converters here?
|
||||||
|
final var convertAnn = member.getAnnotationUsage( Convert.class );
|
||||||
|
if ( convertAnn == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( convertAnn.getBoolean( "disableConversion" ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( convertAnn.getString( "attributeName" ) != null ) {
|
||||||
|
throw new ModelsException( "@Convert#attributeName should not be specified on basic mappings - " + member.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClassDetails converterClassDetails = convertAnn.getClassDetails( "converter" );
|
||||||
|
final Class<AttributeConverter<?, ?>> javaClass = converterClassDetails.toJavaClass();
|
||||||
|
basicValue.setJpaAttributeConverterDescriptor( new ClassBasedConverterDescriptor(
|
||||||
|
javaClass,
|
||||||
|
bindingContext.getClassmateContext()
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static org.hibernate.mapping.Column bindColumn(
|
||||||
|
MemberDetails member,
|
||||||
|
Supplier<String> defaultNameSupplier,
|
||||||
|
BasicValue basicValue,
|
||||||
|
Table primaryTable,
|
||||||
|
BindingOptions bindingOptions,
|
||||||
|
BindingState bindingState,
|
||||||
|
BindingContext bindingContext) {
|
||||||
|
return bindColumn(
|
||||||
|
member,
|
||||||
|
Column.class,
|
||||||
|
defaultNameSupplier,
|
||||||
|
basicValue,
|
||||||
|
primaryTable,
|
||||||
|
bindingOptions,
|
||||||
|
bindingState,
|
||||||
|
bindingContext
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <A extends Annotation> org.hibernate.mapping.Column bindColumn(
|
||||||
|
MemberDetails member,
|
||||||
|
Class<A> annotationType,
|
||||||
|
Supplier<String> defaultNameSupplier,
|
||||||
|
BasicValue basicValue,
|
||||||
|
Table primaryTable,
|
||||||
|
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
||||||
|
BindingState bindingState,
|
||||||
|
@SuppressWarnings("unused") BindingContext bindingContext) {
|
||||||
|
final var columnAnn = member.getAnnotationUsage( annotationType );
|
||||||
|
final var column = ColumnHelper.bindColumn( columnAnn, defaultNameSupplier );
|
||||||
|
|
||||||
|
var tableName = BindingHelper.getValue( columnAnn, "table", "" );
|
||||||
|
if ( StringHelper.isEmpty( tableName ) ) {
|
||||||
|
basicValue.setTable( primaryTable );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final Identifier identifier = Identifier.toIdentifier( tableName );
|
||||||
|
final TableReference tableByName = bindingState.getTableByName( identifier.getCanonicalName() );
|
||||||
|
basicValue.setTable( tableByName.table() );
|
||||||
|
}
|
||||||
|
|
||||||
|
basicValue.addColumn( column );
|
||||||
|
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindTenantId(
|
||||||
|
EntityTypeMetadata managedType,
|
||||||
|
RootClass rootClass,
|
||||||
|
BindingOptions bindingOptions,
|
||||||
|
BindingState bindingState,
|
||||||
|
BindingContext bindingContext) {
|
||||||
|
final AttributeMetadata tenantIdAttribute = managedType.getHierarchy().getTenantIdAttribute();
|
||||||
|
if ( tenantIdAttribute == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final InFlightMetadataCollector collector = bindingState.getMetadataBuildingContext().getMetadataCollector();
|
||||||
|
final TypeConfiguration typeConfiguration = collector.getTypeConfiguration();
|
||||||
|
|
||||||
|
final MemberDetails memberDetails = tenantIdAttribute.getMember();
|
||||||
|
final String returnedClassName = memberDetails.getType().getClassName();
|
||||||
|
final BasicType<Object> tenantIdType = typeConfiguration
|
||||||
|
.getBasicTypeRegistry()
|
||||||
|
.getRegisteredType( returnedClassName );
|
||||||
|
|
||||||
|
final FilterDefinition filterDefinition = collector.getFilterDefinition( TENANT_FILTER_NAME );
|
||||||
|
if ( filterDefinition == null ) {
|
||||||
|
collector.addFilterDefinition( new FilterDefinition(
|
||||||
|
TENANT_FILTER_NAME,
|
||||||
|
"",
|
||||||
|
singletonMap( TENANT_PARAMETER_NAME, tenantIdType )
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final org.hibernate.type.descriptor.java.JavaType<?> tenantIdTypeJtd = tenantIdType.getJavaTypeDescriptor();
|
||||||
|
final org.hibernate.type.descriptor.java.JavaType<?> parameterJtd = filterDefinition
|
||||||
|
.getParameterJdbcMapping( TENANT_PARAMETER_NAME )
|
||||||
|
.getJavaTypeDescriptor();
|
||||||
|
if ( !parameterJtd.getJavaTypeClass().equals( tenantIdTypeJtd.getJavaTypeClass() ) ) {
|
||||||
|
throw new MappingException(
|
||||||
|
"all @TenantId fields must have the same type: "
|
||||||
|
+ parameterJtd.getJavaType().getTypeName()
|
||||||
|
+ " differs from "
|
||||||
|
+ tenantIdTypeJtd.getJavaType().getTypeName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Property property = new Property();
|
||||||
|
rootClass.addProperty( property );
|
||||||
|
property.setName( tenantIdAttribute.getName() );
|
||||||
|
|
||||||
|
final BasicValue basicValue = new BasicValue( bindingState.getMetadataBuildingContext(), rootClass.getRootTable() );
|
||||||
|
property.setValue( basicValue );
|
||||||
|
|
||||||
|
bindImplicitJavaType( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
bindJavaType( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
bindJdbcType( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
|
||||||
|
bindConversion( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
bindEnumerated( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
|
||||||
|
BasicValueHelper.bindColumn(
|
||||||
|
memberDetails,
|
||||||
|
property::getName,
|
||||||
|
basicValue,
|
||||||
|
rootClass.getRootTable(),
|
||||||
|
bindingOptions,
|
||||||
|
bindingState,
|
||||||
|
bindingContext
|
||||||
|
);
|
||||||
|
|
||||||
|
property.resetUpdateable( false );
|
||||||
|
property.resetOptional( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindVersion(
|
||||||
|
EntityTypeMetadata typeMetadata,
|
||||||
|
RootClass rootClass,
|
||||||
|
BindingOptions bindingOptions,
|
||||||
|
BindingState bindingState,
|
||||||
|
BindingContext bindingContext) {
|
||||||
|
final AttributeMetadata versionAttribute = typeMetadata.getHierarchy().getVersionAttribute();
|
||||||
|
if ( versionAttribute == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Property property = new Property();
|
||||||
|
property.setName( versionAttribute.getName() );
|
||||||
|
rootClass.setVersion( property );
|
||||||
|
rootClass.addProperty( property );
|
||||||
|
|
||||||
|
final BasicValue basicValue = new BasicValue(
|
||||||
|
bindingState.getMetadataBuildingContext(),
|
||||||
|
rootClass.getRootTable()
|
||||||
|
);
|
||||||
|
property.setValue( basicValue );
|
||||||
|
|
||||||
|
final MemberDetails memberDetails = versionAttribute.getMember();
|
||||||
|
bindImplicitJavaType( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
bindJavaType( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
bindJdbcType( memberDetails, basicValue, bindingOptions, bindingState, bindingContext );
|
||||||
|
|
||||||
|
final org.hibernate.mapping.Column column = bindColumn(
|
||||||
|
memberDetails,
|
||||||
|
property::getName,
|
||||||
|
basicValue,
|
||||||
|
rootClass.getRootTable(),
|
||||||
|
bindingOptions,
|
||||||
|
bindingState,
|
||||||
|
bindingContext
|
||||||
|
);
|
||||||
|
// force it to be non-nullable
|
||||||
|
column.setNullable( false );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* Copyright: Red Hat Inc. and Hibernate Authors
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.boot.models.bind.internal.binders;
|
package org.hibernate.boot.models.bind.internal;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import static org.hibernate.internal.util.NullnessHelper.nullif;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ColumnBinder {
|
public class ColumnHelper {
|
||||||
public static Column bindColumn(
|
public static Column bindColumn(
|
||||||
AnnotationUsage<?> annotationUsage,
|
AnnotationUsage<?> annotationUsage,
|
||||||
Supplier<String> defaultNameSupplier) {
|
Supplier<String> defaultNameSupplier) {
|
||||||
|
@ -90,7 +90,7 @@ public class ColumnBinder {
|
||||||
return nullif( columnAnnotation.getAttributeValue( "name" ), defaultNameSupplier );
|
return nullif( columnAnnotation.getAttributeValue( "name" ), defaultNameSupplier );
|
||||||
}
|
}
|
||||||
|
|
||||||
private ColumnBinder() {
|
private ColumnHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DiscriminatorType bindDiscriminatorColumn(
|
public static DiscriminatorType bindDiscriminatorColumn(
|
|
@ -6,8 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.boot.models.bind.internal;
|
package org.hibernate.boot.models.bind.internal;
|
||||||
|
|
||||||
import org.hibernate.boot.models.bind.internal.binders.BasicValueBinder;
|
|
||||||
import org.hibernate.boot.models.bind.internal.binders.ColumnBinder;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
import org.hibernate.boot.models.bind.spi.BindingContext;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
import org.hibernate.boot.models.bind.spi.BindingState;
|
||||||
|
@ -106,7 +104,7 @@ public class IdentifierBinding extends Binding {
|
||||||
final PrimaryKey primaryKey = table.getPrimaryKey();
|
final PrimaryKey primaryKey = table.getPrimaryKey();
|
||||||
|
|
||||||
final AnnotationUsage<Column> idColumnAnn = idAttributeMember.getAnnotationUsage( Column.class );
|
final AnnotationUsage<Column> idColumnAnn = idAttributeMember.getAnnotationUsage( Column.class );
|
||||||
final org.hibernate.mapping.Column column = ColumnBinder.bindColumn(
|
final org.hibernate.mapping.Column column = ColumnHelper.bindColumn(
|
||||||
idColumnAnn,
|
idColumnAnn,
|
||||||
() -> "id",
|
() -> "id",
|
||||||
true,
|
true,
|
||||||
|
@ -115,10 +113,10 @@ public class IdentifierBinding extends Binding {
|
||||||
idValue.addColumn( column, true, false );
|
idValue.addColumn( column, true, false );
|
||||||
primaryKey.addColumn( column );
|
primaryKey.addColumn( column );
|
||||||
|
|
||||||
AttributeBinding.bindImplicitJavaType( idAttributeMember, idProperty, idValue );
|
BasicValueHelper.bindImplicitJavaType( idAttributeMember, idValue, options, state, context );
|
||||||
BasicValueBinder.bindJavaType( idAttributeMember, idProperty, idValue, options, state, context );
|
BasicValueHelper.bindJavaType( idAttributeMember, idValue, options, state, context );
|
||||||
BasicValueBinder.bindJdbcType( idAttributeMember, idProperty, idValue, options, state, context );
|
BasicValueHelper.bindJdbcType( idAttributeMember, idValue, options, state, context );
|
||||||
BasicValueBinder.bindNationalized( idAttributeMember, idProperty, idValue, options, state, context );
|
BasicValueHelper.bindNationalized( idAttributeMember, idValue, options, state, context );
|
||||||
|
|
||||||
return idValue;
|
return idValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.boot.models.bind.internal.binders.ColumnBinder;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
import org.hibernate.boot.models.bind.spi.BindingContext;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
import org.hibernate.boot.models.bind.spi.BindingState;
|
||||||
|
@ -40,8 +39,8 @@ import jakarta.persistence.DiscriminatorType;
|
||||||
import jakarta.persistence.InheritanceType;
|
import jakarta.persistence.InheritanceType;
|
||||||
|
|
||||||
import static org.hibernate.boot.models.bind.ModelBindingLogging.MODEL_BINDING_LOGGER;
|
import static org.hibernate.boot.models.bind.ModelBindingLogging.MODEL_BINDING_LOGGER;
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.TenantIdBinder.bindTenantId;
|
import static org.hibernate.boot.models.bind.internal.BasicValueHelper.bindTenantId;
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.VersionBinder.bindVersion;
|
import static org.hibernate.boot.models.bind.internal.BasicValueHelper.bindVersion;
|
||||||
import static org.hibernate.internal.util.StringHelper.coalesce;
|
import static org.hibernate.internal.util.StringHelper.coalesce;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,7 +303,7 @@ public class RootEntityBinding extends EntityBinding {
|
||||||
final BasicValue value = new BasicValue( bindingState.getMetadataBuildingContext(), rootClass.getIdentityTable() );
|
final BasicValue value = new BasicValue( bindingState.getMetadataBuildingContext(), rootClass.getIdentityTable() );
|
||||||
rootClass.setDiscriminator( value );
|
rootClass.setDiscriminator( value );
|
||||||
|
|
||||||
final DiscriminatorType discriminatorType = ColumnBinder.bindDiscriminatorColumn(
|
final DiscriminatorType discriminatorType = ColumnHelper.bindDiscriminatorColumn(
|
||||||
bindingContext,
|
bindingContext,
|
||||||
formulaAnn,
|
formulaAnn,
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.models.bind.internal.binders.ColumnBinder;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
import org.hibernate.boot.models.bind.spi.BindingContext;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
import org.hibernate.boot.models.bind.spi.BindingState;
|
||||||
|
@ -172,10 +171,10 @@ public class SubclassEntityBinding extends EntityBinding {
|
||||||
targetColumn,
|
targetColumn,
|
||||||
joinColumnAnns
|
joinColumnAnns
|
||||||
);
|
);
|
||||||
pkColumn = ColumnBinder.bindColumn( joinColumnAnn, targetColumn::getName, true, false );
|
pkColumn = ColumnHelper.bindColumn( joinColumnAnn, targetColumn::getName, true, false );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pkColumn = ColumnBinder.bindColumn( null, targetColumn::getName, true, false );
|
pkColumn = ColumnHelper.bindColumn( null, targetColumn::getName, true, false );
|
||||||
}
|
}
|
||||||
primaryKey.addColumn( pkColumn );
|
primaryKey.addColumn( pkColumn );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
* Copyright: Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.boot.models.bind.internal.binders;
|
|
||||||
|
|
||||||
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
|
||||||
import org.hibernate.boot.models.bind.internal.BindingHelper;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
|
||||||
import org.hibernate.boot.models.bind.spi.TableReference;
|
|
||||||
import org.hibernate.mapping.BasicValue;
|
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.hibernate.mapping.Table;
|
|
||||||
import org.hibernate.models.ModelsException;
|
|
||||||
import org.hibernate.models.spi.ClassDetails;
|
|
||||||
import org.hibernate.models.spi.MemberDetails;
|
|
||||||
|
|
||||||
import jakarta.persistence.AttributeConverter;
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.Convert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class AttributeBinder {
|
|
||||||
public static void bindImplicitJavaType(
|
|
||||||
MemberDetails member,
|
|
||||||
@SuppressWarnings("unused") Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
|
||||||
@SuppressWarnings("unused") BindingState bindingState,
|
|
||||||
@SuppressWarnings("unused") BindingContext bindingContext) {
|
|
||||||
basicValue.setImplicitJavaTypeAccess( (typeConfiguration) -> member.getType().toJavaClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static org.hibernate.mapping.Column processColumn(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
Table primaryTable,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
@SuppressWarnings("unused") BindingContext bindingContext) {
|
|
||||||
// todo : implicit column
|
|
||||||
final var columnAnn = member.getAnnotationUsage( Column.class );
|
|
||||||
final var column = ColumnBinder.bindColumn( columnAnn, property::getName );
|
|
||||||
|
|
||||||
var tableName = BindingHelper.getValue( columnAnn, "table", "" );
|
|
||||||
if ( "".equals( tableName ) || tableName == null ) {
|
|
||||||
basicValue.setTable( primaryTable );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Identifier identifier = Identifier.toIdentifier( tableName );
|
|
||||||
final TableReference tableByName = bindingState.getTableByName( identifier.getCanonicalName() );
|
|
||||||
basicValue.setTable( tableByName.table() );
|
|
||||||
}
|
|
||||||
|
|
||||||
basicValue.addColumn( column );
|
|
||||||
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindConversion(
|
|
||||||
MemberDetails member,
|
|
||||||
@SuppressWarnings("unused") Property property,
|
|
||||||
@SuppressWarnings("unused") BasicValue basicValue,
|
|
||||||
@SuppressWarnings("unused") BindingOptions bindingOptions,
|
|
||||||
@SuppressWarnings("unused") BindingState bindingState,
|
|
||||||
@SuppressWarnings("unused") BindingContext bindingContext) {
|
|
||||||
// todo : do we need to account for auto-applied converters here?
|
|
||||||
final var convertAnn = member.getAnnotationUsage( Convert.class );
|
|
||||||
if ( convertAnn == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( convertAnn.getBoolean( "disableConversion" ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( convertAnn.getString( "attributeName" ) != null ) {
|
|
||||||
throw new ModelsException( "@Convert#attributeName should not be specified on basic mappings - " + member.getName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
final ClassDetails converterClassDetails = convertAnn.getClassDetails( "converter" );
|
|
||||||
final Class<AttributeConverter<?, ?>> javaClass = converterClassDetails.toJavaClass();
|
|
||||||
basicValue.setJpaAttributeConverterDescriptor( new ClassBasedConverterDescriptor(
|
|
||||||
javaClass,
|
|
||||||
bindingContext.getClassmateContext()
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,202 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
* Copyright: Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.boot.models.bind.internal.binders;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.JavaType;
|
|
||||||
import org.hibernate.annotations.JdbcType;
|
|
||||||
import org.hibernate.annotations.JdbcTypeCode;
|
|
||||||
import org.hibernate.annotations.Nationalized;
|
|
||||||
import org.hibernate.annotations.TimeZoneColumn;
|
|
||||||
import org.hibernate.annotations.TimeZoneStorage;
|
|
||||||
import org.hibernate.annotations.TimeZoneStorageType;
|
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
|
||||||
import org.hibernate.boot.models.AnnotationPlacementException;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
|
||||||
import org.hibernate.boot.models.bind.spi.TableReference;
|
|
||||||
import org.hibernate.mapping.BasicValue;
|
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.hibernate.models.ModelsException;
|
|
||||||
import org.hibernate.models.spi.AnnotationUsage;
|
|
||||||
import org.hibernate.models.spi.MemberDetails;
|
|
||||||
import org.hibernate.type.descriptor.java.BasicJavaType;
|
|
||||||
|
|
||||||
import jakarta.persistence.Enumerated;
|
|
||||||
import jakarta.persistence.Lob;
|
|
||||||
import jakarta.persistence.Temporal;
|
|
||||||
import jakarta.persistence.TemporalType;
|
|
||||||
|
|
||||||
import static jakarta.persistence.EnumType.ORDINAL;
|
|
||||||
import static org.hibernate.annotations.TimeZoneStorageType.AUTO;
|
|
||||||
import static org.hibernate.annotations.TimeZoneStorageType.COLUMN;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class BasicValueBinder {
|
|
||||||
|
|
||||||
public static void bindJavaType(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
// todo : do we need to account for JavaTypeRegistration here?
|
|
||||||
final var javaTypeAnn = member.getAnnotationUsage( JavaType.class );
|
|
||||||
if ( javaTypeAnn == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
basicValue.setExplicitJavaTypeAccess( (typeConfiguration) -> {
|
|
||||||
final var classDetails = javaTypeAnn.getClassDetails( "value" );
|
|
||||||
final Class<BasicJavaType<?>> javaClass = classDetails.toJavaClass();
|
|
||||||
try {
|
|
||||||
return javaClass.getConstructor().newInstance();
|
|
||||||
}
|
|
||||||
catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
|
||||||
final ModelsException modelsException = new ModelsException( "Error instantiating local @JavaType - " + member.getName() );
|
|
||||||
modelsException.addSuppressed( e );
|
|
||||||
throw modelsException;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindJdbcType(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
// todo : do we need to account for JdbcTypeRegistration here?
|
|
||||||
final var jdbcTypeAnn = member.getAnnotationUsage( JdbcType.class );
|
|
||||||
final var jdbcTypeCodeAnn = member.getAnnotationUsage( JdbcTypeCode.class );
|
|
||||||
|
|
||||||
if ( jdbcTypeAnn != null ) {
|
|
||||||
if ( jdbcTypeCodeAnn != null ) {
|
|
||||||
throw new AnnotationPlacementException(
|
|
||||||
"Illegal combination of @JdbcType and @JdbcTypeCode - " + member.getName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
basicValue.setExplicitJdbcTypeAccess( (typeConfiguration) -> {
|
|
||||||
final var classDetails = jdbcTypeAnn.getClassDetails( "value" );
|
|
||||||
final Class<org.hibernate.type.descriptor.jdbc.JdbcType> javaClass = classDetails.toJavaClass();
|
|
||||||
try {
|
|
||||||
return javaClass.getConstructor().newInstance();
|
|
||||||
}
|
|
||||||
catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
|
||||||
final ModelsException modelsException = new ModelsException( "Error instantiating local @JdbcType - " + member.getName() );
|
|
||||||
modelsException.addSuppressed( e );
|
|
||||||
throw modelsException;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
else if ( jdbcTypeCodeAnn != null ) {
|
|
||||||
final Integer typeCode = jdbcTypeCodeAnn.getInteger( "value" );
|
|
||||||
basicValue.setExplicitJdbcTypeCode( typeCode );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindNationalized(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
if ( member.getAnnotationUsage( Nationalized.class ) != null ) {
|
|
||||||
basicValue.makeNationalized();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindLob(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
if ( member.getAnnotationUsage( Lob.class ) != null ) {
|
|
||||||
basicValue.makeLob();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindEnumerated(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final AnnotationUsage<Enumerated> enumerated = member.getAnnotationUsage( Enumerated.class );
|
|
||||||
if ( enumerated == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
basicValue.setEnumerationStyle( enumerated.getEnum( "value", ORDINAL ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindTemporalPrecision(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final AnnotationUsage<Temporal> temporalAnn = member.getAnnotationUsage( Temporal.class );
|
|
||||||
if ( temporalAnn == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection deprecation
|
|
||||||
final TemporalType precision = temporalAnn.getEnum( "value" );
|
|
||||||
basicValue.setTemporalPrecision( precision );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindTimeZoneStorage(
|
|
||||||
MemberDetails member,
|
|
||||||
Property property,
|
|
||||||
BasicValue basicValue,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final AnnotationUsage<TimeZoneStorage> storageAnn = member.getAnnotationUsage( TimeZoneStorage.class );
|
|
||||||
final AnnotationUsage<TimeZoneColumn> columnAnn = member.getAnnotationUsage( TimeZoneColumn.class );
|
|
||||||
if ( storageAnn != null ) {
|
|
||||||
final TimeZoneStorageType strategy = storageAnn.getEnum( "value", AUTO );
|
|
||||||
if ( strategy != COLUMN && columnAnn != null ) {
|
|
||||||
throw new AnnotationPlacementException(
|
|
||||||
"Illegal combination of @TimeZoneStorage(" + strategy.name() + ") and @TimeZoneColumn"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
basicValue.setTimeZoneStorageType( strategy );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( columnAnn != null ) {
|
|
||||||
final org.hibernate.mapping.Column column = (org.hibernate.mapping.Column) basicValue.getColumn();
|
|
||||||
column.setName( columnAnn.getString( "name", property.getName() + "_tz" ) );
|
|
||||||
column.setSqlType( columnAnn.getString( "columnDefinition", (String) null ) );
|
|
||||||
|
|
||||||
final var tableName = columnAnn.getString( "table", (String) null );
|
|
||||||
TableReference tableByName = null;
|
|
||||||
if ( tableName != null ) {
|
|
||||||
final Identifier identifier = Identifier.toIdentifier( tableName );
|
|
||||||
tableByName = bindingState.getTableByName( identifier.getCanonicalName() );
|
|
||||||
basicValue.setTable( tableByName.table() );
|
|
||||||
}
|
|
||||||
|
|
||||||
property.setInsertable( columnAnn.getBoolean( "insertable", true ) );
|
|
||||||
property.setUpdateable( columnAnn.getBoolean( "updatable", true ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
* Copyright: Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.boot.models.bind.internal.binders;
|
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.AttributeMetadata;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.EntityTypeMetadata;
|
|
||||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
|
||||||
import org.hibernate.engine.spi.FilterDefinition;
|
|
||||||
import org.hibernate.mapping.BasicValue;
|
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.hibernate.mapping.RootClass;
|
|
||||||
import org.hibernate.models.spi.MemberDetails;
|
|
||||||
import org.hibernate.type.BasicType;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
|
||||||
|
|
||||||
import static java.util.Collections.singletonMap;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.AttributeBinder.bindConversion;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.AttributeBinder.bindImplicitJavaType;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.AttributeBinder.processColumn;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.BasicValueBinder.bindEnumerated;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.BasicValueBinder.bindJavaType;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.BasicValueBinder.bindJdbcType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class TenantIdBinder {
|
|
||||||
public static final String FILTER_NAME = "_tenantId";
|
|
||||||
public static final String PARAMETER_NAME = "tenantId";
|
|
||||||
|
|
||||||
public static void bindTenantId(
|
|
||||||
EntityTypeMetadata managedType,
|
|
||||||
RootClass rootClass,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final AttributeMetadata tenantIdAttribute = managedType.getHierarchy().getTenantIdAttribute();
|
|
||||||
if ( tenantIdAttribute == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bindTenantId( tenantIdAttribute, rootClass, bindingOptions, bindingState, bindingContext );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindTenantId(
|
|
||||||
AttributeMetadata attributeMetadata,
|
|
||||||
RootClass rootClass,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final InFlightMetadataCollector collector = bindingState.getMetadataBuildingContext().getMetadataCollector();
|
|
||||||
final TypeConfiguration typeConfiguration = collector.getTypeConfiguration();
|
|
||||||
|
|
||||||
final MemberDetails memberDetails = attributeMetadata.getMember();
|
|
||||||
final String returnedClassName = memberDetails.getType().getClassName();
|
|
||||||
final BasicType<Object> tenantIdType = typeConfiguration
|
|
||||||
.getBasicTypeRegistry()
|
|
||||||
.getRegisteredType( returnedClassName );
|
|
||||||
|
|
||||||
final FilterDefinition filterDefinition = collector.getFilterDefinition( FILTER_NAME );
|
|
||||||
if ( filterDefinition == null ) {
|
|
||||||
collector.addFilterDefinition( new FilterDefinition(
|
|
||||||
FILTER_NAME,
|
|
||||||
"",
|
|
||||||
singletonMap( PARAMETER_NAME, tenantIdType )
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final JavaType<?> tenantIdTypeJtd = tenantIdType.getJavaTypeDescriptor();
|
|
||||||
final JavaType<?> parameterJtd = filterDefinition
|
|
||||||
.getParameterJdbcMapping( PARAMETER_NAME )
|
|
||||||
.getJavaTypeDescriptor();
|
|
||||||
if ( !parameterJtd.getJavaTypeClass().equals( tenantIdTypeJtd.getJavaTypeClass() ) ) {
|
|
||||||
throw new MappingException(
|
|
||||||
"all @TenantId fields must have the same type: "
|
|
||||||
+ parameterJtd.getJavaType().getTypeName()
|
|
||||||
+ " differs from "
|
|
||||||
+ tenantIdTypeJtd.getJavaType().getTypeName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Property property = new Property();
|
|
||||||
rootClass.addProperty( property );
|
|
||||||
property.setName( attributeMetadata.getName() );
|
|
||||||
|
|
||||||
final BasicValue basicValue = new BasicValue( bindingState.getMetadataBuildingContext(), rootClass.getRootTable() );
|
|
||||||
property.setValue( basicValue );
|
|
||||||
|
|
||||||
bindImplicitJavaType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindJavaType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindJdbcType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
|
|
||||||
bindConversion( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindEnumerated( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
|
|
||||||
processColumn(
|
|
||||||
memberDetails,
|
|
||||||
property,
|
|
||||||
basicValue,
|
|
||||||
rootClass.getRootTable(),
|
|
||||||
bindingOptions,
|
|
||||||
bindingState,
|
|
||||||
bindingContext
|
|
||||||
);
|
|
||||||
|
|
||||||
property.resetUpdateable( false );
|
|
||||||
property.resetOptional( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindTenantId(
|
|
||||||
AttributeMetadata attributeMetadata,
|
|
||||||
EntityTypeMetadata managedType,
|
|
||||||
RootClass typeBinding,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
bindTenantId( attributeMetadata, typeBinding, bindingOptions, bindingState, bindingContext );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
* Copyright: Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.boot.models.bind.internal.binders;
|
|
||||||
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.AttributeMetadata;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.EntityTypeMetadata;
|
|
||||||
import org.hibernate.mapping.BasicValue;
|
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.hibernate.mapping.RootClass;
|
|
||||||
import org.hibernate.models.spi.MemberDetails;
|
|
||||||
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.AttributeBinder.bindImplicitJavaType;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.AttributeBinder.processColumn;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.BasicValueBinder.bindJavaType;
|
|
||||||
import static org.hibernate.boot.models.bind.internal.binders.BasicValueBinder.bindJdbcType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class VersionBinder {
|
|
||||||
public static void bindVersion(
|
|
||||||
EntityTypeMetadata typeMetadata,
|
|
||||||
RootClass rootClass,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final AttributeMetadata versionAttribute = typeMetadata.getHierarchy().getVersionAttribute();
|
|
||||||
if ( versionAttribute == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bindVersion( versionAttribute, rootClass, bindingOptions, bindingState, bindingContext );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindVersion(
|
|
||||||
AttributeMetadata versionAttribute,
|
|
||||||
RootClass typeBinding,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final Property property = new Property();
|
|
||||||
property.setName( versionAttribute.getName() );
|
|
||||||
typeBinding.setVersion( property );
|
|
||||||
typeBinding.addProperty( property );
|
|
||||||
|
|
||||||
final BasicValue basicValue = new BasicValue(
|
|
||||||
bindingState.getMetadataBuildingContext(),
|
|
||||||
typeBinding.getRootTable()
|
|
||||||
);
|
|
||||||
property.setValue( basicValue );
|
|
||||||
|
|
||||||
final MemberDetails memberDetails = versionAttribute.getMember();
|
|
||||||
bindImplicitJavaType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindJavaType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindJdbcType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
|
|
||||||
final org.hibernate.mapping.Column column = processColumn(
|
|
||||||
memberDetails,
|
|
||||||
property,
|
|
||||||
basicValue,
|
|
||||||
typeBinding.getRootTable(),
|
|
||||||
bindingOptions,
|
|
||||||
bindingState,
|
|
||||||
bindingContext
|
|
||||||
);
|
|
||||||
// force it to be non-nullable
|
|
||||||
column.setNullable( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindVersion(
|
|
||||||
AttributeMetadata attributeMetadata,
|
|
||||||
EntityTypeMetadata managedType,
|
|
||||||
RootClass typeBinding,
|
|
||||||
BindingOptions bindingOptions,
|
|
||||||
BindingState bindingState,
|
|
||||||
BindingContext bindingContext) {
|
|
||||||
final Property property = new Property();
|
|
||||||
property.setName( attributeMetadata.getName() );
|
|
||||||
typeBinding.setVersion( property );
|
|
||||||
typeBinding.addProperty( property );
|
|
||||||
|
|
||||||
final BasicValue basicValue = new BasicValue(
|
|
||||||
bindingState.getMetadataBuildingContext(),
|
|
||||||
typeBinding.getRootTable()
|
|
||||||
);
|
|
||||||
property.setValue( basicValue );
|
|
||||||
|
|
||||||
final MemberDetails memberDetails = attributeMetadata.getMember();
|
|
||||||
bindImplicitJavaType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindJavaType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
bindJdbcType( memberDetails, property, basicValue, bindingOptions, bindingState, bindingContext );
|
|
||||||
|
|
||||||
final org.hibernate.mapping.Column column = processColumn(
|
|
||||||
memberDetails,
|
|
||||||
property,
|
|
||||||
basicValue,
|
|
||||||
typeBinding.getRootTable(),
|
|
||||||
bindingOptions,
|
|
||||||
bindingState,
|
|
||||||
bindingContext
|
|
||||||
);
|
|
||||||
// force it to be non-nullable
|
|
||||||
column.setNullable( false );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@
|
||||||
package org.hibernate.orm.test.boot.models.bind.tenancy;
|
package org.hibernate.orm.test.boot.models.bind.tenancy;
|
||||||
|
|
||||||
import org.hibernate.annotations.TenantId;
|
import org.hibernate.annotations.TenantId;
|
||||||
import org.hibernate.boot.models.bind.internal.binders.TenantIdBinder;
|
import org.hibernate.boot.models.bind.internal.BasicValueHelper;
|
||||||
import org.hibernate.mapping.BasicValue;
|
import org.hibernate.mapping.BasicValue;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
@ -38,7 +38,7 @@ public class SimpleTenancyTests {
|
||||||
(context) -> {
|
(context) -> {
|
||||||
var metadataCollector = context.getMetadataCollector();
|
var metadataCollector = context.getMetadataCollector();
|
||||||
|
|
||||||
assertThat( metadataCollector.getFilterDefinition( TenantIdBinder.FILTER_NAME ) ).isNotNull();
|
assertThat( metadataCollector.getFilterDefinition( BasicValueHelper.TENANT_FILTER_NAME ) ).isNotNull();
|
||||||
|
|
||||||
final PersistentClass entityBinding = metadataCollector.getEntityBinding( ProtectedEntity.class.getName() );
|
final PersistentClass entityBinding = metadataCollector.getEntityBinding( ProtectedEntity.class.getName() );
|
||||||
final Property tenantProperty = entityBinding.getProperty( "tenant" );
|
final Property tenantProperty = entityBinding.getProperty( "tenant" );
|
||||||
|
@ -65,7 +65,7 @@ public class SimpleTenancyTests {
|
||||||
(context) -> {
|
(context) -> {
|
||||||
var metadataCollector = context.getMetadataCollector();
|
var metadataCollector = context.getMetadataCollector();
|
||||||
|
|
||||||
assertThat( metadataCollector.getFilterDefinition( TenantIdBinder.FILTER_NAME ) ).isNotNull();
|
assertThat( metadataCollector.getFilterDefinition( BasicValueHelper.TENANT_FILTER_NAME ) ).isNotNull();
|
||||||
|
|
||||||
final PersistentClass entityBinding = metadataCollector.getEntityBinding( ProtectedEntityWithColumn.class.getName() );
|
final PersistentClass entityBinding = metadataCollector.getEntityBinding( ProtectedEntityWithColumn.class.getName() );
|
||||||
final Property tenantProperty = entityBinding.getProperty( "tenant" );
|
final Property tenantProperty = entityBinding.getProperty( "tenant" );
|
||||||
|
|
Loading…
Reference in New Issue