org.hibernate.mapping.BasicValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of beangle-hibernate-core Show documentation
Show all versions of beangle-hibernate-core Show documentation
Hibernate Orm Core Shade,Support Scala Collection
/*
* 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.mapping;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.function.Function;
import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.TimeZoneStorageType;
import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext;
import org.hibernate.boot.model.process.internal.EnumeratedValueResolution;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolution;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
import org.hibernate.boot.model.process.internal.NamedBasicTypeResolution;
import org.hibernate.boot.model.process.internal.NamedConverterResolution;
import org.hibernate.boot.model.process.internal.UserTypeResolution;
import org.hibernate.boot.model.process.internal.VersionResolution;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectablePath;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.Type;
import org.hibernate.type.WrapperArrayHandling;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.BasicJavaType;
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.UserType;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.EnumType;
import jakarta.persistence.TemporalType;
import static org.hibernate.mapping.MappingHelper.injectParameters;
/**
* @author Steve Ebersole
*/
public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resolvable {
private static final CoreMessageLogger log = CoreLogging.messageLogger( BasicValue.class );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// incoming "configuration" values
private String explicitTypeName;
private Map explicitLocalTypeParams;
private Function explicitJavaTypeAccess;
private Function explicitJdbcTypeAccess;
private Function explicitMutabilityPlanAccess;
private Function implicitJavaTypeAccess;
private EnumType enumerationStyle;
private TemporalType temporalPrecision;
private TimeZoneStorageType timeZoneStorageType;
private java.lang.reflect.Type resolvedJavaType;
private String ownerName;
private String propertyName;
private AggregateColumn aggregateColumn;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Resolved state - available after `#resolve`
private Resolution> resolution;
public BasicValue(MetadataBuildingContext buildingContext) {
this( buildingContext, null );
}
public BasicValue(MetadataBuildingContext buildingContext, Table table) {
super( buildingContext, table );
buildingContext.getMetadataCollector().registerValueMappingResolver( this::resolve );
}
public BasicValue(BasicValue original) {
super( original );
this.explicitTypeName = original.explicitTypeName;
this.explicitLocalTypeParams = original.explicitLocalTypeParams == null
? null
: new HashMap<>(original.explicitLocalTypeParams);
this.explicitJavaTypeAccess = original.explicitJavaTypeAccess;
this.explicitJdbcTypeAccess = original.explicitJdbcTypeAccess;
this.explicitMutabilityPlanAccess = original.explicitMutabilityPlanAccess;
this.implicitJavaTypeAccess = original.implicitJavaTypeAccess;
this.enumerationStyle = original.enumerationStyle;
this.temporalPrecision = original.temporalPrecision;
this.timeZoneStorageType = original.timeZoneStorageType;
this.resolvedJavaType = original.resolvedJavaType;
this.ownerName = original.ownerName;
this.propertyName = original.propertyName;
}
@Override
public BasicValue copy() {
return new BasicValue( this );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Setters - in preparation of resolution
@Override
public void setTypeUsingReflection(String className, String propertyName) throws MappingException {
if ( resolution != null ) {
throw new IllegalStateException( "BasicValue already resolved" );
}
this.ownerName = className;
this.propertyName = propertyName;
super.setTypeUsingReflection( className, propertyName );
}
public void setEnumerationStyle(EnumType enumerationStyle) {
this.enumerationStyle = enumerationStyle;
}
public EnumType getEnumerationStyle() {
return enumerationStyle;
}
public TimeZoneStorageType getTimeZoneStorageType() {
return timeZoneStorageType;
}
public void setTimeZoneStorageType(TimeZoneStorageType timeZoneStorageType) {
this.timeZoneStorageType = timeZoneStorageType;
}
public void setJpaAttributeConverterDescriptor(ConverterDescriptor descriptor) {
setAttributeConverterDescriptor( descriptor );
super.setJpaAttributeConverterDescriptor( descriptor );
}
@SuppressWarnings("rawtypes")
public void setExplicitJavaTypeAccess(Function explicitJavaTypeAccess) {
this.explicitJavaTypeAccess = explicitJavaTypeAccess;
}
public void setExplicitJdbcTypeAccess(Function jdbcTypeAccess) {
this.explicitJdbcTypeAccess = jdbcTypeAccess;
}
public void setExplicitMutabilityPlanAccess(Function explicitMutabilityPlanAccess) {
this.explicitMutabilityPlanAccess = explicitMutabilityPlanAccess;
}
public void setImplicitJavaTypeAccess(Function implicitJavaTypeAccess) {
this.implicitJavaTypeAccess = implicitJavaTypeAccess;
}
public Selectable getColumn() {
if ( getColumnSpan() == 0 ) {
return null;
}
return getColumn( 0 );
}
public java.lang.reflect.Type getResolvedJavaType() {
return resolvedJavaType;
}
@Override
public long getColumnLength() {
final Selectable column = getColumn();
if ( column instanceof Column ) {
final Long length = ( (Column) column ).getLength();
return length == null ? NO_COLUMN_LENGTH : length;
}
else {
return NO_COLUMN_LENGTH;
}
}
@Override
public int getColumnPrecision() {
final Selectable column = getColumn();
if ( column instanceof Column ) {
final Integer length = ( (Column) column ).getPrecision();
return length == null ? NO_COLUMN_PRECISION : length;
}
else {
return NO_COLUMN_PRECISION;
}
}
@Override
public int getColumnScale() {
final Selectable column = getColumn();
if ( column instanceof Column ) {
final Integer length = ( (Column) column ).getScale();
return length == null ? NO_COLUMN_SCALE : length;
}
else {
return NO_COLUMN_SCALE;
}
}
@Override
public void addColumn(Column incomingColumn) {
super.addColumn( incomingColumn );
checkSelectable( incomingColumn );
}
@Override
public void copyTypeFrom(SimpleValue sourceValue) {
super.copyTypeFrom( sourceValue );
if ( sourceValue instanceof BasicValue ) {
final BasicValue basicValue = (BasicValue) sourceValue;
this.resolution = basicValue.resolution;
this.implicitJavaTypeAccess = (typeConfiguration) -> basicValue.implicitJavaTypeAccess.apply( typeConfiguration );
}
}
private void checkSelectable(Selectable incomingColumn) {
if ( incomingColumn == null ) {
throw new IllegalArgumentException( "Incoming column was null" );
}
final Selectable column = getColumn();
if ( column == incomingColumn || column.getText().equals( incomingColumn.getText() ) ) {
log.debugf( "Skipping column re-registration: %s.%s", getTable().getName(), column.getText() );
return;
}
// throw new IllegalStateException(
// "BasicValue [" + ownerName + "." + propertyName +
// "] already had column associated: `" + column.getText() +
// "` -> `" + incomingColumn.getText() + "`"
// );
}
@Override
public void addColumn(Column incomingColumn, boolean isInsertable, boolean isUpdatable) {
super.addColumn( incomingColumn, isInsertable, isUpdatable );
checkSelectable( incomingColumn );
}
@Override
public void addFormula(Formula formula) {
super.addFormula( formula );
checkSelectable( formula );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Resolution
@Override
public Type getType() throws MappingException {
resolve();
assert getResolution() != null;
return getResolution().getLegacyResolvedBasicType();
}
public Resolution> getResolution() {
return resolution;
}
@Override
public boolean resolve(MetadataBuildingContext buildingContext) {
resolve();
return true;
}
@Override
public Resolution> resolve() {
if ( resolution != null ) {
return resolution;
}
resolution = buildResolution();
if ( resolution == null ) {
throw new IllegalStateException( "Unable to resolve BasicValue : " + this );
}
final Selectable selectable = getColumn();
if ( selectable instanceof Column ) {
resolveColumn( (Column) selectable, getDialect() );
}
return resolution;
}
@Override
public Dialect getDialect() {
return getMetadata().getDatabase().getDialect();
}
private void resolveColumn(Column column, Dialect dialect) {
if ( column.getSqlTypeCode() == null ) {
column.setSqlTypeCode( resolution.getJdbcType().getDdlTypeCode() );
}
if ( resolution.getValueConverter() != null && column.getSqlType() == null ) {
final String declaration = resolution.getLegacyResolvedBasicType().getSpecializedTypeDeclaration(dialect);
if ( declaration != null ) {
column.setSpecializedTypeDeclaration( declaration );
}
}
if ( dialect.supportsColumnCheck() ) {
final String checkCondition = resolution.getLegacyResolvedBasicType()
.getCheckCondition( column.getQuotedName( dialect ), dialect );
if ( checkCondition != null ) {
column.addCheckConstraint( new CheckConstraint( checkCondition ) );
}
}
}
public AggregateColumn getAggregateColumn() {
return aggregateColumn;
}
public void setAggregateColumn(AggregateColumn aggregateColumn) {
this.aggregateColumn = aggregateColumn;
}
public SelectablePath createSelectablePath(String selectableName) {
if ( aggregateColumn != null ) {
return aggregateColumn.getSelectablePath().append( selectableName );
}
return new SelectablePath( selectableName );
}
protected Resolution> buildResolution() {
Properties typeParameters = getTypeParameters();
if ( typeParameters != null
&& Boolean.parseBoolean( typeParameters.getProperty( DynamicParameterizedType.IS_DYNAMIC ) )
&& typeParameters.get( DynamicParameterizedType.PARAMETER_TYPE ) == null ) {
createParameterImpl();
}
if ( explicitTypeName != null ) {
return interpretExplicitlyNamedType(
explicitTypeName,
explicitJavaTypeAccess,
explicitJdbcTypeAccess,
explicitMutabilityPlanAccess,
getAttributeConverterDescriptor(),
typeParameters,
this::setTypeParameters,
this,
getBuildingContext()
);
}
if ( isVersion() ) {
return VersionResolution.from(
implicitJavaTypeAccess,
timeZoneStorageType,
getBuildingContext()
);
}
// determine JavaType if we can
final BasicJavaType explicitJavaType = explicitJavaTypeAccess == null ? null
: explicitJavaTypeAccess.apply( getTypeConfiguration() );
final JavaType> javaType = determineJavaType( explicitJavaType );
final ConverterDescriptor attributeConverterDescriptor = getAttributeConverterDescriptor();
final Selectable column = getColumn();
if ( attributeConverterDescriptor != null ) {
final ManagedBeanRegistry managedBeanRegistry = getServiceRegistry().getService( ManagedBeanRegistry.class );
final NamedConverterResolution> converterResolution = NamedConverterResolution.from(
attributeConverterDescriptor,
explicitJavaTypeAccess,
explicitJdbcTypeAccess,
explicitMutabilityPlanAccess,
this,
new JpaAttributeConverterCreationContext() {
@Override
public ManagedBeanRegistry getManagedBeanRegistry() {
return managedBeanRegistry;
}
@Override
public TypeConfiguration getTypeConfiguration() {
return BasicValue.this.getTypeConfiguration();
}
},
getBuildingContext()
);
if ( javaType instanceof BasicPluralJavaType>
&& !attributeConverterDescriptor.getDomainValueResolvedType()
.getErasedType()
.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
// In this case, the converter applies to the element of a BasicPluralJavaType
final BasicPluralJavaType> containerJtd = (BasicPluralJavaType>) javaType;
final BasicType registeredElementType = converterResolution.getLegacyResolvedBasicType();
final BasicType> registeredType = registeredElementType == null ? null
: containerJtd.resolveType(
getTypeConfiguration(),
getDialect(),
registeredElementType,
column instanceof ColumnTypeInformation ? (ColumnTypeInformation) column : null,
this
);
if ( registeredType != null ) {
getTypeConfiguration().getBasicTypeRegistry().register( registeredType );
return new InferredBasicValueResolution(
registeredType,
registeredType.getJavaTypeDescriptor(),
registeredType.getJavaTypeDescriptor(),
registeredType.getJdbcType(),
registeredType,
null
);
}
}
return converterResolution;
}
final JdbcType jdbcType = explicitJdbcTypeAccess != null
? explicitJdbcTypeAccess.apply( getTypeConfiguration() )
: null;
final JavaType> basicJavaType = javaType == null && jdbcType != null
? jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, getTypeConfiguration() )
: javaType;
if ( basicJavaType == null ) {
throw new MappingException( "Unable to determine JavaType to use : " + this );
}
final TypeDefinition autoAppliedTypeDef = basicJavaType instanceof BasicJavaType>
? getBuildingContext().getTypeDefinitionRegistry().resolveAutoApplied( (BasicJavaType>) basicJavaType )
: null;
if ( autoAppliedTypeDef != null
&& ( !basicJavaType.getJavaTypeClass().isEnum() || enumerationStyle == null ) ) {
log.debug( "BasicValue resolution matched auto-applied type-definition" );
return autoAppliedTypeDef.resolve( typeParameters, null, getBuildingContext(), this );
}
else {
return InferredBasicValueResolver.from(
explicitJavaType,
jdbcType,
resolvedJavaType,
this::determineReflectedJavaType,
explicitMutabilityPlanAccess,
this,
getTable(),
column,
ownerName,
propertyName,
getBuildingContext()
);
}
}
private JavaType> determineJavaType(JavaType> explicitJavaType) {
JavaType> javaType = explicitJavaType;
if ( javaType == null ) {
if ( implicitJavaTypeAccess != null ) {
final java.lang.reflect.Type implicitJtd = implicitJavaTypeAccess.apply( getTypeConfiguration() );
if ( implicitJtd != null ) {
javaType = getTypeConfiguration().getJavaTypeRegistry().getDescriptor( implicitJtd );
}
}
}
if ( javaType == null ) {
final JavaType> reflectedJtd = determineReflectedJavaType();
if ( reflectedJtd != null ) {
javaType = reflectedJtd;
}
}
return javaType;
}
private JavaType> determineReflectedJavaType() {
final java.lang.reflect.Type impliedJavaType;
if ( resolvedJavaType != null ) {
impliedJavaType = resolvedJavaType;
}
else if ( implicitJavaTypeAccess != null ) {
impliedJavaType = implicitJavaTypeAccess.apply( getTypeConfiguration() );
}
else if ( ownerName != null && propertyName != null ) {
impliedJavaType = ReflectHelper.reflectedPropertyType(
ownerName,
propertyName,
getServiceRegistry().getService( ClassLoaderService.class )
);
}
else {
return null;
}
resolvedJavaType = impliedJavaType;
if ( impliedJavaType == null ) {
return null;
}
return getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor( impliedJavaType );
}
private static Resolution> interpretExplicitlyNamedType(
String name,
Function explicitJtdAccess,
Function explicitStdAccess,
Function explicitMutabilityPlanAccess,
ConverterDescriptor converterDescriptor,
Map
© 2015 - 2024 Weber Informatics LLC | Privacy Policy