Skip to content

Commit

Permalink
Introduce VirtualIdEmbeddable and IdClassEmbeddable + instantiators
Browse files Browse the repository at this point in the history
Move all component instantiations to use the new mapping model EmbeddableInstantiator

Still need to
  - 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
  - clean up ComponentType, esp wrt its use of ComponentTuplizer
  • Loading branch information
sebersole committed Dec 1, 2021
1 parent 5b44aa5 commit eb5afb0
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.tuple.component;

import java.lang.reflect.Method;
import java.util.Iterator;

Expand All @@ -13,7 +14,6 @@
import org.hibernate.mapping.Property;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.tuple.Instantiator;

/**
* Support for tuplizers relating to components.
Expand All @@ -25,10 +25,8 @@ public abstract class AbstractComponentTuplizer implements ComponentTuplizer {
protected final Getter[] getters;
protected final Setter[] setters;
protected final int propertySpan;
protected final Instantiator instantiator;
protected final boolean hasCustomAccessors;

protected abstract Instantiator buildInstantiator(Component component);
protected abstract Getter buildGetter(Component component, Property prop);
protected abstract Setter buildSetter(Component component, Property prop);

Expand All @@ -51,7 +49,6 @@ protected AbstractComponentTuplizer(Component component) {
i++;
}
hasCustomAccessors = foundCustomAccessor;
instantiator = buildInstantiator( component );
}

public Object getPropertyValue(Object component, int i) throws HibernateException {
Expand All @@ -72,13 +69,6 @@ public void setPropertyValues(Object component, Object[] values) throws Hibernat
}
}

/**
* This method does not populate the component parent
*/
public Object instantiate() throws HibernateException {
return instantiator.instantiate();
}

