Skip to content

Commit

Permalink
#95 - Bind hierarchy details
Browse files Browse the repository at this point in the history
- version
- tenancy
  • Loading branch information
sebersole committed Nov 21, 2023
1 parent af44b0f commit 3911806
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,19 @@
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.QuotedIdentifierTarget;
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.mapping.BasicValue;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
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.descriptor.java.MutabilityPlan;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;

import static org.hibernate.boot.models.categorize.spi.AttributeMetadata.AttributeNature.BASIC;

Expand Down Expand Up @@ -238,7 +231,7 @@ default boolean process() {
}
}

private static org.hibernate.mapping.Column processColumn(
public static org.hibernate.mapping.Column processColumn(
MemberDetails member,
Property property,
BasicValue basicValue,
Expand All @@ -250,7 +243,7 @@ private static org.hibernate.mapping.Column processColumn(
final var columnAnn = member.getAnnotationUsage( Column.class );
final var column = ColumnBinder.bindColumn( columnAnn, property::getName );

var tableName = BindingHelper.getValue( columnAnn, "table", (String) null );
var tableName = BindingHelper.getValue( columnAnn, "table", "" );
if ( "".equals( tableName ) || tableName == null ) {
basicValue.setTable( primaryTable );
}
Expand All @@ -265,7 +258,7 @@ private static org.hibernate.mapping.Column processColumn(
return column;
}

private static void bindConversion(
public static void bindConversion(
MemberDetails member,
@SuppressWarnings("unused") Property property,
@SuppressWarnings("unused") BasicValue basicValue,
Expand Down Expand Up @@ -294,23 +287,4 @@ private static void bindConversion(
) );
}

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 );

final BasicValue basicValue = new BasicValue( bindingState.getMetadataBuildingContext(), typeBinding.getRootTable() );
property.setValue( basicValue );

final MemberDetails member = attributeMetadata.getMember();
bindImplicitJavaType( member, property, basicValue, bindingOptions, bindingState, bindingContext );

processColumn( member, property, basicValue, typeBinding.getRootTable(), bindingOptions, bindingState, bindingContext );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -495,25 +495,13 @@ private void prepareRootEntityBinding(RootClass typeBinding, ModelBinders modelB
bindIdentifier( getManagedType(), typeBinding, modelBinders, getBindingState(), getOptions(), getBindingContext() );
bindDiscriminator( getManagedType(), typeBinding, modelBinders, getOptions(), getBindingState(), getBindingContext() );
bindVersion( getManagedType(), typeBinding, modelBinders, getOptions(), getBindingState(), getBindingContext() );
bindTenantId( getManagedType(), typeBinding, modelBinders, getOptions(), getBindingState(), getBindingContext() );

processSoftDelete( typeBinding.getIdentityTable(), typeBinding, getManagedType().getClassDetails() );
processOptimisticLocking( typeBinding, getManagedType().getClassDetails() );
processCacheRegions( getManagedType(), typeBinding, getManagedType().getClassDetails() );
}

private static void bindVersion(
EntityTypeMetadata managedType,
RootClass typeBinding,
ModelBinders modelBinders,
BindingOptions options,
BindingState bindingState,
BindingContext bindingContext) {
final AttributeMetadata versionAttribute = managedType.getHierarchy().getVersionAttribute();
if ( versionAttribute != null ) {
AttributeBinder.bindVersion( versionAttribute, managedType, typeBinding, options, bindingState, bindingContext );
}
}

private static void bindDiscriminator(
EntityTypeMetadata managedType,
RootClass typeBinding,
Expand Down Expand Up @@ -581,6 +569,33 @@ private static void bindDiscriminator(
value.setImplicitJavaTypeAccess( typeConfiguration -> discriminatorJavaType );
}

private static void bindVersion(
EntityTypeMetadata managedType,
RootClass typeBinding,
ModelBinders modelBinders,
BindingOptions options,
BindingState bindingState,
BindingContext bindingContext) {
final AttributeMetadata versionAttribute = managedType.getHierarchy().getVersionAttribute();
if ( versionAttribute != null ) {
VersionBinder.bindVersion( versionAttribute, managedType, typeBinding, options, bindingState, bindingContext );
}
}

private void bindTenantId(
EntityTypeMetadata managedType,
RootClass typeBinding,
ModelBinders modelBinders,
BindingOptions options,
BindingState bindingState,
BindingContext bindingContext) {
final AttributeMetadata tenantIdAttribute = managedType.getHierarchy().getTenantIdAttribute();
if ( tenantIdAttribute != null ) {
TenantIdBinder.bindTenantId( tenantIdAttribute, managedType, typeBinding, options, bindingState, bindingContext );
}

}

private void processSoftDelete(
Table primaryTable,
RootClass rootClass,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ protected void prepareBinding(ModelBinders modelBinders) {
final var managedType = getManagedType();

managedType.forEachAttribute( (index, attributeMetadata) -> {
if ( managedType.getHierarchy().getIdMapping().contains( attributeMetadata ) ) {
if ( managedType.getHierarchy().getIdMapping().contains( attributeMetadata )
|| managedType.getHierarchy().getVersionAttribute() == attributeMetadata
|| managedType.getHierarchy().getTenantIdAttribute() == attributeMetadata ) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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(
AttributeMetadata attributeMetadata,
EntityTypeMetadata managedType,
RootClass typeBinding,
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();
typeBinding.addProperty( property );
property.setName( attributeMetadata.getName() );

final BasicValue basicValue = new BasicValue( bindingState.getMetadataBuildingContext(), typeBinding.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,
typeBinding.getRootTable(),
bindingOptions,
bindingState,
bindingContext
);

property.resetUpdateable( false );
property.resetOptional( false );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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(
AttributeMetadata attributeMetadata,
EntityTypeMetadata managedType,
RootClass typeBinding,
BindingOptions bindingOptions,
BindingState bindingState,
BindingContext bindingContext) {
final Property property = new Property();
property.setName( attributeMetadata.getName() );
typeBinding.setVersion( 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 );
}
}
Loading

0 comments on commit 3911806

Please sign in to comment.