diff --git a/documentation/src/main/asciidoc/introduction/Configuration.adoc b/documentation/src/main/asciidoc/introduction/Configuration.adoc index 3479293aaf62..22a355462ea7 100644 --- a/documentation/src/main/asciidoc/introduction/Configuration.adoc +++ b/documentation/src/main/asciidoc/introduction/Configuration.adoc @@ -503,10 +503,11 @@ We'll have more to say about them in <>. [[quoted-identifiers]] === Quoting SQL identifiers -By default, Hibernate never quotes SQL table and column names in generated SQL. +By default, Hibernate never quotes a SQL table or column name in generated SQL when the name contains only alphanumeric characters. This behavior is usually much more convenient, especially when working with a legacy schema, since unquoted identifiers aren't case-sensitive, and so Hibernate doesn't need to know or care whether a column is named `NAME`, `name`, or `Name` on the database side. +On the other hand, any table or column name containing a punctuation character like `$` is automatically quoted by default. -The following settings enable automatic quoting: +The following settings enable additional automatic quoting: .Settings for identifier quoting [%breakable,cols="35,~"] diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/DatabaseIdentifier.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/DatabaseIdentifier.java index 6578bd276d61..0a9fa4144ec7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/DatabaseIdentifier.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/DatabaseIdentifier.java @@ -4,7 +4,7 @@ */ package org.hibernate.boot.model.naming; -import org.hibernate.internal.util.StringHelper; +import static org.hibernate.internal.util.StringHelper.isEmpty; /** * Models an identifier (name), retrieved from the database. @@ -24,13 +24,13 @@ protected DatabaseIdentifier(String text) { } public static DatabaseIdentifier toIdentifier(String text) { - if ( StringHelper.isEmpty( text ) ) { + if ( isEmpty( text ) ) { return null; } else if ( isQuoted( text ) ) { // exclude the quotes from text - final String unquotedtext = text.substring( 1, text.length() - 1 ); - return new DatabaseIdentifier( unquotedtext ); + final String unquoted = text.substring( 1, text.length() - 1 ); + return new DatabaseIdentifier( unquoted ); } else { return new DatabaseIdentifier( text ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/Identifier.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/Identifier.java index 764034ea56e8..61398e34f694 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/Identifier.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/Identifier.java @@ -7,9 +7,12 @@ import java.util.Locale; import org.hibernate.dialect.Dialect; -import org.hibernate.internal.util.StringHelper; +import static java.lang.Character.isLetter; +import static java.lang.Character.isLetterOrDigit; +import static java.lang.Character.isWhitespace; import static org.hibernate.internal.util.StringHelper.isBlank; +import static org.hibernate.internal.util.StringHelper.isEmpty; /** * Models an identifier (name), which may or may not be quoted. @@ -83,13 +86,13 @@ public static Identifier toIdentifier(String text, boolean quote, boolean quoteO int start = 0; int end = text.length(); while ( start < end ) { - if ( !Character.isWhitespace( text.charAt( start ) ) ) { + if ( !isWhitespace( text.charAt( start ) ) ) { break; } start++; } while ( start < end ) { - if ( !Character.isWhitespace( text.charAt( end - 1 ) ) ) { + if ( !isWhitespace( text.charAt( end - 1 ) ) ) { break; } end--; @@ -102,14 +105,14 @@ public static Identifier toIdentifier(String text, boolean quote, boolean quoteO else if ( quoteOnNonIdentifierChar && !quote ) { // Check the letters to determine if we must quote the text char c = text.charAt( start ); - if ( !Character.isLetter( c ) && c != '_' ) { + if ( !isLetter( c ) && c != '_' ) { // SQL identifiers must begin with a letter or underscore quote = true; } else { for ( int i = start + 1; i < end; i++ ) { c = text.charAt( i ); - if ( !Character.isLetterOrDigit( c ) && c != '_' ) { + if ( !isLetterOrDigit( c ) && c != '_' ) { quote = true; break; } @@ -163,7 +166,7 @@ public static String unQuote(String name) { * @param quoted Is this a quoted identifier? */ public Identifier(String text, boolean quoted) { - if ( StringHelper.isEmpty( text ) ) { + if ( isEmpty( text ) ) { throw new IllegalIdentifierException( "Identifier text cannot be null" ); } if ( isQuoted( text ) ) { @@ -234,11 +237,9 @@ public String toString() { @Override public boolean equals(Object o) { - if ( !(o instanceof Identifier) ) { + if ( !(o instanceof Identifier that) ) { return false; } - - final Identifier that = (Identifier) o; return getCanonicalName().equals( that.getCanonicalName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java index e447a56ded32..6edc24bccbda 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java @@ -25,6 +25,7 @@ import org.hibernate.proxy.LazyInitializer; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; @@ -342,33 +343,12 @@ public Object replace( public int getHashCode(Object x, SessionFactoryImplementor factory) { final EntityPersister persister = getAssociatedEntityPersister( factory ); if ( isReferenceToPrimaryKey() ) { - final Object id; - final LazyInitializer lazyInitializer = extractLazyInitializer( x ); - if ( lazyInitializer != null ) { - id = lazyInitializer.getInternalIdentifier(); - } - else { - final Class mappedClass = persister.getMappedClass(); - if ( mappedClass.isInstance( x ) ) { - id = persister.getIdentifier( x ); - } - else { - id = x; - } - } - return persister.getIdentifierType().getHashCode( id, factory ); + return persister.getIdentifierType().getHashCode( getId( x, persister ), factory ); } else { assert uniqueKeyPropertyName != null; - final Object uniqueKey; final Type keyType = persister.getPropertyType( uniqueKeyPropertyName ); - if ( keyType.getReturnedClass().isInstance( x ) ) { - uniqueKey = x; - } - else { - uniqueKey = persister.getPropertyValue( x, uniqueKeyPropertyName ); - } - return keyType.getHashCode( uniqueKey, factory ); + return keyType.getHashCode( getUniqueKey( x, keyType, persister ), factory ); } } @@ -384,60 +364,41 @@ public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) { final EntityPersister persister = getAssociatedEntityPersister( factory ); if ( isReferenceToPrimaryKey() ) { - final Class mappedClass = persister.getMappedClass(); - Object xid; - final LazyInitializer lazyInitializerX = extractLazyInitializer( x ); - if ( lazyInitializerX != null ) { - xid = lazyInitializerX.getInternalIdentifier(); - } - else { - if ( mappedClass.isInstance( x ) ) { - xid = persister.getIdentifier( x ); - } - else { - //JPA 2 case where @IdClass contains the id and not the associated entity - xid = x; - } - } - - Object yid; - final LazyInitializer lazyInitializerY = extractLazyInitializer( y ); - if ( lazyInitializerY != null ) { - yid = lazyInitializerY.getInternalIdentifier(); - } - else { - if ( mappedClass.isInstance( y ) ) { - yid = persister.getIdentifier( y ); - } - else { - //JPA 2 case where @IdClass contains the id and not the associated entity - yid = y; - } - } - + final Object xid = getId( x, persister ); + final Object yid = getId( y, persister ); // Check for reference equality first as the type-specific checks by IdentifierType are sometimes non-trivial - return (xid == yid) || persister.getIdentifierType().isEqual( xid, yid, factory ); + return xid == yid || persister.getIdentifierType().isEqual( xid, yid, factory ); } else { assert uniqueKeyPropertyName != null; - final Object xUniqueKey; final Type keyType = persister.getPropertyType( uniqueKeyPropertyName ); - if ( keyType.getReturnedClass().isInstance( x ) ) { - xUniqueKey = x; - } - else { - xUniqueKey = persister.getPropertyValue( x, uniqueKeyPropertyName ); - } + final Object xUniqueKey = getUniqueKey( x, keyType, persister ); + final Object yUniqueKey = getUniqueKey( y, keyType, persister ); + return xUniqueKey == yUniqueKey + || keyType.isEqual( xUniqueKey, yUniqueKey, factory ); + } + } + + private Object getUniqueKey(Object entity, Type keyType, EntityPersister persister) { + return keyType.getReturnedClass().isInstance( entity ) + ? entity + : persister.getPropertyValue( entity, uniqueKeyPropertyName ); + } - final Object yUniqueKey; - if ( keyType.getReturnedClass().isInstance( y ) ) { - yUniqueKey = y; + private static Object getId(Object entity, EntityPersister persister) { + final LazyInitializer lazyInitializer = extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + return lazyInitializer.getInternalIdentifier(); + } + else { + final Class mappedClass = persister.getMappedClass(); + if ( mappedClass.isInstance( entity ) ) { + return persister.getIdentifier( entity ); } else { - yUniqueKey = persister.getPropertyValue( y, uniqueKeyPropertyName ); + //JPA 2 case where @IdClass contains the id and not the associated entity + return entity; } - return (xUniqueKey == yUniqueKey) - || keyType.isEqual( xUniqueKey, yUniqueKey, factory ); } } @@ -475,10 +436,9 @@ public EntityPersister getAssociatedEntityPersister(final SessionFactoryImplemen //form it returns the local variable to avoid a second volatile read: associatedEntityPersister //needs to be volatile as the initialization might happen by a different thread than the readers. if ( persister == null ) { - associatedEntityPersister = factory - .getRuntimeMetamodels() - .getMappingMetamodel() - .getEntityDescriptor( getAssociatedEntityName() ); + associatedEntityPersister = + factory.getMappingMetamodel() + .getEntityDescriptor( getAssociatedEntityName() ); return associatedEntityPersister; } else { @@ -486,13 +446,10 @@ public EntityPersister getAssociatedEntityPersister(final SessionFactoryImplemen } } - protected final Object getIdentifier(Object value, SharedSessionContractImplementor session) throws HibernateException { + protected final Object getIdentifier(Object value, SharedSessionContractImplementor session) + throws HibernateException { if ( isReferenceToIdentifierProperty() ) { - return ForeignKeys.getEntityIdentifierIfNotUnsaved( - getAssociatedEntityName(), - value, - session - ); //tolerates nulls + return getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls } else if ( value == null ) { return null; @@ -500,22 +457,19 @@ else if ( value == null ) { else { final LazyInitializer lazyInitializer = extractLazyInitializer( value ); if ( lazyInitializer != null ) { - /* - If the value is a Proxy and the property access is field, the value returned by - `attributeMapping.getAttributeMetadata().getPropertyAccess().getGetter().get( object )` - is always null except for the id, we need the to use the proxy implementation to - extract the property value. - */ + // If the value is a Proxy and the property access is field, the value returned by + // attributeMapping.getAttributeMetadata().getPropertyAccess().getGetter().get( object ) + // is always null except for the id, we need the to use the proxy implementation to + // extract the property value. value = lazyInitializer.getImplementation(); } else if ( isPersistentAttributeInterceptable( value ) ) { - /* - If the value is an instance of PersistentAttributeInterceptable, and it is not initialized - we need to force initialization the get the property value - */ - final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( value ).$$_hibernate_getInterceptor(); - if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { - ( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( value, null ); + // If the value is an instance of PersistentAttributeInterceptable, and it is + // not initialized, we need to force initialization the get the property value + final PersistentAttributeInterceptor interceptor = + asPersistentAttributeInterceptable( value ).$$_hibernate_getInterceptor(); + if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) { + lazinessInterceptor.forceInitialize( value, null ); } } final EntityPersister entityPersister = getAssociatedEntityPersister( session.getFactory() ); @@ -524,20 +478,17 @@ else if ( isPersistentAttributeInterceptable( value ) ) { // we need to dig a little deeper, as that property might also be // an entity type, in which case we need to resolve its identifier final Type type = entityPersister.getPropertyType( uniqueKeyPropertyName ); - if ( type instanceof EntityType ) { - return ( (EntityType) type ).getIdentifier( propertyValue, session ); - } - else { - return propertyValue; - } + return type instanceof EntityType entityType + ? entityType.getIdentifier( propertyValue, session ) + : propertyValue; } } - protected final Object getIdentifier(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException { + protected final Object getIdentifier(Object value, SessionFactoryImplementor sessionFactory) + throws HibernateException { if ( isReferenceToIdentifierProperty() ) { return getAssociatedEntityPersister( sessionFactory ) - .getIdentifierMapping() - .getIdentifier( value ); + .getIdentifierMapping().getIdentifier( value ); } else if ( value == null ) { return null; @@ -549,12 +500,9 @@ else if ( value == null ) { // we need to dig a little deeper, as that property might also be // an entity type, in which case we need to resolve its identifier final Type type = entityPersister.getPropertyType( uniqueKeyPropertyName ); - if ( type instanceof EntityType ) { - return ( (EntityType) type ).getIdentifier( propertyValue, sessionFactory ); - } - else { - return propertyValue; - } + return type instanceof EntityType entityType + ? entityType.getIdentifier( propertyValue, sessionFactory ) + : propertyValue; } } @@ -570,35 +518,32 @@ else if ( value == null ) { */ @Override public String toLoggableString(Object value, SessionFactoryImplementor factory) { - if ( value == null ) { - return "null"; - } + return value == null + ? "null" + : loggableString( value, getAssociatedEntityPersister( factory ) ); + } - final EntityPersister persister = getAssociatedEntityPersister( factory ); - if ( ! persister.isInstance( value ) ) { + private String loggableString(Object entity, EntityPersister persister) { + if ( !persister.isInstance( entity ) // it should be the id type... - if ( persister.getIdentifierType().getReturnedClass().isInstance( value ) ) { - return associatedEntityName + "#" + value; - } + && persister.getIdentifierType().getReturnedClass().isInstance( entity ) ) { + return associatedEntityName + "#" + entity; } - - final StringBuilder result = new StringBuilder().append( associatedEntityName ); - - if ( persister.hasIdentifierProperty() ) { - final Object id; - final LazyInitializer lazyInitializer = extractLazyInitializer( value ); - if ( lazyInitializer != null ) { - id = lazyInitializer.getInternalIdentifier(); - } - else { - id = persister.getIdentifier( value ); + else { + final StringBuilder result = new StringBuilder().append( associatedEntityName ); + if ( persister.hasIdentifierProperty() ) { + result.append( '#' ).append( identifierString( entity, persister ) ); } - - result.append( '#' ) - .append( persister.getIdentifierType().toLoggableString( id, factory ) ); + return result.toString(); } + } - return result.toString(); + private static String identifierString(Object entity, EntityPersister persister) { + final LazyInitializer lazyInitializer = extractLazyInitializer( entity ); + final Object id = lazyInitializer != null + ? lazyInitializer.getInternalIdentifier() + : persister.getIdentifier( entity ); + return persister.getIdentifierType().toLoggableString( id, persister.getFactory() ); } /** @@ -681,9 +626,11 @@ public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingEx } /** - * Determine the type of either (1) the identifier if we reference the - * associated entity's PK or (2) the unique key to which we refer (i.e. - * the property-ref). + * Determine the type of either: + *
    + *
  1. the identifier if we reference the primary key of the associated entity, or + *
  2. the unique key to which we refer, that is, the property-ref. + *
