diff --git a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java index 1ba92b36f6c5..bb28e433eccb 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java @@ -13,6 +13,7 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; import org.hibernate.FetchMode; import org.hibernate.HibernateException; @@ -54,8 +55,8 @@ * @author Gavin King */ public class ComponentType extends AbstractType implements CompositeTypeImplementor, ProcedureParameterExtractionAware { - private final Class componentClass; - private final boolean mutable; + private Supplier> componentClass; + private Supplier mutable; private final String[] propertyNames; private final Type[] propertyTypes; @@ -79,14 +80,48 @@ public ComponentType(Component component, int[] originalPropertyOrder, MetadataB } public ComponentType(Component component, int[] originalPropertyOrder) { - this( component, originalPropertyOrder, - component.getComponentClassName() != null - && !isRecord( component.getComponentClass() ) ); + this( component, originalPropertyOrder, (Boolean) null); } public ComponentType(Component component, int[] originalPropertyOrder, boolean mutable) { - this.componentClass = component.isDynamic() ? Map.class : component.getComponentClass(); - this.mutable = mutable; + this(component, originalPropertyOrder, (Boolean) mutable); + } + + private ComponentType(final Component component, int[] originalPropertyOrder, Boolean mutable) { + // As mutable and componentClass are based on the actual component + // type, both variables must be lazily initialized in some cases. + // E.g. on code generation by hibernate-tools, the component type + // might not yet exist (compound keys), resulting in a + // ClassNotFoundException. + // + // The lazy initialization is performance optimized as far as possible. + + if(mutable != null) { + this.mutable = () -> mutable; + } + else { + this.mutable = () -> { + final Class clazz = component.getComponentClass(); + final boolean mutableVal = ( clazz != null && !isRecord(clazz) ); + + this.mutable = () -> mutableVal; + + return mutableVal; + }; + } + + if(component.isDynamic()) { + this.componentClass = () -> Map.class; + } + else { + this.componentClass = () -> { + final Class clazz = component.getComponentClass(); + this.componentClass = () -> clazz; + + return clazz; + }; + } + this.isAggregate = component.getAggregateColumn() != null; this.isKey = component.isKey(); this.propertySpan = component.getPropertySpan(); @@ -165,7 +200,7 @@ public final boolean isComponentType() { } public Class getReturnedClass() { - return componentClass; + return componentClass.get(); } @Override @@ -585,7 +620,7 @@ public CascadeStyle getCascadeStyle(int i) { @Override public boolean isMutable() { - return mutable; + return mutable.get(); } @Override @@ -822,7 +857,7 @@ protected final EmbeddableInstantiator instantiator(Object compositeInstance) { if ( embeddableTypeDescriptor().isPolymorphic() ) { final String compositeClassName = compositeInstance != null ? compositeInstance.getClass().getName() : - componentClass.getName(); + componentClass.get().getName(); return representationStrategy.getInstantiatorForClass( compositeClassName ); } else {