HHH-15847 run AttributeBinders in a SecondPass

so that they can do stuff like register converters and not
have the results hammered by the SecondPass registered by
BasicValueBinder.
This commit is contained in:
Gavin 2022-12-11 14:15:45 +01:00 committed by Gavin King
parent 2b7eb6fc1c
commit 33faa5b060
3 changed files with 24 additions and 36 deletions

View File

@ -1766,6 +1766,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
* Ugh! But we need this done before we ask Envers to produce its entities. * Ugh! But we need this done before we ask Envers to produce its entities.
*/ */
public void processSecondPasses(MetadataBuildingContext buildingContext) { public void processSecondPasses(MetadataBuildingContext buildingContext) {
assert !inSecondPass;
inSecondPass = true; inSecondPass = true;
try { try {

View File

@ -41,7 +41,6 @@ import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.RootClass; import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.ToOne; import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value; import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.metamodel.spi.EmbeddableInstantiator;
@ -232,8 +231,8 @@ public class PropertyBinder {
basicValueBinder.setAccessType( accessType ); basicValueBinder.setAccessType( accessType );
final SimpleValue propertyValue = basicValueBinder.make(); value = basicValueBinder.make();
setValue( propertyValue );
return makeProperty(); return makeProperty();
} }
@ -266,7 +265,7 @@ public class PropertyBinder {
this.isXToMany = xToMany; this.isXToMany = xToMany;
} }
private Property bind(Property prop) { private Property bind(Property property) {
if ( isId ) { if ( isId ) {
final RootClass rootClass = (RootClass) holder.getPersistentClass(); final RootClass rootClass = (RootClass) holder.getPersistentClass();
//if an xToMany, it has to be wrapped today. //if an xToMany, it has to be wrapped today.
@ -280,7 +279,7 @@ public class PropertyBinder {
new PropertyPreloadedData(null, null, null), new PropertyPreloadedData(null, null, null),
true, true,
false, false,
resolveCustomInstantiator( property, returnedClass ), resolveCustomInstantiator(this.property, returnedClass ),
buildingContext buildingContext
); );
rootClass.setIdentifier( identifier ); rootClass.setIdentifier( identifier );
@ -289,7 +288,7 @@ public class PropertyBinder {
rootClass.setIdentifierMapper( identifier ); rootClass.setIdentifierMapper( identifier );
} }
//FIXME is it good enough? //FIXME is it good enough?
identifier.addProperty( prop ); identifier.addProperty( property );
} }
else { else {
rootClass.setIdentifier( (KeyValue) getValue() ); rootClass.setIdentifier( (KeyValue) getValue() );
@ -297,29 +296,34 @@ public class PropertyBinder {
rootClass.setEmbeddedIdentifier( true ); rootClass.setEmbeddedIdentifier( true );
} }
else { else {
rootClass.setIdentifierProperty( prop ); rootClass.setIdentifierProperty( property );
final MappedSuperclass superclass = getMappedSuperclassOrNull( final MappedSuperclass superclass = getMappedSuperclassOrNull(
declaringClass, declaringClass,
inheritanceStatePerClass, inheritanceStatePerClass,
buildingContext buildingContext
); );
if ( superclass != null ) { if ( superclass != null ) {
superclass.setDeclaredIdentifierProperty(prop); superclass.setDeclaredIdentifierProperty(property);
} }
else { else {
//we know the property is on the actual entity //we know the property is on the actual entity
rootClass.setDeclaredIdentifierProperty( prop ); rootClass.setDeclaredIdentifierProperty( property );
} }
} }
} }
} }
else { else {
holder.addProperty( prop, columns, declaringClass ); holder.addProperty( property, columns, declaringClass );
} }
callAttributeBinders( prop ); if ( buildingContext.getMetadataCollector().isInSecondPass() ) {
callAttributeBinders( property );
}
else {
buildingContext.getMetadataCollector().addSecondPass( persistentClasses -> callAttributeBinders( property ) );
}
return prop; return property;
} }
private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(XProperty property, XClass embeddableClass) { private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(XProperty property, XClass embeddableClass) {
@ -370,6 +374,7 @@ public class PropertyBinder {
property.setUpdateable( updatable ); property.setUpdateable( updatable );
LOG.tracev( "Cascading {0} with {1}", name, cascade ); LOG.tracev( "Cascading {0} with {1}", name, cascade );
return property; return property;
} }

View File

@ -6,17 +6,13 @@
*/ */
package org.hibernate.orm.test.mapping.attributebinder; package org.hibernate.orm.test.mapping.attributebinder;
import java.sql.Types;
import org.hibernate.boot.model.convert.internal.InstanceBasedConverterDescriptor; import org.hibernate.boot.model.convert.internal.InstanceBasedConverterDescriptor;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
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;
import org.hibernate.binder.AttributeBinder; import org.hibernate.binder.AttributeBinder;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.type.YesNoConverter; import org.hibernate.type.YesNoConverter;
import org.hibernate.type.descriptor.java.BasicJavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
//tag::attribute-binder-example[] //tag::attribute-binder-example[]
/** /**
@ -29,26 +25,12 @@ public class YesNoBinder implements AttributeBinder<YesNo> {
MetadataBuildingContext buildingContext, MetadataBuildingContext buildingContext,
PersistentClass persistentClass, PersistentClass persistentClass,
Property property) { Property property) {
final BasicValue booleanValueMapping = (BasicValue) property.getValue(); ( (SimpleValue) property.getValue() ).setJpaAttributeConverterDescriptor(
new InstanceBasedConverterDescriptor(
final BasicJavaType<?> javaType = (BasicJavaType<?>) buildingContext.getBootstrapContext() YesNoConverter.INSTANCE,
.getTypeConfiguration() buildingContext.getBootstrapContext().getClassmateContext()
.getJavaTypeRegistry() )
.getDescriptor( Boolean.class );
final JdbcType jdbcType = buildingContext.getBootstrapContext()
.getTypeConfiguration()
.getJdbcTypeRegistry()
.getDescriptor( Types.CHAR );
final InstanceBasedConverterDescriptor converter = new InstanceBasedConverterDescriptor(
YesNoConverter.INSTANCE,
buildingContext.getBootstrapContext().getClassmateContext()
); );
booleanValueMapping.setExplicitJavaTypeAccess( (typeConfiguration) -> javaType );
booleanValueMapping.setExplicitJdbcTypeAccess( (typeConfiguration) -> jdbcType );
booleanValueMapping.setJpaAttributeConverterDescriptor( converter );
} }
} }
//end::attribute-binder-example[] //end::attribute-binder-example[]