All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.mapping.SimpleValue Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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 .
 */
package org.hibernate.mapping;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Objects;
import javax.persistence.AttributeConverter;

import org.hibernate.FetchMode;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.XProperty;
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.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BinaryType;
import org.hibernate.type.RowVersionType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter;
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext;
import org.hibernate.type.descriptor.sql.JdbcTypeJavaClassMappings;
import org.hibernate.type.descriptor.sql.LobTypeMappings;
import org.hibernate.type.descriptor.sql.NationalizedTypeMappings;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.DynamicParameterizedType;

/**
 * Any value that maps to columns.
 * @author Gavin King
 */
public class SimpleValue implements KeyValue {
	private static final CoreMessageLogger log = CoreLogging.messageLogger( SimpleValue.class );

	public static final String DEFAULT_ID_GEN_STRATEGY = "assigned";

	private MetadataBuildingContext buildingContext;
	private final MetadataImplementor metadata;

	private final List columns = new ArrayList<>();
	private final List insertability = new ArrayList<>();
	private final List updatability = new ArrayList<>();

	private String typeName;
	private Properties typeParameters;
	private boolean isVersion;
	private boolean isNationalized;
	private boolean isLob;

	private Properties identifierGeneratorProperties;
	private String identifierGeneratorStrategy = DEFAULT_ID_GEN_STRATEGY;
	private String nullValue;
	private Table table;
	private String foreignKeyName;
	private String foreignKeyDefinition;
	private boolean alternateUniqueKey;
	private boolean cascadeDeleteEnabled;

	private ConverterDescriptor attributeConverterDescriptor;
	private Type type;

	/**
	 * @deprecated Use {@link SimpleValue#SimpleValue(MetadataBuildingContext)} instead.
	 */
	@Deprecated
	public SimpleValue(MetadataImplementor metadata) {
		this.metadata = metadata;
	}

	/**
	 * @deprecated Use {@link SimpleValue#SimpleValue(MetadataBuildingContext, Table)} instead.
	 */
	@Deprecated
	public SimpleValue(MetadataImplementor metadata, Table table) {
		this( metadata );
		this.table = table;
	}

	public SimpleValue(MetadataBuildingContext buildingContext) {
		this(buildingContext.getMetadataCollector());
		this.buildingContext = buildingContext;
	}

	public SimpleValue(MetadataBuildingContext buildingContext, Table table) {
		this( buildingContext );
		this.table = table;
	}

	public MetadataImplementor getMetadata() {
		return metadata;
	}

	@Override
	public ServiceRegistry getServiceRegistry() {
		return getMetadata().getMetadataBuildingOptions().getServiceRegistry();
	}

	@Override
	public boolean isCascadeDeleteEnabled() {
		return cascadeDeleteEnabled;
	}