public boolean isMethodOf(Method method) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@ public interface ComponentTuplizer extends Tuplizer, Serializable {
*/
public boolean isMethodOf(Method method);

/**
* Generate a new, empty entity.
*
* @return The new, empty entity instance.
*/
public Object instantiate();

/**
* Extract the current values contained on the given entity.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.tuple.DynamicMapInstantiator;
import org.hibernate.tuple.Instantiator;

/**
* A {@link ComponentTuplizer} specific to the dynamic-map entity mode.
Expand All @@ -27,10 +25,6 @@ public Class getMappedClass() {
return Map.class;
}

protected Instantiator buildInstantiator(Component component) {
return new DynamicMapInstantiator();
}

public DynamicMapComponentTuplizer(Component component) {
super(component);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
import org.hibernate.cfg.Environment;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
Expand All @@ -24,7 +23,6 @@
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PojoInstantiator;

/**
* A {@link ComponentTuplizer} specific to the pojo entity mode.
Expand Down Expand Up @@ -110,19 +108,6 @@ public boolean isMethodOf(Method method) {
return false;
}

protected Instantiator buildInstantiator(Component component) {
if ( component.isEmbedded() && ReflectHelper.isAbstractClass( this.componentClass ) ) {
ProxyFactoryFactory proxyFactoryFactory = component.getServiceRegistry().getService( ProxyFactoryFactory.class );
return new ProxiedInstantiator( this.componentClass, proxyFactoryFactory );
}
if ( optimizer == null ) {
return new PojoInstantiator( this.componentClass, null );
}
else {
return new PojoInstantiator( this.componentClass, optimizer.getInstantiationOptimizer() );
}
}

protected Getter buildGetter(Component component, Property prop) {
return prop.getGetter( this.componentClass );
}
Expand Down
107 changes: 58 additions & 49 deletions hibernate-core/src/main/java/org/hibernate/type/ComponentType.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.tuple.StandardProperty;
import org.hibernate.tuple.ValueGeneration;
Expand Down Expand Up @@ -466,19 +467,20 @@ public String[] getPropertyNames() {
}

@Override
public Object deepCopy(Object component, SessionFactoryImplementor factory)
throws HibernateException {
public Object deepCopy(Object component, SessionFactoryImplementor factory) {
if ( component == null ) {
return null;
}

Object[] values = getPropertyValues( component );
final Object[] values = getPropertyValues( component );
for ( int i = 0; i < propertySpan; i++ ) {
values[i] = propertyTypes[i].deepCopy( values[i], factory );
}

Object result = instantiate();
setPropertyValues( result, values );
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
Object result = instantiator.instantiate( () -> values, factory );

//not absolutely necessary, but helps for some
//equals()/hashCode() implementations
Expand All @@ -496,29 +498,42 @@ public Object replace(
Object target,
SharedSessionContractImplementor session,
Object owner,
Map copyCache)
throws HibernateException {
Map copyCache) {

if ( original == null ) {
return null;
}
//if ( original == target ) return target;

final Object result = target == null
? instantiate( owner, session )
: target;
final Object[] originalValues = getPropertyValues( original );
final Object[] resultValues;

if ( target == null ) {
resultValues = new Object[originalValues.length];
}
else {
resultValues = getPropertyValues( target );
}

Object[] values = TypeHelper.replace(
getPropertyValues( original ),
getPropertyValues( result ),
final Object[] replacedValues = TypeHelper.replace(
originalValues,
resultValues,
propertyTypes,
session,
owner,
copyCache
);

setPropertyValues( result, values );
return result;
if ( target == null ) {
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> replacedValues, session.getSessionFactory() );
}
else {
setPropertyValues( target, replacedValues );
return target;
}
}

@Override
Expand All @@ -528,52 +543,44 @@ public Object replace(
SharedSessionContractImplementor session,
Object owner,
Map copyCache,
ForeignKeyDirection foreignKeyDirection)
throws HibernateException {
ForeignKeyDirection foreignKeyDirection) {

if ( original == null ) {
return null;
}
//if ( original == target ) return target;

final Object result = target == null ?
instantiate( owner, session ) :
target;

Object[] values = TypeHelper.replace(
getPropertyValues( original ),
getPropertyValues( result ),
final Object[] originalValues = getPropertyValues( original );
final Object[] resultValues;

if ( target == null ) {
resultValues = new Object[originalValues.length];
}
else {
resultValues = getPropertyValues( target );
}

final Object[] replacedValues = TypeHelper.replace(
originalValues,
resultValues,
propertyTypes,
session,
owner,
copyCache,
foreignKeyDirection
);

setPropertyValues( result, values );
return result;
}

/**
* This method does not populate the component parent
*/
public Object instantiate() {
return componentTuplizer.instantiate();
}

public Object instantiate(Object parent, SharedSessionContractImplementor session) {
Object result = instantiate();

final PropertyAccess parentAccess = mappingModelPart().getParentInjectionAttributePropertyAccess();
if ( parentAccess != null && parent != null ) {
parentAccess.getSetter().set(
result,
session.getPersistenceContextInternal().proxyFor( parent ),
session.getFactory()
);
if ( target == null ) {
final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> replacedValues, session.getSessionFactory() );
}
else {
setPropertyValues( target, replacedValues );
return target;
}

return result;
}

@Override
Expand Down Expand Up @@ -615,9 +622,11 @@ public Object assemble(Serializable object, SharedSessionContractImplementor ses
for ( int i = 0; i < propertyTypes.length; i++ ) {
assembled[i] = propertyTypes[i].assemble( (Serializable) values[i], session, owner );
}
Object result = instantiate( owner, session );
setPropertyValues( result, assembled );
return result;

final EmbeddableInstantiator instantiator = mappingModelPart.getEmbeddableTypeDescriptor()
.getRepresentationStrategy()
.getInstantiator();
return instantiator.instantiate( () -> assembled, session.getFactory() );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

import java.lang.reflect.Method;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.tuple.component.ComponentMetamodel;
import org.hibernate.type.spi.TypeConfiguration;

Expand All @@ -28,15 +26,4 @@ public boolean isEmbedded() {
public boolean isMethodOf(Method method) {
return componentTuplizer.isMethodOf( method );
}

@Override
public Object instantiate(Object parent, SharedSessionContractImplementor session) throws HibernateException {
final boolean useParent = parent != null &&
//TODO: Yuck! This is not quite good enough, it's a quick
//hack around the problem of having a to-one association
//that refers to an embedded component:
super.getReturnedClass().isInstance( parent );

return useParent ? parent : super.instantiate( parent, session );
}
}

0 comments on commit eb5afb0

Please sign in to comment.