Skip to content

Instantly share code, notes, and snippets.

@sebersole
Last active August 29, 2015 14:06
Show Gist options
  • Save sebersole/4197af3a95b6a19982b5 to your computer and use it in GitHub Desktop.
Save sebersole/4197af3a95b6a19982b5 to your computer and use it in GitHub Desktop.
package org.hibernate.cfg.naming;
/**
* Defines the source for entity naming. Between legacy Hibernate requirements and
* JPA requirements this is, unfortunately, multi-sourced. This contract allows
* access to all source values.
*
* @author Steve Ebersole
*/
public interface EntityNamingSource {
/**
* The FQN of the entity class. Note, this may be {@code null} in the case
* of (non-JPA-compliant) dynamic entities).
*
* @return The entity class FQN, or {@code null} if a dynamic entity.
*/
public String getEntityClassName();
/**
* Get the explicitly specified Hibernate entity name. The Hibernate name is
* very much different from the JPA concept of entity name.
*
* @return The explicitly specified entity name
*/
public String getExplicitEntityName();
/**
* The Hibernate entity name. This might be either:<ul>
* <li>The explicitly specified entity name, if one</li>
* <li>The unqualified entity class name if no entity name was explicitly specified</li>
* </ul>
*
* @return The Hibernate entity name
*/
public String getEntityName();
/**
* The JPA-specific entity name. See {@link javax.persistence.Entity#name()} for details.
*
* @return The JPA entity name, if one was specified. May return {@code null} if one
* was not explicitly specified.
*/
public String getJpaEntityName();
}
package org.hibernate.cfg.naming;
/**
* Database objects are generally defined within a schema and/or catalog (depending on the type and
* RDBMS). This is a common contract for sources of these database object names to consistently
* give access to the explicitly specified schema/catalog parts.
*
* @author Steve Ebersole
*/
public interface ExplicitDatabaseObjectNameSource {
/**
* Access to the explicitly specified schema name.
*
* @return The explicitly specified schema name, or {@code null} if not specified.
*/
public String getExplicitSchemaName();
/**
* Access to the explicitly specified catalog name.
*
* @return The explicitly specified catalog name, or {@code null} if not specified.
*/
public String getExplicitCatalogName();
}
package org.hibernate.cfg.naming;
/**
* Access to explicitly specified naming information for a database table.
*
* @author Steve Ebersole
*/
public interface ExplicitTableNameSource extends ExplicitDatabaseObjectNameSource {
/**
* Access to the explicitly specified table name.
*
* @return The explicitly specified table name, or {@code null} if not specified.
*/
public String getExplicitTableName();
}
import org.hibernate.metamodel.relational.ObjectName;
/**
* Access to the source information used to determine the logical name for a join table.
*
* @author Steve Ebersole
*
* @see javax.persistence.CollectionTable
*/
public interface LogicalCollectionTableNameSource {
/**
* Access to any explicit table name information
*
* @return The explicit table name information
*/
public ExplicitTableNameSource getExplicitTableNameSource();
/**
* Access to the physical name of the owning entity's primary table.
*
* @return Owning entity's primary table name.
*/
public ObjectName getOwningPhysicalTableName();
/**
* Access to entity naming information for the owning side.
*
* @return Owning entity naming information
*/
public EntityNamingSource getOwningEntityNamingSource();
/**
* Access to the name of the attribute, from the owning side, that defines the association.
*
* @return The owning side's attribute name.
*/
public String getAssociationOwningAttributeName();
}
package org.hibernate.cfg.naming;
import org.hibernate.metamodel.relational.ObjectName;
/**
* Access to the source information used to determine the logical name for a join table.
*
* @author Steve Ebersole
*
* @see javax.persistence.JoinTable
*/
public interface LogicalJoinTableNameSource {
/**
* Access to any explicit table name information
*
* @return The explicit table name information
*/
public ExplicitTableNameSource getExplicitTableNameSource();
/**
* Access to the physical name of the owning entity's primary table.
*
* @return Owning entity's primary table name.
*/
public ObjectName getOwningPhysicalTableName();
/**
* Access to entity naming information for the owning side.
*
* @return Owning entity naming information
*/
public EntityNamingSource getOwningEntityNamingSource();
/**
* Access to the physical name of the non-owning entity's primary table.
*
* @return Owning entity's primary table name.
*/
public ObjectName getNonOwningPhysicalTableName();
/**
* Access to entity naming information for the owning side.
*
* @return Owning entity naming information
*/
public EntityNamingSource getNonOwningEntityNamingSource();
/**
* Access to the name of the attribute, from the owning side, that defines the association.
*
* @return The owning side's attribute name.
*/
public String getAssociationOwningAttributeName();
}
package org.hibernate.cfg.naming;
/**
* Pluggable strategy contract for applying logical naming in determining database object names.
*
* @author Steve Ebersole
*/
public interface LogicalNamingStrategy {
/**
* Determine the logical name of a entity's primary table given the source naming
* information.
*
* @param source The source information
*
* @return The logical name.
*/
public LogicalTableName determinePrimaryTableLogicalName(LogicalPrimaryTableNameSource source);
/**
* Determine the logical name of an association join table.
*
* @param source The source information
*
* @return The logical name.
*/
public LogicalTableName determineJoinTableLogicalName(LogicalJoinTableNameSource source);
/**
* Determine the logical name of a collection table.
*
* @param source The source information
*
* @return The logical name.
*/
public LogicalTableName determineCollectionTableLogicalName(LogicalCollectionTableNameSource source);
}
package org.hibernate.cfg.naming;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.StringHelper;
/**
* Implementation of the LogicalNamingStrategy contract, generally preferring to conform
* to JPA standards.
*
* @author Steve Ebersole
*/
public class LogicalNamingStrategyStandardImpl implements LogicalNamingStrategy {
@Override
public LogicalTableName determinePrimaryTableLogicalName(LogicalPrimaryTableNameSource source) {
String schemaName = null;
String catalogName = null;
String tableName = null;
final ExplicitTableNameSource tableNameSource = source.getExplicitTableNameSource();
if ( tableNameSource != null ) {
schemaName = StringHelper.normalizeEmptyString( tableNameSource.getExplicitSchemaName() );
catalogName = StringHelper.normalizeEmptyString( tableNameSource.getExplicitCatalogName() );
tableName = StringHelper.normalizeEmptyString( tableNameSource.getExplicitTableName() );
}
if ( tableName == null ) {
final EntityNamingSource entityNamingSource = source.getEntityNamingSource();
if ( entityNamingSource == null ) {
// should never happen, but to be defensive...
throw new HibernateException( "Entity naming information was not provided." );
}
if ( StringHelper.isNotEmpty( entityNamingSource.getJpaEntityName() ) ) {
// prefer the JPA entity name, if specified...
tableName = entityNamingSource.getJpaEntityName();
}
else {
// otherwise, use the Hibernate entity name
tableName = entityNamingSource.getEntityName();
}
}
if ( tableName == null ) {
// todo : add info to error message
throw new HibernateException( "Could not determine primary table name for entity" );
}
return new LogicalTableName( schemaName, catalogName, tableName );
}
@Override
public LogicalTableName determineJoinTableLogicalName(LogicalJoinTableNameSource source) {
String schemaName = null;
String catalogName = null;
String tableName = null;
final ExplicitTableNameSource tableNameSource = source.getExplicitTableNameSource();
if ( tableNameSource != null ) {
schemaName = StringHelper.normalizeEmptyString( tableNameSource.getExplicitSchemaName() );
catalogName = StringHelper.normalizeEmptyString( tableNameSource.getExplicitCatalogName() );
tableName = StringHelper.normalizeEmptyString( tableNameSource.getExplicitTableName() );
}
if ( tableName == null ) {
// 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}
tableName = source.getOwningPhysicalTableName().getName().getName()
+ '_'
+ source.getNonOwningPhysicalTableName().getName().getName();
}
return new LogicalTableName( schemaName, catalogName, tableName );
}
@Override
public LogicalTableName determineCollectionTableLogicalName(LogicalCollectionTableNameSource source) {
...
}
}
package org.hibernate.cfg.naming;
/**
* Access to the source information used to determine the logical name for an entity's
* primary table.
*
* @author Steve Ebersole
*
* @see javax.persistence.Table
*/
public interface LogicalPrimaryTableNameSource {
/**
* Access to any explicit table name information
*
* @return The explicit table name information
*/
public ExplicitTableNameSource getExplicitTableNameSource();
/**
* Access to entity naming information.
*
* @return Entity naming information
*/
public EntityNamingSource getEntityNamingSource();
}
package org.hibernate.cfg.naming;
/**
* Represents the logical name of a table.
*
* @author Steve Ebersole
*/
public class LogicalTableName {
private final String schemaName;
private final String catalogName;
private final String tableName;
public LogicalTableName(String schemaName, String catalogName, String tableName) {
this.schemaName = schemaName;
this.catalogName = catalogName;
this.tableName = tableName;
}
public String getSchemaName() {
return schemaName;
}
public String getCatalogName() {
return catalogName;
}
public String getTableName() {
return tableName;
}
}
package org.hibernate.cfg.naming;
import org.hibernate.metamodel.relational.ObjectName;
/**
* Pluggable strategy contract for applying physical naming rules for database object names.
*
* NOTE: Ideally we'd pass "extra" things in here like Dialect, etc to better handle identifier
* length constraints or auto quoting of identifiers. However, the pre-5.0 model does not
* necessarily know this information at the time the strategy is called.
*
* @author Steve Ebersole
*/
public interface PhysicalNamingStrategy {
public ObjectName toPhysicalName(LogicalTableName logicalTableName);
}
@gbadner
Copy link

gbadner commented Sep 18, 2014

How about:

public interface LogicalPrimaryTableNameSource {
        public String getExplicitTableName();
        public EntityName getEntityName();
}

public interface EntityName {
        public String getEntityClassName();
        public String getEntityName();
        public String getJpaEntityName();
}

@sebersole
Copy link
Author

I can see that.

@sebersole
Copy link
Author

Though not sure I am a huge fan of calls like abc.getEntityName().getEntityName()

@gbadner
Copy link

gbadner commented Sep 18, 2014

"LogicalPrimaryTableNameSource is a ExplicitTableNameSource" isn't intuitive to me.

"LogicalPrimaryTableNameSource has a ExplicitTableNameSource" (or has a simple String representing the explicit table name).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment