Introduce `VirtualIdEmbeddable` and `IdClassEmbeddable` + instantiators
Prep work for EmbeddableInstantiator - initializer Still need to - integrate EmbeddableInstantiator work - integrate embedded forms. `VirtualIdEmbeddable` does not really need it as it can use the id-mapping itself as the embedded form. But `IdClassEmbedded` should really be integrated - integrate `VirtualKeyEmbeddable` and `VirtualKeyEmbedded` for use as inverse composite fks - share `#finishInit` handling for `EmbeddableMappingType`, `VirtualIdEmbeddable` and `IdClassEmbeddable` - ability to use the containing composite owner as the parent of a composite (legacy behavior is to always use the "first" entity
This commit is contained in:
parent
42d1fcca19
commit
82d884d65c
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.metamodel.internal;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.bytecode.spi.BasicProxyFactory;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
|
||||
/**
|
||||
* EmbeddableInstantiator used for instantiating "proxies" of an embeddable.
|
||||
*/
|
||||
public class EmbeddableInstantiatorProxied implements EmbeddableInstantiator {
|
||||
private final Class<?> proxiedClass;
|
||||
private final BasicProxyFactory factory;
|
||||
|
||||
public EmbeddableInstantiatorProxied(Class proxiedClass, BasicProxyFactory factory) {
|
||||
this.proxiedClass = proxiedClass;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiate(Supplier<Object[]> valuesAccess, SessionFactoryImplementor sessionFactory) {
|
||||
return factory.getProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(Object object, SessionFactoryImplementor sessionFactory) {
|
||||
return proxiedClass.isInstance( object );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameClass(Object object, SessionFactoryImplementor sessionFactory) {
|
||||
return object.getClass() == proxiedClass;
|
||||
}
|
||||
}
|
|
@ -11,9 +11,11 @@ import java.util.function.Supplier;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
|
||||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.mapping.Backref;
|
||||
|
@ -67,10 +69,13 @@ public class EmbeddableRepresentationStrategyPojo extends AbstractEmbeddableRepr
|
|||
false
|
||||
);
|
||||
|
||||
this.instantiator = determineInstantiator( runtimeDescriptorAccess );
|
||||
this.instantiator = determineInstantiator( bootDescriptor, runtimeDescriptorAccess, creationContext );
|
||||
}
|
||||
|
||||
private EmbeddableInstantiator determineInstantiator(Supplier<EmbeddableMappingType> runtimeDescriptorAccess) {
|
||||
private EmbeddableInstantiator determineInstantiator(
|
||||
Component bootDescriptor,
|
||||
Supplier<EmbeddableMappingType> runtimeDescriptorAccess,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
if ( reflectionOptimizer != null && reflectionOptimizer.getInstantiationOptimizer() != null ) {
|
||||
final ReflectionOptimizer.InstantiationOptimizer instantiationOptimizer = reflectionOptimizer.getInstantiationOptimizer();
|
||||
return new EmbeddableInstantiatorPojoOptimized(
|
||||
|
@ -80,6 +85,14 @@ public class EmbeddableRepresentationStrategyPojo extends AbstractEmbeddableRepr
|
|||
);
|
||||
}
|
||||
|
||||
if ( bootDescriptor.isEmbedded() && ReflectHelper.isAbstractClass( bootDescriptor.getComponentClass() ) ) {
|
||||
final ProxyFactoryFactory proxyFactoryFactory = creationContext.getSessionFactory().getServiceRegistry().getService( ProxyFactoryFactory.class );
|
||||
return new EmbeddableInstantiatorProxied(
|
||||
bootDescriptor.getComponentClass(),
|
||||
proxyFactoryFactory.buildBasicProxyFactory( bootDescriptor.getComponentClass() )
|
||||
);
|
||||
}
|
||||
|
||||
return new EmbeddableInstantiatorPojoStandard( getEmbeddableJavaTypeDescriptor(), runtimeDescriptorAccess );
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.sql.results.graph.embeddable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -160,23 +161,34 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
|||
|
||||
if ( compositeInstance != NULL_MARKER ) {
|
||||
notifyResolutionListeners( compositeInstance );
|
||||
|
||||
if ( compositeInstance instanceof HibernateProxy ) {
|
||||
final Initializer parentInitializer = processingState.resolveInitializer( navigablePath.getParent() );
|
||||
if ( parentInitializer != this ) {
|
||||
( (FetchParentAccess) parentInitializer ).registerResolutionListener(
|
||||
(entity) -> setPropertyValuesOnTarget( entity, processingState )
|
||||
(entity) -> representationEmbeddable.setPropertyValues( entity, resolvedValues )
|
||||
);
|
||||
}
|
||||
else {
|
||||
Object target = representationStrategy
|
||||
// At this point, createEmptyCompositesEnabled is always true, so we generate
|
||||
// the composite instance.
|
||||
//
|
||||
// NOTE: `valuesAccess` is set to null to indicate that all values are null,
|
||||
// as opposed to returning the all-null value array. the instantiator
|
||||
// interprets that as the values are not known or were all null.
|
||||
final Supplier<Object[]> valuesAccess = allValuesNull
|
||||
? null
|
||||
: () -> resolvedValues;
|
||||
final Object target = representationStrategy
|
||||
.getInstantiator()
|
||||
.instantiate( null, sessionFactory );
|
||||
setPropertyValuesOnTarget( target, processingState );
|
||||
.instantiate( valuesAccess, sessionFactory);
|
||||
( (HibernateProxy) compositeInstance ).getHibernateLazyInitializer().setImplementation( target );
|
||||
}
|
||||
}
|
||||
else if ( allValuesNull == FALSE ) {
|
||||
setPropertyValuesOnTarget( compositeInstance, processingState );
|
||||
// todo (6.0) : i think this is still called for cases where
|
||||
// we have already done the "ctor injection"
|
||||
representationEmbeddable.setPropertyValues( compositeInstance, resolvedValues );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,18 +209,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
|||
&& embeddableJtd instanceof EntityJavaTypeDescriptor<?>
|
||||
&& !( embedded instanceof CompositeIdentifierMapping )
|
||||
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() ) ) {
|
||||
EmbeddableLoadingLogger.INSTANCE.debugf(
|
||||
"Linking composite instance to fetch-parent [%s] - %s",
|
||||
navigablePath,
|
||||
fetchParentAccess
|
||||
);
|
||||
fetchParentAccess.resolveInstance( processingState );
|
||||
compositeInstance = fetchParentAccess.getInitializedInstance();
|
||||
EmbeddableLoadingLogger.INSTANCE.debugf(
|
||||
"Done linking composite instance to fetch-parent [%s] - %s",
|
||||
navigablePath,
|
||||
compositeInstance
|
||||
);
|
||||
}
|
||||
|
||||
if ( compositeInstance == null ) {
|
||||
|
@ -240,6 +242,40 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
|||
allValuesNull = false;
|
||||
}
|
||||
}
|
||||
|
||||
applyMapsId( processingState );
|
||||
}
|
||||
|
||||
private void applyMapsId(RowProcessingState processingState) {
|
||||
final SharedSessionContractImplementor session = processingState.getSession();
|
||||
if ( embedded instanceof CompositeIdentifierMapping ) {
|
||||
final CompositeIdentifierMapping cid = (CompositeIdentifierMapping) embedded;
|
||||
final EmbeddableMappingType mappedIdEmbeddable = cid.getMappedIdEmbeddableTypeDescriptor();
|
||||
if ( cid.hasContainingClass() ) {
|
||||
final EmbeddableMappingType virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor();
|
||||
if ( virtualIdEmbeddable == mappedIdEmbeddable ) {
|
||||
return;
|
||||
}
|
||||
|
||||
virtualIdEmbeddable.forEachAttributeMapping(
|
||||
(position, virtualIdAttribute) -> {
|
||||
final AttributeMapping mappedIdAttribute = mappedIdEmbeddable.getAttributeMapping( position );
|
||||
|
||||
if ( virtualIdAttribute instanceof ToOneAttributeMapping
|
||||
&& !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute;
|
||||
final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
|
||||
final Object associationKey = fkDescriptor.getAssociationKeyFromSide(
|
||||
resolvedValues[position],
|
||||
toOneAttributeMapping.getSideNature().inverse(),
|
||||
session
|
||||
);
|
||||
resolvedValues[position] = associationKey;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object createCompositeInstance(
|
||||
|
@ -251,7 +287,11 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
|||
return NULL_MARKER;
|
||||
}
|
||||
|
||||
final Object instance = representationStrategy.getInstantiator().instantiate( null, sessionFactory );
|
||||
final Supplier<Object[]> valuesAccess = allValuesNull == TRUE
|
||||
? null
|
||||
: () -> resolvedValues;
|
||||
|
||||
final Object instance = representationStrategy.getInstantiator().instantiate( valuesAccess, sessionFactory );
|
||||
|
||||
EmbeddableLoadingLogger.INSTANCE.debugf( "Created composite instance [%s] : %s", navigablePath, instance );
|
||||
|
||||
|
@ -343,43 +383,6 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
|||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
private void setPropertyValuesOnTarget(Object compositeInstance, RowProcessingState processingState) {
|
||||
applyMapsId( processingState );
|
||||
representationEmbeddable.setPropertyValues( compositeInstance, resolvedValues );
|
||||
}
|
||||
|
||||
private void applyMapsId(RowProcessingState processingState) {
|
||||
final SharedSessionContractImplementor session = processingState.getSession();
|
||||
if ( embedded instanceof CompositeIdentifierMapping ) {
|
||||
final CompositeIdentifierMapping cid = (CompositeIdentifierMapping) embedded;
|
||||
final EmbeddableMappingType mappedIdEmbeddable = cid.getMappedIdEmbeddableTypeDescriptor();
|
||||
if ( cid.hasContainingClass() ) {
|
||||
final EmbeddableMappingType virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor();
|
||||
if ( virtualIdEmbeddable == mappedIdEmbeddable ) {
|
||||
return;
|
||||
}
|
||||
|
||||
virtualIdEmbeddable.forEachAttributeMapping(
|
||||
(position, virtualIdAttribute) -> {
|
||||
final AttributeMapping mappedIdAttribute = mappedIdEmbeddable.getAttributeMapping( position );
|
||||
|
||||
if ( virtualIdAttribute instanceof ToOneAttributeMapping
|
||||
&& !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute;
|
||||
final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
|
||||
final Object associationKey = fkDescriptor.getAssociationKeyFromSide(
|
||||
resolvedValues[position],
|
||||
toOneAttributeMapping.getSideNature().inverse(),
|
||||
session
|
||||
);
|
||||
resolvedValues[position] = associationKey;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||
compositeInstance = null;
|
||||
|
|
Loading…
Reference in New Issue