Skip to content

Commit

Permalink
Introduce VirtualIdEmbeddable and IdClassEmbeddable + instantiators
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sebersole committed Dec 1, 2021
1 parent 42d1fcc commit 82d884d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

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;
Expand Down Expand Up @@ -67,10 +69,13 @@ public EmbeddableRepresentationStrategyPojo(
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(
Expand All @@ -80,6 +85,14 @@ private EmbeddableInstantiator determineInstantiator(Supplier<EmbeddableMappingT
);
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -160,23 +161,34 @@ public void initializeInstance(RowProcessingState processingState) {

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 );
}
}
}
Expand All @@ -197,18 +209,8 @@ private void prepareCompositeInstance(RowProcessingState processingState) {
&& 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 ) {
Expand Down Expand Up @@ -240,6 +242,40 @@ private void extractRowState(RowProcessingState processingState) {
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(
Expand All @@ -251,7 +287,11 @@ private Object createCompositeInstance(
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 );

Expand Down Expand Up @@ -343,43 +383,6 @@ private Object determineParentInstance(RowProcessingState processingState) {
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;
Expand Down

0 comments on commit 82d884d

Please sign in to comment.