* * @param mappingContext The mappings context {@see MappingContext} * @@ -697,13 +644,11 @@ public final Type getIdentifierOrUniqueKeyType(MappingContext mappingContext) th return getIdentifierType( mappingContext ); } else { - final Type type = mappingContext.getReferencedPropertyType( getAssociatedEntityName(), uniqueKeyPropertyName ); - if ( type instanceof EntityType entityType ) { - return entityType.getIdentifierOrUniqueKeyType( mappingContext ); - } - else { - return type; - } + final Type type = + mappingContext.getReferencedPropertyType( getAssociatedEntityName(), uniqueKeyPropertyName ); + return type instanceof EntityType entityType + ? entityType.getIdentifierOrUniqueKeyType( mappingContext ) + : type; } } @@ -716,7 +661,10 @@ public final Type getIdentifierOrUniqueKeyType(MappingContext mappingContext) th * @return The appropriate property name. * * @throws MappingException Generally, if unable to resolve the associated entity name + * + * @deprecated No longer used */ + @Deprecated(since = "7", forRemoval = true) public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory) throws MappingException { return getIdentifierOrUniqueKeyPropertyName( (MappingContext) factory); @@ -761,22 +709,23 @@ public boolean isReferenceToIdentifierProperty() { * * @throws HibernateException Indicates problems performing the load. */ - protected final Object resolveIdentifier(Object id, SharedSessionContractImplementor session, Boolean overridingEager) throws HibernateException { - - final boolean isProxyUnwrapEnabled = unwrapProxy && - getAssociatedEntityPersister( session.getFactory() ) - .isInstrumented(); + protected final Object resolveIdentifier(Object id, SharedSessionContractImplementor session, Boolean overridingEager) + throws HibernateException { final boolean isEager = isEager( overridingEager ); // If the association is lazy, retrieve the concrete type if required - final String entityName = isEager ? getAssociatedEntityName() - : getAssociatedEntityPersister( session.getFactory() ).resolveConcreteProxyTypeForId( id, session ) + final String entityName = isEager + ? getAssociatedEntityName() + : getAssociatedEntityPersister( session.getFactory() ) + .resolveConcreteProxyTypeForId( id, session ) .getEntityName(); final Object proxyOrEntity = session.internalLoad( entityName, id, isEager, isNullable() ); final LazyInitializer lazyInitializer = extractLazyInitializer( proxyOrEntity ); if ( lazyInitializer != null ) { + final boolean isProxyUnwrapEnabled = + unwrapProxy && getAssociatedEntityPersister( session.getFactory() ).isInstrumented(); lazyInitializer.setUnwrap( isProxyUnwrapEnabled ); } @@ -809,13 +758,10 @@ public Object loadByUniqueKey( Object key, SharedSessionContractImplementor session) throws HibernateException { final SessionFactoryImplementor factory = session.getFactory(); - final EntityPersister persister = - factory.getMappingMetamodel() - .getEntityDescriptor( entityName ); //TODO: implement 2nd level caching?! natural id caching ?! proxies?! - final EntityUniqueKey euk = new EntityUniqueKey( + final EntityUniqueKey entityUniqueKey = new EntityUniqueKey( entityName, uniqueKeyPropertyName, key, @@ -824,29 +770,33 @@ public Object loadByUniqueKey( ); final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - Object result = persistenceContext.getEntity( euk ); - if ( result == null ) { - result = persister.loadByUniqueKey( uniqueKeyPropertyName, key, session ); - - // If the entity was not in the Persistence Context, but was found now, - // add it to the Persistence Context - if (result != null) { - persistenceContext.addEntity(euk, result); + final Object entity = persistenceContext.getEntity( entityUniqueKey ); + final Object result; + if ( entity == null ) { + result = factory.getMappingMetamodel().getEntityDescriptor( entityName ) + .loadByUniqueKey( uniqueKeyPropertyName, key, session ); + if ( result != null ) { + // If the entity was not in the persistence context, + // but was found now, add it to the persistence context + persistenceContext.addEntity( entityUniqueKey, result ); } } + else { + result = entity; + } return result == null ? null : persistenceContext.proxyFor( result ); } protected Type requireIdentifierOrUniqueKeyType(MappingContext mapping) { - final Type fkTargetType = getIdentifierOrUniqueKeyType( mapping ); - if ( fkTargetType == null ) { + final Type targetType = getIdentifierOrUniqueKeyType( mapping ); + if ( targetType == null ) { throw new MappingException( - "Unable to determine FK target Type for many-to-one or one-to-one mapping: " + + "Unable to determine foreign key target Type for many-to-one or one-to-one mapping: " + "referenced-entity-name=[" + getAssociatedEntityName() + "], referenced-entity-attribute-name=[" + getLHSPropertyName() + "]" ); } - return fkTargetType; + return targetType; } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java b/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java index d3e545b26190..e5f9fa1896e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java @@ -10,7 +10,6 @@ import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.MappingException; -import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -18,6 +17,8 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved; + /** * A many-to-one association to an entity. * @@ -117,7 +118,8 @@ public ForeignKeyDirection getForeignKeyDirection() { /** * Register the entity as batch loadable, if enabled */ - private void scheduleBatchLoadIfNeeded(Object id, SharedSessionContractImplementor session) throws MappingException { + private void scheduleBatchLoadIfNeeded(Object id, SharedSessionContractImplementor session) + throws MappingException { //cannot batch fetch by unique key (property-ref associations) if ( uniqueKeyPropertyName == null && id != null ) { final EntityPersister persister = getAssociatedEntityPersister( session.getFactory() ); @@ -141,26 +143,28 @@ public boolean isModified( Object old, Object current, boolean[] checkable, - SharedSessionContractImplementor session) throws HibernateException { + SharedSessionContractImplementor session) + throws HibernateException { if ( current == null ) { return old != null; } - if ( old == null ) { + else if ( old == null ) { // we already know current is not null... return true; } - - - // the ids are fully resolved, so compare them with isDirty(), not isModified() - return getIdentifierOrUniqueKeyType( session.getFactory() ) - .isDirty( old, getIdentifier( current, session ), session ); + else { + // the ids are fully resolved, so compare them with isDirty(), not isModified() + return getIdentifierOrUniqueKeyType( session.getFactory() ) + .isDirty( old, getIdentifier( current, session ), session ); + } } @Override public Serializable disassemble( Object value, SharedSessionContractImplementor session, - Object owner) throws HibernateException { + Object owner) + throws HibernateException { if ( value == null ) { return null; @@ -168,57 +172,44 @@ public Serializable disassemble( else { // cache the actual id of the object, not the value of the // property-ref, which might not be initialized - Object id = ForeignKeys.getEntityIdentifierIfNotUnsaved( - getAssociatedEntityName(), - value, - session - ); - if ( id == null ) { - throw new AssertionFailure( - "cannot cache a reference to an object with a null id: " + - getAssociatedEntityName() - ); - } + final Object id = getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); + checkIdNotNull( id ); return getIdentifierType( session ).disassemble( id, session, owner ); } } @Override - public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException { + public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) + throws HibernateException { if ( value == null ) { return null; } else { // cache the actual id of the object, not the value of the // property-ref, which might not be initialized - Object id = getIdentifier( value, sessionFactory ); - if ( id == null ) { - throw new AssertionFailure( - "cannot cache a reference to an object with a null id: " + - getAssociatedEntityName() - ); - } + final Object id = getIdentifier( value, sessionFactory ); + checkIdNotNull( id ); return getIdentifierType( sessionFactory ).disassemble( id, sessionFactory ); } } + private void checkIdNotNull(Object id) { + if ( id == null ) { + throw new AssertionFailure( + "cannot cache a reference to an object with a null id: " + getAssociatedEntityName() + ); + } + } + @Override public Object assemble( Serializable oid, SharedSessionContractImplementor session, Object owner) throws HibernateException { - //TODO: currently broken for unique-key references (does not detect // change to unique key property of the associated object) - - Object id = assembleId( oid, session ); - - if ( id == null ) { - return null; - } - else { - return resolveIdentifier( id, session ); - } + final Object id = assembleId( oid, session ); + return id == null ? null : resolveIdentifier( id, session ); } private Object assembleId(Serializable oid, SharedSessionContractImplementor session) { @@ -233,7 +224,7 @@ public void beforeAssemble(Serializable oid, SharedSessionContractImplementor se @Override public boolean[] toColumnNullness(Object value, MappingContext mapping) { - boolean[] result = new boolean[ getColumnSpan( mapping ) ]; + final boolean[] result = new boolean[ getColumnSpan( mapping ) ]; if ( value != null ) { Arrays.fill( result, true ); } @@ -248,9 +239,11 @@ public boolean isDirty( if ( isSame( old, current ) ) { return false; } - Object oldid = getIdentifier( old, session ); - Object newid = getIdentifier( current, session ); - return getIdentifierOrUniqueKeyType( session.getFactory() ).isDirty( oldid, newid, session ); + else { + final Object oldid = getIdentifier( old, session ); + final Object newid = getIdentifier( current, session ); + return getIdentifierOrUniqueKeyType( session.getFactory() ).isDirty( oldid, newid, session ); + } } @Override @@ -262,15 +255,14 @@ public boolean isDirty( if ( isAlwaysDirtyChecked() ) { return isDirty( old, current, session ); } + else if ( isSame( old, current ) ) { + return false; + } else { - if ( isSame( old, current ) ) { - return false; - } - Object oldid = getIdentifier( old, session ); - Object newid = getIdentifier( current, session ); + final Object oldid = getIdentifier( old, session ); + final Object newid = getIdentifier( current, session ); return getIdentifierOrUniqueKeyType( session.getFactory() ).isDirty( oldid, newid, checkable, session ); } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java b/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java index ccbd5e421d0f..0221765350ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java @@ -12,10 +12,12 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_BOOLEAN_ARRAY; +import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_INT_ARRAY; + /** * A one-to-one association to an entity * @@ -80,17 +82,22 @@ public int getColumnSpan(MappingContext session) throws MappingException { } @Override - public int[] getSqlTypeCodes(MappingContext mappingContext) throws MappingException { - return ArrayHelper.EMPTY_INT_ARRAY; + public int[] getSqlTypeCodes(MappingContext mappingContext) { + return EMPTY_INT_ARRAY; } @Override public boolean[] toColumnNullness(Object value, MappingContext mapping) { - return ArrayHelper.EMPTY_BOOLEAN_ARRAY; + return EMPTY_BOOLEAN_ARRAY; } @Override - public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) { + public void nullSafeSet( + PreparedStatement st, + Object value, + int index, + boolean[] settable, + SharedSessionContractImplementor session) { //nothing to do } @@ -130,21 +137,22 @@ public boolean useLHSPrimaryKey() { } @Override - public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException { + public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) { return null; } @Override - public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException { + public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) { return null; } @Override - public Object assemble(Serializable oid, SharedSessionContractImplementor session, Object owner) throws HibernateException { + public Object assemble(Serializable oid, SharedSessionContractImplementor session, Object owner) + throws HibernateException { //this should be a call to resolve(), not resolveIdentifier(), //because it might be a property-ref, and we did not cache the //referenced value - return resolve( session.getContextEntityIdentifier(owner), session, owner ); + return resolve( session.getContextEntityIdentifier( owner ), session, owner ); } /**