	public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
		this.cascadeDeleteEnabled = cascadeDeleteEnabled;
	}
	
	public void addColumn(Column column) {
		addColumn( column, true, true );
	}

	public void addColumn(Column column, boolean isInsertable, boolean isUpdatable) {
		int index = columns.indexOf( column );
		if ( index == -1 ) {
			columns.add(column);
			insertability.add( isInsertable );
			updatability.add( isUpdatable );
		}
		else {
			if ( insertability.get( index ) != isInsertable ) {
				throw new IllegalStateException( "Same column is added more than once with different values for isInsertable" );
			}
			if ( updatability.get( index ) != isUpdatable ) {
				throw new IllegalStateException( "Same column is added more than once with different values for isUpdatable" );
			}
		}
		column.setValue( this );
		column.setTypeIndex( columns.size() - 1 );
	}

	public void addFormula(Formula formula) {
		columns.add( formula );
		insertability.add( false );
		updatability.add( false );
	}

	@Override
	public boolean hasFormula() {
		Iterator iter = getColumnIterator();
		while ( iter.hasNext() ) {
			Object o = iter.next();
			if (o instanceof Formula) {
				return true;
			}
		}
		return false;
	}

	@Override
	public int getColumnSpan() {
		return columns.size();
	}

	@Override
	public Iterator getColumnIterator() {
		return columns.iterator();
	}

	public List getConstraintColumns() {
		return columns;
	}

	public String getTypeName() {
		return typeName;
	}

	public void setTypeName(String typeName) {
		if ( typeName != null && typeName.startsWith( AttributeConverterTypeAdapter.NAME_PREFIX ) ) {
			final String converterClassName = typeName.substring( AttributeConverterTypeAdapter.NAME_PREFIX.length() );
			final ClassLoaderService cls = getMetadata()
					.getMetadataBuildingOptions()
					.getServiceRegistry()
					.getService( ClassLoaderService.class );
			try {
				final Class converterClass = cls.classForName( converterClassName );
				this.attributeConverterDescriptor = new ClassBasedConverterDescriptor(
						converterClass,
						false,
						( (InFlightMetadataCollector) getMetadata() ).getClassmateContext()
				);
				return;
			}
			catch (Exception e) {
				log.logBadHbmAttributeConverterType( typeName, e.getMessage() );
			}
		}

		this.typeName = typeName;
	}

	public void makeVersion() {
		this.isVersion = true;
	}

	public boolean isVersion() {
		return isVersion;
	}
	public void makeNationalized() {
		this.isNationalized = true;
	}

	public boolean isNationalized() {
		return isNationalized;
	}

	public void makeLob() {
		this.isLob = true;
	}

	public boolean isLob() {
		return isLob;
	}

	public void setTable(Table table) {
		this.table = table;
	}

	@Override
	public void createForeignKey() throws MappingException {}

	@Override
	public void createForeignKeyOfEntity(String entityName) {
		if ( !hasFormula() && !"none".equals(getForeignKeyName())) {
			ForeignKey fk = table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName, getForeignKeyDefinition() );
			fk.setCascadeDeleteEnabled(cascadeDeleteEnabled);
		}
	}

	private IdentifierGenerator identifierGenerator;

	@Override
	public IdentifierGenerator createIdentifierGenerator(
			IdentifierGeneratorFactory identifierGeneratorFactory,
			Dialect dialect, 
			String defaultCatalog, 
			String defaultSchema, 
			RootClass rootClass) throws MappingException {

		if ( identifierGenerator != null ) {
			return identifierGenerator;
		}

		Properties params = new Properties();
		
		//if the hibernate-mapping did not specify a schema/catalog, use the defaults
		//specified by properties - but note that if the schema/catalog were specified
		//in hibernate-mapping, or as params, they will already be initialized and
		//will override the values set here (they are in identifierGeneratorProperties)
		if ( defaultSchema!=null ) {
			params.setProperty(PersistentIdentifierGenerator.SCHEMA, defaultSchema);
		}
		if ( defaultCatalog!=null ) {
			params.setProperty(PersistentIdentifierGenerator.CATALOG, defaultCatalog);
		}
		
		//pass the entity-name, if not a collection-id
		if (rootClass!=null) {
			params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
			params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, rootClass.getJpaEntityName() );
		}
		
		//init the table here instead of earlier, so that we can get a quoted table name
		//TODO: would it be better to simply pass the qualified table name, instead of
		//      splitting it up into schema/catalog/table names
		String tableName = getTable().getQuotedName(dialect);
		params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
		
		//pass the column name (a generated id almost always has a single column)
		String columnName = ( (Column) getColumnIterator().next() ).getQuotedName(dialect);
		params.setProperty( PersistentIdentifierGenerator.PK, columnName );
		
		if (rootClass!=null) {
			StringBuilder tables = new StringBuilder();
			Iterator iter = rootClass.getIdentityTables().iterator();
			while ( iter.hasNext() ) {
				Table table= (Table) iter.next();
				tables.append( table.getQuotedName(dialect) );
				if ( iter.hasNext() ) {
					tables.append(", ");
				}
			}
			params.setProperty( PersistentIdentifierGenerator.TABLES, tables.toString() );
		}
		else {
			params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
		}

		if (identifierGeneratorProperties!=null) {
			params.putAll(identifierGeneratorProperties);
		}

		// TODO : we should pass along all settings once "config lifecycle" is hashed out...
		final ConfigurationService cs = metadata.getMetadataBuildingOptions().getServiceRegistry()
				.getService( ConfigurationService.class );

		params.put(
				AvailableSettings.PREFER_POOLED_VALUES_LO,
				cs.getSetting( AvailableSettings.PREFER_POOLED_VALUES_LO, StandardConverters.BOOLEAN, false )
		);
		if ( cs.getSettings().get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) != null ) {
			params.put(
					AvailableSettings.PREFERRED_POOLED_OPTIMIZER,
					cs.getSettings().get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER )
			);
		}

		identifierGeneratorFactory.setDialect( dialect );
		identifierGenerator = identifierGeneratorFactory.createIdentifierGenerator( identifierGeneratorStrategy, getType(), params );

		return identifierGenerator;
	}

	public boolean isUpdateable() {
		//needed to satisfy KeyValue
		return true;
	}
	
	public FetchMode getFetchMode() {
		return FetchMode.SELECT;
	}

	public Properties getIdentifierGeneratorProperties() {
		return identifierGeneratorProperties;
	}

	public String getNullValue() {
		return nullValue;
	}

	public Table getTable() {
		return table;
	}

	/**
	 * Returns the identifierGeneratorStrategy.
	 * @return String
	 */
	public String getIdentifierGeneratorStrategy() {
		return identifierGeneratorStrategy;
	}
	
	public boolean isIdentityColumn(IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect) {
		identifierGeneratorFactory.setDialect( dialect );
		return IdentityGenerator.class.isAssignableFrom(identifierGeneratorFactory.getIdentifierGeneratorClass( identifierGeneratorStrategy ));
	}

	/**
	 * Sets the identifierGeneratorProperties.
	 * @param identifierGeneratorProperties The identifierGeneratorProperties to set
	 */
	public void setIdentifierGeneratorProperties(Properties identifierGeneratorProperties) {
		this.identifierGeneratorProperties = identifierGeneratorProperties;
	}

	/**
	 * Sets the identifierGeneratorStrategy.
	 * @param identifierGeneratorStrategy The identifierGeneratorStrategy to set
	 */
	public void setIdentifierGeneratorStrategy(String identifierGeneratorStrategy) {
		this.identifierGeneratorStrategy = identifierGeneratorStrategy;
	}

	/**
	 * Sets the nullValue.
	 * @param nullValue The nullValue to set
	 */
	public void setNullValue(String nullValue) {
		this.nullValue = nullValue;
	}

	public String getForeignKeyName() {
		return foreignKeyName;
	}

	public void setForeignKeyName(String foreignKeyName) {
		this.foreignKeyName = foreignKeyName;
	}
	
	public String getForeignKeyDefinition() {
		return foreignKeyDefinition;
	}

	public void setForeignKeyDefinition(String foreignKeyDefinition) {
		this.foreignKeyDefinition = foreignKeyDefinition;
	}

	public boolean isAlternateUniqueKey() {
		return alternateUniqueKey;
	}

	public void setAlternateUniqueKey(boolean unique) {
		this.alternateUniqueKey = unique;
	}

	public boolean isNullable() {
		Iterator itr = getColumnIterator();
		while ( itr.hasNext() ) {
			final Object selectable = itr.next();
			if ( selectable instanceof Formula ) {
				// if there are *any* formulas, then the Value overall is
				// considered nullable
				return true;
			}
			else if ( !( (Column) selectable ).isNullable() ) {
				// if there is a single non-nullable column, the Value
				// overall is considered non-nullable.
				return false;
			}
		}
		// nullable by default
		return true;
	}

	public boolean isSimpleValue() {
		return true;
	}

	public boolean isValid(Mapping mapping) throws MappingException {
		return getColumnSpan()==getType().getColumnSpan(mapping);
	}

	public Type getType() throws MappingException {
		if ( type != null ) {
			return type;
		}

		if ( typeName == null ) {
			throw new MappingException( "No type name" );
		}

		if ( typeParameters != null
				&& Boolean.valueOf( typeParameters.getProperty( DynamicParameterizedType.IS_DYNAMIC ) )
				&& typeParameters.get( DynamicParameterizedType.PARAMETER_TYPE ) == null ) {
			createParameterImpl();
		}

		Type result = getMetadata().getTypeConfiguration().getTypeResolver().heuristicType( typeName, typeParameters );
		// if this is a byte[] version/timestamp, then we need to use RowVersionType
		// instead of BinaryType (HHH-10413)
		if ( isVersion && BinaryType.class.isInstance( result ) ) {
			log.debug( "version is BinaryType; changing to RowVersionType" );
			result = RowVersionType.INSTANCE;
		}
		if ( result == null ) {
			String msg = "Could not determine type for: " + typeName;
			if ( table != null ) {
				msg += ", at table: " + table.getName();
			}
			if ( columns != null && columns.size() > 0 ) {
				msg += ", for columns: " + columns;
			}
			throw new MappingException( msg );
		}

		return result;
	}

	@Override
	public void setTypeUsingReflection(String className, String propertyName) throws MappingException {
		// NOTE : this is called as the last piece in setting SimpleValue type information, and implementations
		// rely on that fact, using it as a signal that all information it is going to get is defined at this point...

		if ( typeName != null ) {
			// assume either (a) explicit type was specified or (b) determine was already performed
			return;
		}

		if ( type != null ) {
			return;
		}

		if ( attributeConverterDescriptor == null ) {
			// this is here to work like legacy.  This should change when we integrate with metamodel to
			// look for SqlTypeDescriptor and JavaTypeDescriptor individually and create the BasicType (well, really
			// keep a registry of [SqlTypeDescriptor,JavaTypeDescriptor] -> BasicType...)
			if ( className == null ) {
				throw new MappingException( "Attribute types for a dynamic entity must be explicitly specified: " + propertyName );
			}
			typeName = ReflectHelper.reflectedPropertyClass(
					className,
					propertyName,
					getMetadata()
							.getMetadataBuildingOptions()
							.getServiceRegistry()
							.getService( ClassLoaderService.class )
			).getName();
			// todo : to fully support isNationalized here we need do the process hinted at above
			// 		essentially, much of the logic from #buildAttributeConverterTypeAdapter wrt resolving
			//		a (1) SqlTypeDescriptor, a (2) JavaTypeDescriptor and dynamically building a BasicType
			// 		combining them.
			return;
		}

		// we had an AttributeConverter...
		type = buildAttributeConverterTypeAdapter();
	}

	/**
	 * Build a Hibernate Type that incorporates the JPA AttributeConverter.  AttributeConverter works totally in
	 * memory, meaning it converts between one Java representation (the entity attribute representation) and another
	 * (the value bound into JDBC statements or extracted from results).  However, the Hibernate Type system operates
	 * at the lower level of actually dealing directly with those JDBC objects.  So even though we have an
	 * AttributeConverter, we still need to "fill out" the rest of the BasicType data and bridge calls
	 * to bind/extract through the converter.
	 * 

* Essentially the idea here is that an intermediate Java type needs to be used. Let's use an example as a means * to illustrate... Consider an {@code AttributeConverter}. This tells Hibernate that the domain * model defines this attribute as an Integer value (the 'entityAttributeJavaType'), but that we need to treat the * value as a String (the 'databaseColumnJavaType') when dealing with JDBC (aka, the database type is a * VARCHAR/CHAR):

    *
  • * When binding values to PreparedStatements we need to convert the Integer value from the entity * into a String and pass that String to setString. The conversion is handled by calling * {@link AttributeConverter#convertToDatabaseColumn(Object)} *
  • *
  • * When extracting values from ResultSets (or CallableStatement parameters) we need to handle the * value via getString, and convert that returned String to an Integer. That conversion is handled * by calling {@link AttributeConverter#convertToEntityAttribute(Object)} *
  • *
* * @return The built AttributeConverter -> Type adapter * * @todo : ultimately I want to see attributeConverterJavaType and attributeConverterJdbcTypeCode specify-able separately * then we can "play them against each other" in terms of determining proper typing * * @todo : see if we already have previously built a custom on-the-fly BasicType for this AttributeConverter; see note below about caching */ @SuppressWarnings("unchecked") private Type buildAttributeConverterTypeAdapter() { // todo : validate the number of columns present here? final JpaAttributeConverter jpaAttributeConverter = attributeConverterDescriptor.createJpaAttributeConverter( new JpaAttributeConverterCreationContext() { @Override public ManagedBeanRegistry getManagedBeanRegistry() { return getMetadata() .getMetadataBuildingOptions() .getServiceRegistry() .getService( ManagedBeanRegistry.class ); } @Override public org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() { return metadata.getTypeConfiguration().getJavaTypeDescriptorRegistry(); } } ); final BasicJavaDescriptor entityAttributeJavaTypeDescriptor = jpaAttributeConverter.getDomainJavaTypeDescriptor(); // build the SqlTypeDescriptor adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Going back to the illustration, this should be a SqlTypeDescriptor that handles the Integer <-> String // conversions. This is the more complicated piece. First we need to determine the JDBC type code // corresponding to the AttributeConverter's declared "databaseColumnJavaType" (how we read that value out // of ResultSets). See JdbcTypeJavaClassMappings for details. Again, given example, this should return // VARCHAR/CHAR final SqlTypeDescriptor recommendedSqlType = jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJdbcRecommendedSqlType( // todo (6.0) : handle the other JdbcRecommendedSqlTypeMappingContext methods metadata::getTypeConfiguration ); int jdbcTypeCode = recommendedSqlType.getSqlType(); if ( isLob() ) { if ( LobTypeMappings.isMappedToKnownLobCode( jdbcTypeCode ) ) { jdbcTypeCode = LobTypeMappings.getLobCodeTypeMapping( jdbcTypeCode ); } else { if ( Serializable.class.isAssignableFrom( entityAttributeJavaTypeDescriptor.getJavaType() ) ) { jdbcTypeCode = Types.BLOB; } else { throw new IllegalArgumentException( String.format( Locale.ROOT, "JDBC type-code [%s (%s)] not known to have a corresponding LOB equivalent, and Java type is not Serializable (to use BLOB)", jdbcTypeCode, JdbcTypeNameMapper.getTypeName( jdbcTypeCode ) ) ); } } } if ( isNationalized() ) { jdbcTypeCode = NationalizedTypeMappings.toNationalizedTypeCode( jdbcTypeCode ); } // find the standard SqlTypeDescriptor for that JDBC type code (allow itr to be remapped if needed!) final SqlTypeDescriptor sqlTypeDescriptor = getMetadata() .getMetadataBuildingOptions() .getServiceRegistry() .getService( JdbcServices.class ) .getJdbcEnvironment() .getDialect() .remapSqlTypeDescriptor( metadata.getTypeConfiguration() .getSqlTypeDescriptorRegistry() .getDescriptor( jdbcTypeCode ) ); // and finally construct the adapter, which injects the AttributeConverter calls into the binding/extraction // process... final SqlTypeDescriptor sqlTypeDescriptorAdapter = new AttributeConverterSqlTypeDescriptorAdapter( jpaAttributeConverter, sqlTypeDescriptor, jpaAttributeConverter.getRelationalJavaTypeDescriptor() ); // todo : cache the AttributeConverterTypeAdapter in case that AttributeConverter is applied multiple times. final String name = AttributeConverterTypeAdapter.NAME_PREFIX + jpaAttributeConverter.getConverterJavaTypeDescriptor().getJavaType().getName(); final String description = String.format( "BasicType adapter for AttributeConverter<%s,%s>", jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType().getSimpleName(), jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType().getSimpleName() ); return new AttributeConverterTypeAdapter( name, description, jpaAttributeConverter, sqlTypeDescriptorAdapter, jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType(), jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType(), entityAttributeJavaTypeDescriptor ); } public boolean isTypeSpecified() { return typeName!=null; } public void setTypeParameters(Properties parameterMap) { this.typeParameters = parameterMap; } public Properties getTypeParameters() { return typeParameters; } public void copyTypeFrom( SimpleValue sourceValue ) { setTypeName( sourceValue.getTypeName() ); setTypeParameters( sourceValue.getTypeParameters() ); type = sourceValue.type; attributeConverterDescriptor = sourceValue.attributeConverterDescriptor; } @Override public boolean isSame(Value other) { return this == other || other instanceof SimpleValue && isSame( (SimpleValue) other ); } protected static boolean isSame(Value v1, Value v2) { return v1 == v2 || v1 != null && v2 != null && v1.isSame( v2 ); } public boolean isSame(SimpleValue other) { return Objects.equals( columns, other.columns ) && Objects.equals( typeName, other.typeName ) && Objects.equals( typeParameters, other.typeParameters ) && Objects.equals( table, other.table ) && Objects.equals( foreignKeyName, other.foreignKeyName ) && Objects.equals( foreignKeyDefinition, other.foreignKeyDefinition ); } @Override public String toString() { return getClass().getName() + '(' + columns.toString() + ')'; } public Object accept(ValueVisitor visitor) { return visitor.accept(this); } public boolean[] getColumnInsertability() { return extractBooleansFromList( insertability ); } public boolean[] getColumnUpdateability() { return extractBooleansFromList( updatability ); } private static boolean[] extractBooleansFromList(List list) { final boolean[] array = new boolean[ list.size() ]; int i = 0; for ( Boolean value : list ) { array[ i++ ] = value; } return array; } public void setJpaAttributeConverterDescriptor(ConverterDescriptor descriptor) { this.attributeConverterDescriptor = descriptor; } private void createParameterImpl() { try { String[] columnsNames = new String[columns.size()]; for ( int i = 0; i < columns.size(); i++ ) { Selectable column = columns.get(i); if (column instanceof Column){ columnsNames[i] = ((Column) column).getName(); } } final XProperty xProperty = (XProperty) typeParameters.get( DynamicParameterizedType.XPROPERTY ); // todo : not sure this works for handling @MapKeyEnumerated final Annotation[] annotations = xProperty == null ? null : xProperty.getAnnotations(); final ClassLoaderService classLoaderService = getMetadata() .getMetadataBuildingOptions() .getServiceRegistry() .getService( ClassLoaderService.class ); typeParameters.put( DynamicParameterizedType.PARAMETER_TYPE, new ParameterTypeImpl( classLoaderService.classForName( typeParameters.getProperty( DynamicParameterizedType.RETURNED_CLASS ) ), annotations, table.getCatalog(), table.getSchema(), table.getName(), Boolean.valueOf( typeParameters.getProperty( DynamicParameterizedType.IS_PRIMARY_KEY ) ), columnsNames ) ); } catch ( ClassLoadingException e ) { throw new MappingException( "Could not create DynamicParameterizedType for type: " + typeName, e ); } } private static final class ParameterTypeImpl implements DynamicParameterizedType.ParameterType { private final Class returnedClass; private final Annotation[] annotationsMethod; private final String catalog; private final String schema; private final String table; private final boolean primaryKey; private final String[] columns; private ParameterTypeImpl(Class returnedClass, Annotation[] annotationsMethod, String catalog, String schema, String table, boolean primaryKey, String[] columns) { this.returnedClass = returnedClass; this.annotationsMethod = annotationsMethod; this.catalog = catalog; this.schema = schema; this.table = table; this.primaryKey = primaryKey; this.columns = columns; } @Override public Class getReturnedClass() { return returnedClass; } @Override public Annotation[] getAnnotationsMethod() { return annotationsMethod; } @Override public String getCatalog() { return catalog; } @Override public String getSchema() { return schema; } @Override public String getTable() { return table; } @Override public boolean isPrimaryKey() { return primaryKey; } @Override public String[] getColumns() { return columns; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy