alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (Binder.java)

This example Hibernate source code file (Binder.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

abstractpluralattributebinding, abstractpluralattributebinding, basicattributebinding, bean, class, class, entitybinding, entitybinding, exception, javabean, metaattributecontext, pluralattributesource, reflection, singularattribute, string, string, tablespecification, util

The Hibernate Binder.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.metamodel.source.binder;

import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.beans.BeanInfoHelper;
import org.hibernate.metamodel.binding.AbstractPluralAttributeBinding;
import org.hibernate.metamodel.binding.AttributeBinding;
import org.hibernate.metamodel.binding.AttributeBindingContainer;
import org.hibernate.metamodel.binding.BasicAttributeBinding;
import org.hibernate.metamodel.binding.BasicCollectionElement;
import org.hibernate.metamodel.binding.CollectionElementNature;
import org.hibernate.metamodel.binding.CollectionLaziness;
import org.hibernate.metamodel.binding.ComponentAttributeBinding;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.EntityDiscriminator;
import org.hibernate.metamodel.binding.HibernateTypeDescriptor;
import org.hibernate.metamodel.binding.IdGenerator;
import org.hibernate.metamodel.binding.InheritanceType;
import org.hibernate.metamodel.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.binding.MetaAttribute;
import org.hibernate.metamodel.binding.SimpleValueBinding;
import org.hibernate.metamodel.binding.SingularAttributeBinding;
import org.hibernate.metamodel.binding.TypeDef;
import org.hibernate.metamodel.domain.Component;
import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.domain.PluralAttribute;
import org.hibernate.metamodel.domain.SingularAttribute;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.DerivedValue;
import org.hibernate.metamodel.relational.Identifier;
import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.source.LocalBindingContext;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.MetaAttributeContext;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.source.hbm.Helper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.tuple.entity.EntityTuplizer;

/**
 * The common binder shared between annotations and {@code hbm.xml} processing.
 * <p/>
 * The API consists of {@link #Binder(MetadataImplementor, List)} and {@link #processEntityHierarchy(EntityHierarchy)}
 *
 * @author Steve Ebersole
 * @author Hardy Ferentschik
 */
public class Binder {
	private final MetadataImplementor metadata;
	private final List<String> processedEntityNames;

	private InheritanceType currentInheritanceType;
	private EntityMode currentHierarchyEntityMode;
	private LocalBindingContext currentBindingContext;

	public Binder(MetadataImplementor metadata, List<String> processedEntityNames) {
		this.metadata = metadata;
		this.processedEntityNames = processedEntityNames;
	}

	/**
	 * Process an entity hierarchy.
	 *
	 * @param entityHierarchy THe hierarchy to process.
	 */
	public void processEntityHierarchy(EntityHierarchy entityHierarchy) {
		currentInheritanceType = entityHierarchy.getHierarchyInheritanceType();
		EntityBinding rootEntityBinding = createEntityBinding( entityHierarchy.getRootEntitySource(), null );
		if ( currentInheritanceType != InheritanceType.NO_INHERITANCE ) {
			processHierarchySubEntities( entityHierarchy.getRootEntitySource(), rootEntityBinding );
		}
		currentHierarchyEntityMode = null;
	}

	private void processHierarchySubEntities(SubclassEntityContainer subclassEntitySource, EntityBinding superEntityBinding) {
		for ( SubclassEntitySource subEntity : subclassEntitySource.subclassEntitySources() ) {
			EntityBinding entityBinding = createEntityBinding( subEntity, superEntityBinding );
			processHierarchySubEntities( subEntity, entityBinding );
		}
	}


	// Entities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	private EntityBinding createEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) {
		if ( processedEntityNames.contains( entitySource.getEntityName() ) ) {
			return metadata.getEntityBinding( entitySource.getEntityName() );
		}

		currentBindingContext = entitySource.getLocalBindingContext();
		try {
			final EntityBinding entityBinding = doCreateEntityBinding( entitySource, superEntityBinding );

			metadata.addEntity( entityBinding );
			processedEntityNames.add( entityBinding.getEntity().getName() );

			processFetchProfiles( entitySource, entityBinding );

			return entityBinding;
		}
		finally {
			currentBindingContext = null;
		}
	}

	private EntityBinding doCreateEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) {
		final EntityBinding entityBinding = createBasicEntityBinding( entitySource, superEntityBinding );

		bindSecondaryTables( entitySource, entityBinding );
		bindAttributes( entitySource, entityBinding );

		bindTableUniqueConstraints( entitySource, entityBinding );

		return entityBinding;
	}

	private EntityBinding createBasicEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) {
		if ( superEntityBinding == null ) {
			return makeRootEntityBinding( (RootEntitySource) entitySource );
		}
		else {
			switch ( currentInheritanceType ) {
				case SINGLE_TABLE:
					return makeDiscriminatedSubclassBinding( (SubclassEntitySource) entitySource, superEntityBinding );
				case JOINED:
					return makeJoinedSubclassBinding( (SubclassEntitySource) entitySource, superEntityBinding );
				case TABLE_PER_CLASS:
					return makeUnionedSubclassBinding( (SubclassEntitySource) entitySource, superEntityBinding );
				default:
					// extreme internal error!
					throw new AssertionFailure( "Internal condition failure" );
			}
		}
	}

	private EntityBinding makeRootEntityBinding(RootEntitySource entitySource) {
		currentHierarchyEntityMode = entitySource.getEntityMode();

		final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, null );

		bindPrimaryTable( entitySource, entityBinding );

		bindIdentifier( entitySource, entityBinding );
		bindVersion( entityBinding, entitySource );
		bindDiscriminator( entitySource, entityBinding );

		entityBinding.getHierarchyDetails().setCaching( entitySource.getCaching() );
		entityBinding.getHierarchyDetails().setExplicitPolymorphism( entitySource.isExplicitPolymorphism() );
		entityBinding.getHierarchyDetails().setOptimisticLockStyle( entitySource.getOptimisticLockStyle() );

		entityBinding.setMutable( entitySource.isMutable() );
		entityBinding.setWhereFilter( entitySource.getWhere() );
		entityBinding.setRowId( entitySource.getRowId() );

		return entityBinding;
	}

	private EntityBinding buildBasicEntityBinding(EntitySource entitySource, EntityBinding superEntityBinding) {
		final EntityBinding entityBinding = superEntityBinding == null
				? new EntityBinding( currentInheritanceType, currentHierarchyEntityMode )
				: new EntityBinding( superEntityBinding );

		final String entityName = entitySource.getEntityName();
		final String className = currentHierarchyEntityMode == EntityMode.POJO ? entitySource.getClassName() : null;

		final Entity entity = new Entity(
				entityName,
				className,
				currentBindingContext.makeClassReference( className ),
				superEntityBinding == null ? null : superEntityBinding.getEntity()
		);
		entityBinding.setEntity( entity );

		entityBinding.setJpaEntityName( entitySource.getJpaEntityName() );

		if ( currentHierarchyEntityMode == EntityMode.POJO ) {
			final String proxy = entitySource.getProxy();
			if ( proxy != null ) {
				entityBinding.setProxyInterfaceType(
						currentBindingContext.makeClassReference(
								currentBindingContext.qualifyClassName( proxy )
						)
				);
				entityBinding.setLazy( true );
			}
			else if ( entitySource.isLazy() ) {
				entityBinding.setProxyInterfaceType( entityBinding.getEntity().getClassReferenceUnresolved() );
				entityBinding.setLazy( true );
			}
		}
		else {
			entityBinding.setProxyInterfaceType( null );
			entityBinding.setLazy( entitySource.isLazy() );
		}

		final String customTuplizerClassName = entitySource.getCustomTuplizerClassName();
		if ( customTuplizerClassName != null ) {
			entityBinding.setCustomEntityTuplizerClass(
					currentBindingContext.<EntityTuplizer>locateClassByName(
							customTuplizerClassName
					)
			);
		}

		final String customPersisterClassName = entitySource.getCustomPersisterClassName();
		if ( customPersisterClassName != null ) {
			entityBinding.setCustomEntityPersisterClass(
					currentBindingContext.<EntityPersister>locateClassByName(
							customPersisterClassName
					)
			);
		}

		entityBinding.setMetaAttributeContext( buildMetaAttributeContext( entitySource ) );

		entityBinding.setDynamicUpdate( entitySource.isDynamicUpdate() );
		entityBinding.setDynamicInsert( entitySource.isDynamicInsert() );
		entityBinding.setBatchSize( entitySource.getBatchSize() );
		entityBinding.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() );
		entityBinding.setAbstract( entitySource.isAbstract() );

		entityBinding.setCustomLoaderName( entitySource.getCustomLoaderName() );
		entityBinding.setCustomInsert( entitySource.getCustomSqlInsert() );
		entityBinding.setCustomUpdate( entitySource.getCustomSqlUpdate() );
		entityBinding.setCustomDelete( entitySource.getCustomSqlDelete() );

		if ( entitySource.getSynchronizedTableNames() != null ) {
			entityBinding.addSynchronizedTableNames( entitySource.getSynchronizedTableNames() );
		}

		entityBinding.setJpaCallbackClasses(entitySource.getJpaCallbackClasses());

		return entityBinding;
	}

	private EntityBinding makeDiscriminatedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) {
		final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding );

		entityBinding.setPrimaryTable( superEntityBinding.getPrimaryTable() );
		entityBinding.setPrimaryTableName( superEntityBinding.getPrimaryTableName() );
		bindDiscriminatorValue( entitySource, entityBinding );

		return entityBinding;
	}

	private EntityBinding makeJoinedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) {
		final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding );

		bindPrimaryTable( entitySource, entityBinding );

		// todo : join

		return entityBinding;
	}

	private EntityBinding makeUnionedSubclassBinding(SubclassEntitySource entitySource, EntityBinding superEntityBinding) {
		final EntityBinding entityBinding = buildBasicEntityBinding( entitySource, superEntityBinding );

		bindPrimaryTable( entitySource, entityBinding );

		// todo : ??

		return entityBinding;
	}

	// Attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	private void bindIdentifier(RootEntitySource entitySource, EntityBinding entityBinding) {
		if ( entitySource.getIdentifierSource() == null ) {
			throw new AssertionFailure( "Expecting identifier information on root entity descriptor" );
		}
		switch ( entitySource.getIdentifierSource().getNature() ) {
			case SIMPLE: {
				bindSimpleIdentifier( (SimpleIdentifierSource) entitySource.getIdentifierSource(), entityBinding );
				break;
			}
			case AGGREGATED_COMPOSITE: {
				// composite id with an actual component class
			    break;
			}
			case COMPOSITE: {
				// what we used to term an "embedded composite identifier", which is not tobe confused with the JPA
				// term embedded. Specifically a composite id where there is no component class, though there may
				// be a @IdClass :/
			    break;
			}
		}
	}

	private void bindSimpleIdentifier(SimpleIdentifierSource identifierSource, EntityBinding entityBinding) {
		final BasicAttributeBinding idAttributeBinding = doBasicSingularAttributeBindingCreation(
				identifierSource.getIdentifierAttributeSource(), entityBinding
		);

		entityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( idAttributeBinding );
		IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
		if ( generator == null ) {
			Map<String, String> params = new HashMap();
			params.put( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntity().getName() );
			generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
		}
		entityBinding.getHierarchyDetails()
				.getEntityIdentifier()
				.setIdGenerator( generator );

		final org.hibernate.metamodel.relational.Value relationalValue = idAttributeBinding.getValue();

		if ( SimpleValue.class.isInstance( relationalValue ) ) {
			if ( !Column.class.isInstance( relationalValue ) ) {
				// this should never ever happen..
				throw new AssertionFailure( "Simple-id was not a column." );
			}
			entityBinding.getPrimaryTable().getPrimaryKey().addColumn( Column.class.cast( relationalValue ) );
		}
		else {
			for ( SimpleValue subValue : ( (Tuple) relationalValue ).values() ) {
				if ( Column.class.isInstance( subValue ) ) {
					entityBinding.getPrimaryTable().getPrimaryKey().addColumn( Column.class.cast( subValue ) );
				}
			}
		}
	}

	private void bindVersion(EntityBinding entityBinding, RootEntitySource entitySource) {
		final SingularAttributeSource versioningAttributeSource = entitySource.getVersioningAttributeSource();
		if ( versioningAttributeSource == null ) {
			return;
		}

		BasicAttributeBinding attributeBinding = doBasicSingularAttributeBindingCreation(
				versioningAttributeSource, entityBinding
		);
		entityBinding.getHierarchyDetails().setVersioningAttributeBinding( attributeBinding );
	}

	private void bindDiscriminator(RootEntitySource entitySource, EntityBinding entityBinding) {
		final DiscriminatorSource discriminatorSource = entitySource.getDiscriminatorSource();
		if ( discriminatorSource == null ) {
			return;
		}

		EntityDiscriminator discriminator = new EntityDiscriminator();
		SimpleValue relationalValue = makeSimpleValue(
				entityBinding,
				discriminatorSource.getDiscriminatorRelationalValueSource()
		);
		discriminator.setBoundValue( relationalValue );

		discriminator.getExplicitHibernateTypeDescriptor().setExplicitTypeName(
				discriminatorSource.getExplicitHibernateTypeName() != null
						? discriminatorSource.getExplicitHibernateTypeName()
						: "string"
		);

		discriminator.setInserted( discriminatorSource.isInserted() );
		discriminator.setForced( discriminatorSource.isForced() );

		entityBinding.getHierarchyDetails().setEntityDiscriminator( discriminator );
		entityBinding.setDiscriminatorMatchValue( entitySource.getDiscriminatorMatchValue() );
	}

	private void bindDiscriminatorValue(SubclassEntitySource entitySource, EntityBinding entityBinding) {
		final String discriminatorValue = entitySource.getDiscriminatorMatchValue();
		if ( discriminatorValue == null ) {
			return;
		}
		entityBinding.setDiscriminatorMatchValue( discriminatorValue );
	}

	private void bindAttributes(AttributeSourceContainer attributeSourceContainer, AttributeBindingContainer attributeBindingContainer) {
		// todo : we really need the notion of a Stack here for the table from which the columns come for binding these attributes.
		// todo : adding the concept (interface) of a source of attribute metadata would allow reuse of this method for entity, component, unique-key, etc
		// for now, simply assume all columns come from the base table....

		for ( AttributeSource attributeSource : attributeSourceContainer.attributeSources() ) {
			if ( attributeSource.isSingular() ) {
				final SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource;
				if ( singularAttributeSource.getNature() == SingularAttributeNature.COMPONENT ) {
					bindComponent( (ComponentAttributeSource) singularAttributeSource, attributeBindingContainer );
				}
				else {
					doBasicSingularAttributeBindingCreation( singularAttributeSource, attributeBindingContainer );
				}
			}
			else {
				bindPersistentCollection( (PluralAttributeSource) attributeSource, attributeBindingContainer );
			}
		}
	}

	private void bindComponent(ComponentAttributeSource attributeSource, AttributeBindingContainer container) {
		final String attributeName = attributeSource.getName();
		SingularAttribute attribute = container.getAttributeContainer().locateComponentAttribute( attributeName );
		if ( attribute == null ) {
			final Component component = new Component(
					attributeSource.getPath(),
					attributeSource.getClassName(),
					attributeSource.getClassReference(),
					null // component inheritance not YET supported
			);
			attribute = container.getAttributeContainer().createComponentAttribute( attributeName, component );
		}
		ComponentAttributeBinding componentAttributeBinding = container.makeComponentAttributeBinding( attribute );

		if ( StringHelper.isNotEmpty( attributeSource.getParentReferenceAttributeName() ) ) {
			final SingularAttribute parentReferenceAttribute =
					componentAttributeBinding.getComponent()
							.createSingularAttribute( attributeSource.getParentReferenceAttributeName() );
			componentAttributeBinding.setParentReference( parentReferenceAttribute );
		}

		componentAttributeBinding.setMetaAttributeContext(
				buildMetaAttributeContext( attributeSource.metaAttributes(), container.getMetaAttributeContext() )
		);

		bindAttributes( attributeSource, componentAttributeBinding );
	}

	private void bindPersistentCollection(PluralAttributeSource attributeSource, AttributeBindingContainer attributeBindingContainer) {
		final PluralAttribute existingAttribute = attributeBindingContainer.getAttributeContainer()
				.locatePluralAttribute( attributeSource.getName() );
		final AbstractPluralAttributeBinding pluralAttributeBinding;

		if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.BAG ) {
			final PluralAttribute attribute = existingAttribute != null
					? existingAttribute
					: attributeBindingContainer.getAttributeContainer().createBag( attributeSource.getName() );
			pluralAttributeBinding = attributeBindingContainer.makeBagAttributeBinding(
					attribute,
					convert( attributeSource.getElementSource().getNature() )
			);
		}
		else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SET ) {
			final PluralAttribute attribute = existingAttribute != null
					? existingAttribute
					: attributeBindingContainer.getAttributeContainer().createSet( attributeSource.getName() );
			pluralAttributeBinding = attributeBindingContainer.makeSetAttributeBinding(
					attribute,
					convert( attributeSource.getElementSource().getNature() )
			);
		}
		else {
			// todo : implement other collection types
			throw new NotYetImplementedException( "Collections other than bag and set not yet implemented :(" );
		}

		doBasicPluralAttributeBinding( attributeSource, pluralAttributeBinding );

		bindCollectionTable( attributeSource, pluralAttributeBinding );
		bindSortingAndOrdering( attributeSource, pluralAttributeBinding );

		bindCollectionKey( attributeSource, pluralAttributeBinding );
		bindCollectionElement( attributeSource, pluralAttributeBinding );
		bindCollectionIndex( attributeSource, pluralAttributeBinding );

		metadata.addCollection( pluralAttributeBinding );
	}

	private void doBasicPluralAttributeBinding(PluralAttributeSource source, AbstractPluralAttributeBinding binding) {
		binding.setFetchTiming( source.getFetchTiming() );
		binding.setFetchStyle( source.getFetchStyle() );
		binding.setCascadeStyles( source.getCascadeStyles() );

		binding.setCaching( source.getCaching() );

		binding.getHibernateTypeDescriptor().setJavaTypeName(
				source.getPluralAttributeNature().reportedJavaType().getName()
		);
		binding.getHibernateTypeDescriptor().setExplicitTypeName( source.getTypeInformation().getName() );
		binding.getHibernateTypeDescriptor().getTypeParameters().putAll( source.getTypeInformation().getParameters() );

		if ( StringHelper.isNotEmpty( source.getCustomPersisterClassName() ) ) {
			binding.setCollectionPersisterClass(
					currentBindingContext.<CollectionPersister>locateClassByName( source.getCustomPersisterClassName() )
			);
		}

		if ( source.getCustomPersisterClassName() != null ) {
			binding.setCollectionPersisterClass(
					metadata.<CollectionPersister>locateClassByName( source.getCustomPersisterClassName() )
			);
		}

		binding.setCustomLoaderName( source.getCustomLoaderName() );
		binding.setCustomSqlInsert( source.getCustomSqlInsert() );
		binding.setCustomSqlUpdate( source.getCustomSqlUpdate() );
		binding.setCustomSqlDelete( source.getCustomSqlDelete() );
		binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() );

		binding.setMetaAttributeContext(
				buildMetaAttributeContext(
						source.metaAttributes(),
						binding.getContainer().getMetaAttributeContext()
				)
		);

		doBasicAttributeBinding( source, binding );
	}

	private CollectionLaziness interpretLaziness(String laziness) {
		if ( laziness == null ) {
			laziness = Boolean.toString( metadata.getMappingDefaults().areAssociationsLazy() );
		}

		if ( "extra".equals( laziness ) ) {
			return CollectionLaziness.EXTRA;
		}
		else if ( "false".equals( laziness ) ) {
			return CollectionLaziness.NOT;
		}
		else if ( "true".equals( laziness ) ) {
			return CollectionLaziness.LAZY;
		}

		throw new MappingException(
				String.format( "Unexpected collection laziness value %s", laziness ),
				currentBindingContext.getOrigin()
		);
	}

	private void bindCollectionTable(
			PluralAttributeSource attributeSource,
			AbstractPluralAttributeBinding pluralAttributeBinding) {
		if ( attributeSource.getElementSource().getNature() == PluralAttributeElementNature.ONE_TO_MANY ) {
			return;
		}

		final Schema.Name schemaName = Helper.determineDatabaseSchemaName(
				attributeSource.getExplicitSchemaName(),
				attributeSource.getExplicitCatalogName(),
				currentBindingContext
		);
		final Schema schema = metadata.getDatabase().locateSchema( schemaName );

		final String tableName = attributeSource.getExplicitCollectionTableName();
		if ( StringHelper.isNotEmpty( tableName ) ) {
			final Identifier tableIdentifier = Identifier.toIdentifier(
					currentBindingContext.getNamingStrategy().tableName( tableName )
			);
			Table collectionTable = schema.locateTable( tableIdentifier );
			if ( collectionTable == null ) {
				collectionTable = schema.createTable( tableIdentifier );
			}
			pluralAttributeBinding.setCollectionTable( collectionTable );
		}
		else {
			// todo : not sure wel have all the needed info here in all cases, specifically when needing to know the "other side"
			final EntityBinding owner = pluralAttributeBinding.getContainer().seekEntityBinding();
			final String ownerTableLogicalName = Table.class.isInstance( owner.getPrimaryTable() )
					? Table.class.cast( owner.getPrimaryTable() ).getTableName().getName()
					: null;
			String collectionTableName = currentBindingContext.getNamingStrategy().collectionTableName(
					owner.getEntity().getName(),
					ownerTableLogicalName,
					null,	// todo : here
					null,	// todo : and here
					pluralAttributeBinding.getContainer().getPathBase() + '.' + attributeSource.getName()
			);
			collectionTableName = quoteIdentifier( collectionTableName );
			pluralAttributeBinding.setCollectionTable(
					schema.locateOrCreateTable(
							Identifier.toIdentifier(
									collectionTableName
							)
					)
			);
		}

		if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableComment() ) ) {
			pluralAttributeBinding.getCollectionTable().addComment( attributeSource.getCollectionTableComment() );
		}

		if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableCheck() ) ) {
			pluralAttributeBinding.getCollectionTable().addCheckConstraint( attributeSource.getCollectionTableCheck() );
		}

		pluralAttributeBinding.setWhere( attributeSource.getWhere() );
	}

	private void bindCollectionKey(
			PluralAttributeSource attributeSource,
			AbstractPluralAttributeBinding pluralAttributeBinding) {
		pluralAttributeBinding.getCollectionKey().prepareForeignKey(
				attributeSource.getKeySource().getExplicitForeignKeyName(),
				null  // todo : handle secondary table names
		);
		pluralAttributeBinding.getCollectionKey().getForeignKey().setDeleteRule(
				attributeSource.getKeySource().getOnDeleteAction()
		);
		// todo : need to bind "relational values", account for property-ref
	}

	private void bindCollectionElement(
			PluralAttributeSource attributeSource,
			AbstractPluralAttributeBinding pluralAttributeBinding) {
		final PluralAttributeElementSource elementSource = attributeSource.getElementSource();
		if ( elementSource.getNature() == PluralAttributeElementNature.BASIC ) {
			final BasicPluralAttributeElementSource basicElementSource = (BasicPluralAttributeElementSource) elementSource;
			final BasicCollectionElement basicCollectionElement = (BasicCollectionElement) pluralAttributeBinding.getCollectionElement();
			resolveTypeInformation(
					basicElementSource.getExplicitHibernateTypeSource(),
					pluralAttributeBinding.getAttribute(),
					basicCollectionElement
			);
			// todo : temp
			return;
		}
		// todo : implement
		throw new NotYetImplementedException(
				String.format(
						"Support for collection elements of type %s not yet implemented",
						elementSource.getNature()
				)
		);
	}

	private void bindCollectionIndex(
			PluralAttributeSource attributeSource,
			AbstractPluralAttributeBinding pluralAttributeBinding) {
		if ( attributeSource.getPluralAttributeNature() != PluralAttributeNature.LIST
				&& attributeSource.getPluralAttributeNature() != PluralAttributeNature.MAP ) {
			return;
		}

		// todo : implement
		throw new NotYetImplementedException();
	}

	private void bindSortingAndOrdering(
			PluralAttributeSource attributeSource,
			AbstractPluralAttributeBinding pluralAttributeBinding) {
		if ( Sortable.class.isInstance( attributeSource ) ) {
			final Sortable sortable = Sortable.class.cast( attributeSource );
			if ( sortable.isSorted() ) {
				// todo : handle setting comparator

				// and then return because sorting and ordering are mutually exclusive
				return;
			}
		}

		if ( Orderable.class.isInstance( attributeSource ) ) {
			final Orderable orderable = Orderable.class.cast( attributeSource );
			if ( orderable.isOrdered() ) {
				// todo : handle setting ordering
			}
		}
	}

	private void doBasicAttributeBinding(AttributeSource attributeSource, AttributeBinding attributeBinding) {
		attributeBinding.setPropertyAccessorName( attributeSource.getPropertyAccessorName() );
		attributeBinding.setIncludedInOptimisticLocking( attributeSource.isIncludedInOptimisticLocking() );
	}

	private CollectionElementNature convert(PluralAttributeElementNature pluralAttributeElementNature) {
		return CollectionElementNature.valueOf( pluralAttributeElementNature.name() );
	}

	private BasicAttributeBinding doBasicSingularAttributeBindingCreation(
			SingularAttributeSource attributeSource,
			AttributeBindingContainer attributeBindingContainer) {
		final SingularAttribute existingAttribute = attributeBindingContainer.getAttributeContainer()
				.locateSingularAttribute( attributeSource.getName() );
		final SingularAttribute attribute;
		if ( existingAttribute != null ) {
			attribute = existingAttribute;
		}
		else if ( attributeSource.isVirtualAttribute() ) {
			attribute = attributeBindingContainer.getAttributeContainer().createVirtualSingularAttribute(
					attributeSource.getName()
			);
		}
		else {
			attribute = attributeBindingContainer.getAttributeContainer()
					.createSingularAttribute( attributeSource.getName() );
		}

		final BasicAttributeBinding attributeBinding;
		if ( attributeSource.getNature() == SingularAttributeNature.BASIC ) {
			attributeBinding = attributeBindingContainer.makeBasicAttributeBinding( attribute );
			resolveTypeInformation( attributeSource.getTypeInformation(), attributeBinding );
		}
		else if ( attributeSource.getNature() == SingularAttributeNature.MANY_TO_ONE ) {
			attributeBinding = attributeBindingContainer.makeManyToOneAttributeBinding( attribute );
			resolveTypeInformation( attributeSource.getTypeInformation(), attributeBinding );
			resolveToOneInformation(
					(ToOneAttributeSource) attributeSource,
					(ManyToOneAttributeBinding) attributeBinding
			);
		}
		else {
			throw new NotYetImplementedException();
		}

		attributeBinding.setGeneration( attributeSource.getGeneration() );
		attributeBinding.setLazy( attributeSource.isLazy() );
		attributeBinding.setIncludedInOptimisticLocking( attributeSource.isIncludedInOptimisticLocking() );

		attributeBinding.setPropertyAccessorName(
				Helper.getPropertyAccessorName(
						attributeSource.getPropertyAccessorName(),
						false,
						currentBindingContext.getMappingDefaults().getPropertyAccessorName()
				)
		);

		bindRelationalValues( attributeSource, attributeBinding );

		attributeBinding.setMetaAttributeContext(
				buildMetaAttributeContext(
						attributeSource.metaAttributes(),
						attributeBindingContainer.getMetaAttributeContext()
				)
		);

		return attributeBinding;
	}

	private void resolveTypeInformation(ExplicitHibernateTypeSource typeSource, BasicAttributeBinding attributeBinding) {
		final Class<?> attributeJavaType = determineJavaType( attributeBinding.getAttribute() );
		if ( attributeJavaType != null ) {
			attributeBinding.getAttribute()
					.resolveType( currentBindingContext.makeJavaType( attributeJavaType.getName() ) );
		}

		resolveTypeInformation( typeSource, attributeBinding.getHibernateTypeDescriptor(), attributeJavaType );
	}

	private void resolveTypeInformation(
			ExplicitHibernateTypeSource typeSource,
			PluralAttribute attribute,
			BasicCollectionElement collectionElement) {
		final Class<?> attributeJavaType = determineJavaType( attribute );
		resolveTypeInformation( typeSource, collectionElement.getHibernateTypeDescriptor(), attributeJavaType );
	}

	private void resolveTypeInformation(
			ExplicitHibernateTypeSource typeSource,
			HibernateTypeDescriptor hibernateTypeDescriptor,
			Class<?> discoveredJavaType) {
		if ( discoveredJavaType != null ) {
			hibernateTypeDescriptor.setJavaTypeName( discoveredJavaType.getName() );
		}

		final String explicitTypeName = typeSource.getName();
		if ( explicitTypeName != null ) {
			final TypeDef typeDef = currentBindingContext.getMetadataImplementor()
					.getTypeDefinition( explicitTypeName );
			if ( typeDef != null ) {
				hibernateTypeDescriptor.setExplicitTypeName( typeDef.getTypeClass() );
				hibernateTypeDescriptor.getTypeParameters().putAll( typeDef.getParameters() );
			}
			else {
				hibernateTypeDescriptor.setExplicitTypeName( explicitTypeName );
			}
			final Map<String, String> parameters = typeSource.getParameters();
			if ( parameters != null ) {
				hibernateTypeDescriptor.getTypeParameters().putAll( parameters );
			}
		}
		else {
			if ( discoveredJavaType == null ) {
				// we will have problems later determining the Hibernate Type to use.  Should we throw an
				// exception now?  Might be better to get better contextual info
			}
		}
	}

	/**
	 * @param attribute the domain attribute
	 *
	 * @return Returns the Java type of the attribute using reflection or {@code null} if the type cannot be discovered
	 */
	private Class<?> determineJavaType(final SingularAttribute attribute) {
		try {
			final Class<?> ownerClass = attribute.getAttributeContainer().getClassReference();
			AttributeJavaTypeDeterminerDelegate delegate = new AttributeJavaTypeDeterminerDelegate( attribute.getName() );
			BeanInfoHelper.visitBeanInfo( ownerClass, delegate );
			return delegate.javaType;
		}
		catch ( Exception ignore ) {
			// todo : log it?
		}
		return null;
	}

	private Class<?> determineJavaType(PluralAttribute attribute) {
		try {
			final Class<?> ownerClass = attribute.getAttributeContainer().getClassReference();
			PluralAttributeJavaTypeDeterminerDelegate delegate = new PluralAttributeJavaTypeDeterminerDelegate(
					ownerClass,
					attribute.getName()
			);
			BeanInfoHelper.visitBeanInfo( ownerClass, delegate );
			return delegate.javaType;
		}
		catch ( Exception ignore ) {
			// todo : log it?
		}
		return null;
	}

	private class PluralAttributeJavaTypeDeterminerDelegate implements BeanInfoHelper.BeanInfoDelegate {
		private final Class<?> ownerClass;
		private final String attributeName;

		private Class<?> javaType = null;

		private PluralAttributeJavaTypeDeterminerDelegate(Class<?> ownerClass, String attributeName) {
			this.ownerClass = ownerClass;
			this.attributeName = attributeName;
		}

		@Override
		public void processBeanInfo(BeanInfo beanInfo) throws Exception {
			for ( PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors() ) {
				if ( propertyDescriptor.getName().equals( attributeName ) ) {
					javaType = extractCollectionComponentType( beanInfo, propertyDescriptor );
					break;
				}
			}
		}

		@SuppressWarnings( { "unchecked" })
		private Class<?> extractCollectionComponentType(BeanInfo beanInfo, PropertyDescriptor propertyDescriptor) {
			final java.lang.reflect.Type collectionAttributeType;
			if ( propertyDescriptor.getReadMethod() != null ) {
				collectionAttributeType = propertyDescriptor.getReadMethod().getGenericReturnType();
			}
			else if ( propertyDescriptor.getWriteMethod() != null ) {
				collectionAttributeType = propertyDescriptor.getWriteMethod().getGenericParameterTypes()[0];
			}
			else {
				// we need to look for the field and look at it...
				try {
					collectionAttributeType = ownerClass.getField( propertyDescriptor.getName() ).getGenericType();
				}
				catch ( Exception e ) {
					return null;
				}
			}

			if ( ParameterizedType.class.isInstance( collectionAttributeType ) ) {
				final java.lang.reflect.Type[] types = ( (ParameterizedType) collectionAttributeType ).getActualTypeArguments();
				if ( types == null ) {
					return null;
				}
				else if ( types.length == 1 ) {
					return (Class<?>) types[0];
				}
				else if ( types.length == 2 ) {
					// Map<K,V>
					return (Class<?>) types[1];
				}
			}
			return null;
		}
	}

	private void resolveToOneInformation(ToOneAttributeSource attributeSource, ManyToOneAttributeBinding attributeBinding) {
		final String referencedEntityName = attributeSource.getReferencedEntityName() != null
				? attributeSource.getReferencedEntityName()
				: attributeBinding.getAttribute().getSingularAttributeType().getClassName();
		attributeBinding.setReferencedEntityName( referencedEntityName );
		// todo : we should consider basing references on columns instead of property-ref, which would require a resolution (later) of property-ref to column names
		attributeBinding.setReferencedAttributeName( attributeSource.getReferencedEntityAttributeName() );

		attributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() );
		attributeBinding.setFetchTiming( attributeSource.getFetchTiming() );
		attributeBinding.setFetchStyle( attributeSource.getFetchStyle() );
	}

	private MetaAttributeContext buildMetaAttributeContext(EntitySource entitySource) {
		return buildMetaAttributeContext(
				entitySource.metaAttributes(),
				true,
				currentBindingContext.getMetadataImplementor().getGlobalMetaAttributeContext()
		);
	}

	private static MetaAttributeContext buildMetaAttributeContext(
			Iterable<MetaAttributeSource> metaAttributeSources,
			MetaAttributeContext parentContext) {
		return buildMetaAttributeContext( metaAttributeSources, false, parentContext );
	}

	private static MetaAttributeContext buildMetaAttributeContext(
			Iterable<MetaAttributeSource> metaAttributeSources,
			boolean onlyInheritable,
			MetaAttributeContext parentContext) {
		final MetaAttributeContext subContext = new MetaAttributeContext( parentContext );

		for ( MetaAttributeSource metaAttributeSource : metaAttributeSources ) {
			if ( onlyInheritable & !metaAttributeSource.isInheritable() ) {
				continue;
			}

			final String name = metaAttributeSource.getName();
			final MetaAttribute inheritedMetaAttribute = parentContext.getMetaAttribute( name );
			MetaAttribute metaAttribute = subContext.getLocalMetaAttribute( name );
			if ( metaAttribute == null || metaAttribute == inheritedMetaAttribute ) {
				metaAttribute = new MetaAttribute( name );
				subContext.add( metaAttribute );
			}
			metaAttribute.addValue( metaAttributeSource.getValue() );
		}

		return subContext;
	}

	// Relational ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	private void bindPrimaryTable(EntitySource entitySource, EntityBinding entityBinding) {
		final TableSource tableSource = entitySource.getPrimaryTable();
		final Table table = createTable( entityBinding, tableSource );
		entityBinding.setPrimaryTable( table );
		entityBinding.setPrimaryTableName( table.getTableName().getName() );
	}

	private void bindSecondaryTables(EntitySource entitySource, EntityBinding entityBinding) {
		for ( TableSource secondaryTableSource : entitySource.getSecondaryTables() ) {
			final Table table = createTable( entityBinding, secondaryTableSource );
			entityBinding.addSecondaryTable( secondaryTableSource.getLogicalName(), table );
		}
	}

	private Table createTable(EntityBinding entityBinding, TableSource tableSource) {
		String tableName = tableSource.getExplicitTableName();
		if ( StringHelper.isEmpty( tableName ) ) {
			tableName = currentBindingContext.getNamingStrategy()
					.classToTableName( entityBinding.getEntity().getClassName() );
		}
		else {
			tableName = currentBindingContext.getNamingStrategy().tableName( tableName );
		}
		tableName = quoteIdentifier( tableName );

		final Schema.Name databaseSchemaName = Helper.determineDatabaseSchemaName(
				tableSource.getExplicitSchemaName(),
				tableSource.getExplicitCatalogName(),
				currentBindingContext
		);
		return currentBindingContext.getMetadataImplementor()
				.getDatabase()
				.locateSchema( databaseSchemaName )
				.locateOrCreateTable( Identifier.toIdentifier( tableName ) );
	}

	private void bindTableUniqueConstraints(EntitySource entitySource, EntityBinding entityBinding) {
		for ( ConstraintSource constraintSource : entitySource.getConstraints() ) {
			if ( constraintSource instanceof UniqueConstraintSource ) {
				TableSpecification table = entityBinding.locateTable( constraintSource.getTableName() );
				if ( table == null ) {
					// throw exception !?
				}
				String constraintName = constraintSource.name();
				if ( constraintName == null ) {
					// create a default name
				}

				UniqueKey uniqueKey = table.getOrCreateUniqueKey( constraintName );
				for ( String columnName : constraintSource.columnNames() ) {
					uniqueKey.addColumn( table.locateOrCreateColumn( quoteIdentifier( columnName ) ) );
				}
			}
		}
	}

	private void bindRelationalValues(
			RelationalValueSourceContainer relationalValueSourceContainer,
			SingularAttributeBinding attributeBinding) {

		List<SimpleValueBinding> valueBindings = new ArrayList();

		if ( !relationalValueSourceContainer.relationalValueSources().isEmpty() ) {
			for ( RelationalValueSource valueSource : relationalValueSourceContainer.relationalValueSources() ) {
				final TableSpecification table = attributeBinding.getContainer()
						.seekEntityBinding()
						.locateTable( valueSource.getContainingTableName() );

				if ( ColumnSource.class.isInstance( valueSource ) ) {
					final ColumnSource columnSource = ColumnSource.class.cast( valueSource );
					final Column column = makeColumn( (ColumnSource) valueSource, table );
					valueBindings.add(
							new SimpleValueBinding(
									column,
									columnSource.isIncludedInInsert(),
									columnSource.isIncludedInUpdate()
							)
					);
				}
				else {
					valueBindings.add(
							new SimpleValueBinding(
									makeDerivedValue( ( (DerivedValueSource) valueSource ), table )
							)
					);
				}
			}
		}
		else {
			String name = metadata.getOptions()
					.getNamingStrategy()
					.propertyToColumnName( attributeBinding.getAttribute().getName() );
			name = quoteIdentifier( name );
			Column column = attributeBinding.getContainer()
									.seekEntityBinding()
									.getPrimaryTable()
									.locateOrCreateColumn( name );
			column.setNullable( relationalValueSourceContainer.areValuesNullableByDefault() );
			valueBindings.add(
					new SimpleValueBinding(
							column,
							relationalValueSourceContainer.areValuesIncludedInInsertByDefault(),
							relationalValueSourceContainer.areValuesIncludedInUpdateByDefault()
					)
			);
		}
		attributeBinding.setSimpleValueBindings( valueBindings );
	}

	private String quoteIdentifier(String identifier) {
		return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( identifier ) : identifier;
	}

	private SimpleValue makeSimpleValue(
			EntityBinding entityBinding,
			RelationalValueSource valueSource) {
		final TableSpecification table = entityBinding.locateTable( valueSource.getContainingTableName() );

		if ( ColumnSource.class.isInstance( valueSource ) ) {
			return makeColumn( (ColumnSource) valueSource, table );
		}
		else {
			return makeDerivedValue( (DerivedValueSource) valueSource, table );
		}
	}

	private Column makeColumn(ColumnSource columnSource, TableSpecification table) {
		String name = columnSource.getName();
		name = metadata.getOptions().getNamingStrategy().columnName( name );
		name = quoteIdentifier( name );
		final Column column = table.locateOrCreateColumn( name );
		column.setNullable( columnSource.isNullable() );
		column.setDefaultValue( columnSource.getDefaultValue() );
		column.setSqlType( columnSource.getSqlType() );
		column.setSize( columnSource.getSize() );
		column.setDatatype( columnSource.getDatatype() );
		column.setReadFragment( columnSource.getReadFragment() );
		column.setWriteFragment( columnSource.getWriteFragment() );
		column.setUnique( columnSource.isUnique() );
		column.setCheckCondition( columnSource.getCheckCondition() );
		column.setComment( columnSource.getComment() );
		return column;
	}

	private DerivedValue makeDerivedValue(DerivedValueSource derivedValueSource, TableSpecification table) {
		return table.locateOrCreateDerivedValue( derivedValueSource.getExpression() );
	}

	private void processFetchProfiles(EntitySource entitySource, EntityBinding entityBinding) {
		// todo : process the entity-local fetch-profile declaration
	}

	private static class AttributeJavaTypeDeterminerDelegate implements BeanInfoHelper.BeanInfoDelegate {
		private final String attributeName;
		private Class<?> javaType = null;

		private AttributeJavaTypeDeterminerDelegate(String attributeName) {
			this.attributeName = attributeName;
		}

		@Override
		public void processBeanInfo(BeanInfo beanInfo) throws Exception {
			for ( PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors() ) {
				if ( propertyDescriptor.getName().equals( attributeName ) ) {
					javaType = propertyDescriptor.getPropertyType();
					break;
				}
			}
		}
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate Binder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.