/*
 * 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.boot.model.naming;

import java.io.Serializable;

import org.hibernate.HibernateException;
import org.hibernate.boot.model.source.spi.AttributePath;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.util.StringHelper;

Implementation of the ImplicitNamingStrategy contract, generally preferring to conform to JPA standards.

For the legacy JPA-based naming standards initially implemented by Hibernate, see/use ImplicitNamingStrategyLegacyJpaImpl
Author:Steve Ebersole
/** * Implementation of the ImplicitNamingStrategy contract, generally preferring to conform * to JPA standards. * <p/> * For the legacy JPA-based naming standards initially implemented by Hibernate, * see/use {@link org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl} * * @author Steve Ebersole */
public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStrategy, Serializable { public static final ImplicitNamingStrategy INSTANCE = new ImplicitNamingStrategyJpaCompliantImpl(); public ImplicitNamingStrategyJpaCompliantImpl() { } @Override public Identifier determinePrimaryTableName(ImplicitEntityNameSource source) { if ( source == null ) { // should never happen, but to be defensive... throw new HibernateException( "Entity naming information was not provided." ); } String tableName = transformEntityName( source.getEntityNaming() ); if ( tableName == null ) { // todo : add info to error message - but how to know what to write since we failed to interpret the naming source throw new HibernateException( "Could not determine primary table name for entity" ); } return toIdentifier( tableName, source.getBuildingContext() ); } protected String transformEntityName(EntityNaming entityNaming) { // prefer the JPA entity name, if specified... if ( StringHelper.isNotEmpty( entityNaming.getJpaEntityName() ) ) { return entityNaming.getJpaEntityName(); } else { // otherwise, use the Hibernate entity name return StringHelper.unqualify( entityNaming.getEntityName() ); } } @Override public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) { // JPA states we should use the following as default: // "The concatenated names of the two associated primary entity tables (owning side // first), separated by an underscore." // aka: // {OWNING SIDE PRIMARY TABLE NAME}_{NON-OWNING SIDE PRIMARY TABLE NAME} final String name = source.getOwningPhysicalTableName() + '_' + source.getNonOwningPhysicalTableName(); return toIdentifier( name, source.getBuildingContext() ); } @Override public Identifier determineCollectionTableName(ImplicitCollectionTableNameSource source) { // JPA states we should use the following as default: // "The concatenation of the name of the containing entity and the name of the // collection attribute, separated by an underscore. // aka: // if owning entity has a JPA entity name: {OWNER JPA ENTITY NAME}_{COLLECTION ATTRIBUTE NAME} // otherwise: {OWNER ENTITY NAME}_{COLLECTION ATTRIBUTE NAME} final String entityName = transformEntityName( source.getOwningEntityNaming() ); final String name = entityName + '_' + transformAttributePath( source.getOwningAttributePath() ); return toIdentifier( name, source.getBuildingContext() ); } @Override public Identifier determineIdentifierColumnName(ImplicitIdentifierColumnNameSource source) { // JPA states the implicit column name should be the attribute name return toIdentifier( transformAttributePath( source.getIdentifierAttributePath() ), source.getBuildingContext() ); } @Override public Identifier determineDiscriminatorColumnName(ImplicitDiscriminatorColumnNameSource source) { return toIdentifier( source.getBuildingContext().getMappingDefaults().getImplicitDiscriminatorColumnName(), source.getBuildingContext() ); } @Override public Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource source) { return toIdentifier( source.getBuildingContext().getMappingDefaults().getImplicitTenantIdColumnName(), source.getBuildingContext() ); } @Override public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) { // JPA states we should use the following as default: // "The property or field name" // aka: // The unqualified attribute path. return toIdentifier( transformAttributePath( source.getAttributePath() ), source.getBuildingContext() ); } @Override public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) { // JPA states we should use the following as default: // // (1) if there is a "referencing relationship property": // "The concatenation of the following: the name of the referencing relationship // property or field of the referencing entity or embeddable class; "_"; the // name of the referenced primary key column." // // (2) if there is no such "referencing relationship property", or if the association is // an element collection: // "The concatenation of the following: the name of the entity; "_"; the name of the // referenced primary key column" // todo : we need to better account for "referencing relationship property" final String name; if ( source.getNature() == ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION || source.getAttributePath() == null ) { name = transformEntityName( source.getEntityNaming() ) + '_' + source.getReferencedColumnName().getText(); } else { name = transformAttributePath( source.getAttributePath() ) + '_' + source.getReferencedColumnName().getText(); } return toIdentifier( name, source.getBuildingContext() ); } @Override public Identifier determinePrimaryKeyJoinColumnName(ImplicitPrimaryKeyJoinColumnNameSource source) { // JPA states we should use the following as default: // "the same name as the primary key column [of the referenced table]" return source.getReferencedPrimaryKeyColumnName(); } @Override public Identifier determineAnyDiscriminatorColumnName(ImplicitAnyDiscriminatorColumnNameSource source) { return toIdentifier( transformAttributePath( source.getAttributePath() ) + "_" + source.getBuildingContext().getMappingDefaults().getImplicitDiscriminatorColumnName(), source.getBuildingContext() ); } @Override public Identifier determineAnyKeyColumnName(ImplicitAnyKeyColumnNameSource source) { return toIdentifier( transformAttributePath( source.getAttributePath() ) + "_" + source.getBuildingContext().getMappingDefaults().getImplicitIdColumnName(), source.getBuildingContext() ); } @Override public Identifier determineMapKeyColumnName(ImplicitMapKeyColumnNameSource source) { return toIdentifier( transformAttributePath( source.getPluralAttributePath() ) + "_KEY", source.getBuildingContext() ); } @Override public Identifier determineListIndexColumnName(ImplicitIndexColumnNameSource source) { return toIdentifier( transformAttributePath( source.getPluralAttributePath() ) + "_ORDER", source.getBuildingContext() ); } @Override public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) { Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); source.getBuildingContext().getBuildingOptions().getSchemaCharset(); return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( NamingHelper.withCharset( source.getBuildingContext().getBuildingOptions().getSchemaCharset() ).generateHashedFkName( "FK", source.getTableName(), source.getReferencedTableName(), source.getColumnNames() ), source.getBuildingContext() ); } @Override public Identifier determineUniqueKeyName(ImplicitUniqueKeyNameSource source) { Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( NamingHelper.withCharset( source.getBuildingContext().getBuildingOptions().getSchemaCharset() ).generateHashedConstraintName( "UK", source.getTableName(), source.getColumnNames() ), source.getBuildingContext() ); } @Override public Identifier determineIndexName(ImplicitIndexNameSource source) { Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( NamingHelper.withCharset( source.getBuildingContext().getBuildingOptions().getSchemaCharset() ).generateHashedConstraintName( "IDX", source.getTableName(), source.getColumnNames() ), source.getBuildingContext() ); }
For JPA standards we typically need the unqualified name. However, a more usable impl tends to use the whole path. This method provides an easy hook for subclasses to accomplish that
Params:
  • attributePath – The attribute path
Returns:The extracted name
/** * For JPA standards we typically need the unqualified name. However, a more usable * impl tends to use the whole path. This method provides an easy hook for subclasses * to accomplish that * * @param attributePath The attribute path * * @return The extracted name */
protected String transformAttributePath(AttributePath attributePath) { return attributePath.getProperty(); }
Easy hook to build an Identifier using the keyword safe IdentifierHelper.
Params:
  • stringForm – The String form of the name
  • buildingContext – Access to the IdentifierHelper
Returns:The identifier
/** * Easy hook to build an Identifier using the keyword safe IdentifierHelper. * * @param stringForm The String form of the name * @param buildingContext Access to the IdentifierHelper * * @return The identifier */
protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) { return buildingContext.getMetadataCollector() .getDatabase() .getJdbcEnvironment() .getIdentifierHelper() .toIdentifier( stringForm ); } }