Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: hibernate/hibernate-orm
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6.2.34
Choose a base ref
...
head repository: hibernate/hibernate-orm
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6.2.35
Choose a head ref
  • 8 commits
  • 22 files changed
  • 6 contributors

Commits on Feb 26, 2025

  1. Post-steps for release : 6.2.34.Final

    Hibernate-CI committed Feb 26, 2025
    Copy the full SHA
    9d2f9bd View commit details

Commits on Mar 3, 2025

  1. Copy the full SHA
    3b5540a View commit details
  2. HHH-19206 Skip dirty tracking for embedded id fields

    beikov committed Mar 3, 2025
    Copy the full SHA
    6b462c1 View commit details

Commits on Mar 5, 2025

  1. HHH-17151 Add test for issue

    msfm authored and mbladel committed Mar 5, 2025
    Copy the full SHA
    baedaae View commit details
  2. Copy the full SHA
    283e27c View commit details

Commits on Mar 6, 2025

  1. HHH-18229 Handle null owner key for collections

    (cherry picked from commit 1f08501)
    soul2zimate authored and beikov committed Mar 6, 2025
    Copy the full SHA
    a894991 View commit details

Commits on Mar 7, 2025

  1. Copy the full SHA
    d2f6f4e View commit details

Commits on Mar 9, 2025

  1. Copy the full SHA
    78c665f View commit details
Showing with 777 additions and 141 deletions.
  1. +12 −0 changelog.txt
  2. +1 −1 gradle/version.properties
  3. +8 −11 hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java
  4. +12 −2 hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java
  5. +3 −2 ...e/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/InlineDirtyCheckingHandler.java
  6. +13 −8 hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java
  7. +5 −4 hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java
  8. +5 −3 hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java
  9. +3 −1 hibernate-core/src/main/java/org/hibernate/engine/spi/CollectionEntry.java
  10. +3 −2 hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java
  11. +17 −15 hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java
  12. +2 −1 hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java
  13. +2 −1 hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CollectionLoaderSubSelectFetch.java
  14. +5 −1 hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
  15. +30 −8 hibernate-core/src/main/java/org/hibernate/query/internal/BindingTypeHelper.java
  16. +8 −23 hibernate-core/src/main/java/org/hibernate/type/CollectionType.java
  17. +12 −0 hibernate-core/src/main/java/org/hibernate/type/descriptor/java/TemporalJavaType.java
  18. +99 −0 hibernate-core/src/test/java/org/hibernate/orm/test/annotations/onetoone/JoinColumnTest.java
  19. +117 −0 ...ate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/dirty/DirtyTrackingIdTest.java
  20. +147 −0 ...-core/src/test/java/org/hibernate/orm/test/collection/NonPkCompositeJoinColumnCollectionTest.java
  21. +195 −0 hibernate-core/src/test/java/org/hibernate/orm/test/collection/NonPkJoinColumnCollectionTest.java
  22. +78 −58 hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/DateTimeParameterTest.java
12 changes: 12 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -3,6 +3,18 @@ Hibernate 6 Changelog

Note: Please refer to JIRA to learn more about each issue.

Changes in 6.2.35.Final (March 09, 2025)
------------------------------------------------------------------------------------------------------------------------

https://hibernate.atlassian.net/projects/HHH/versions/32713

** Bug
* [HHH-19206] - Bytecode-enhanced dirty checking ineffective if entity's embedded ID set manually (to same value)
* [HHH-18229] - "UnsupportedOperationException: Re-work support for semi-resolve " with null value in column referenced by @JoinColumn
* [HHH-17420] - JoinColumn throws an `occurs out of order` AnnotationException
* [HHH-17151] - NPE when binding null parameter in native query with explicit TemporalType


Changes in 6.2.34.Final (February 26, 2025)
------------------------------------------------------------------------------------------------------------------------

2 changes: 1 addition & 1 deletion gradle/version.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
hibernateVersion=6.2.34.Final
hibernateVersion=6.2.35.Final
Original file line number Diff line number Diff line change
@@ -201,19 +201,16 @@ private void addCollectionKey(
PersistenceContext persistenceContext) {
if ( o instanceof PersistentCollection ) {
final CollectionPersister collectionPersister = pluralAttributeMapping.getCollectionDescriptor();
final CollectionKey collectionKey = new CollectionKey(
final Object key = ( (AbstractEntityPersister) getPersister() ).getCollectionKey(
collectionPersister,
( (AbstractEntityPersister) getPersister() ).getCollectionKey(
collectionPersister,
getInstance(),
persistenceContext.getEntry( getInstance() ),
getSession()
)
);
persistenceContext.addCollectionByKey(
collectionKey,
(PersistentCollection<?>) o
getInstance(),
persistenceContext.getEntry( getInstance() ),
getSession()
);
if ( key != null ) {
final CollectionKey collectionKey = new CollectionKey( collectionPersister, key );
persistenceContext.addCollectionByKey( collectionKey, (PersistentCollection<?>) o );
}
}
}

Original file line number Diff line number Diff line change
@@ -444,9 +444,16 @@ else if ( columnOwner instanceof Join ) {
// which are mapped to that column. (There might be multiple such
// properties for each column.)
if ( columnOwner instanceof PersistentClass ) {
PersistentClass persistentClass = (PersistentClass) columnOwner;
final PersistentClass persistentClass = (PersistentClass) columnOwner;
// Process ToOne associations after Components, Basic and Id properties
final List<Property> toOneProperties = new ArrayList<>();
for ( Property property : persistentClass.getProperties() ) {
matchColumnsByProperty( property, columnsToProperty );
if ( property.getValue() instanceof ToOne ) {
toOneProperties.add( property );
}
else {
matchColumnsByProperty( property, columnsToProperty );
}
}
if ( persistentClass.hasIdentifierProperty() ) {
matchColumnsByProperty( persistentClass.getIdentifierProperty(), columnsToProperty );
@@ -458,6 +465,9 @@ else if ( columnOwner instanceof Join ) {
matchColumnsByProperty( p, columnsToProperty );
}
}
for ( Property property : toOneProperties ) {
matchColumnsByProperty( property, columnsToProperty );
}
}
else {
for ( Property property : ((Join) columnOwner).getProperties() ) {
Original file line number Diff line number Diff line change
@@ -78,8 +78,9 @@ else if ( !persistentField.hasAnnotation( Id.class )
}

if ( enhancementContext.isCompositeField( persistentField )
// Don't do composite owner tracking for records
&& !persistentField.getType().isRecord() ) {
&& !persistentField.hasAnnotation( EmbeddedId.class )
// Don't do composite owner tracking for records
&& !persistentField.getType().isRecord() ) {

// HHH-13759 - Call getter on superclass if field is not visible
// An embedded field won't be visible if declared private in a superclass
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import java.util.Map;
import java.util.UUID;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.AssertionFailure;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
@@ -42,6 +43,10 @@
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;

import org.checkerframework.checker.nullness.qual.Nullable;

import static org.hibernate.pretty.MessageHelper.collectionInfoString;

/**
* Base class implementing {@link PersistentCollection}
*
@@ -58,16 +63,16 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P

private transient List<DelayedOperation<E>> operationQueue;
private transient boolean directlyAccessible;
private Object owner;
private @Nullable Object owner;
private int cachedSize = -1;

private String role;
private Object key;
private @Nullable String role;
private @Nullable Object key;
// collections detect changes made via their public interface and mark
// themselves as dirty as a performance optimization
private boolean dirty;
protected boolean elementRemoved;
private Serializable storedSnapshot;
private @Nullable Serializable storedSnapshot;

private String sessionFactoryUuid;
private boolean allowLoadOutsideTransaction;
@@ -84,12 +89,12 @@ protected AbstractPersistentCollection(SharedSessionContractImplementor session)
}

@Override
public final String getRole() {
public final @Nullable String getRole() {
return role;
}

@Override
public final Object getKey() {
public final @Nullable Object getKey() {
return key;
}

@@ -120,7 +125,7 @@ public final void dirty() {
}

@Override
public final Serializable getStoredSnapshot() {
public final @Nullable Serializable getStoredSnapshot() {
return storedSnapshot;
}

@@ -1351,7 +1356,7 @@ public Object getIdentifier(Object entry, int i) {
}

@Override
public Object getOwner() {
public @Nullable Object getOwner() {
return owner;
}

Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
import java.util.Iterator;
import java.util.List;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.HibernateException;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -60,7 +61,7 @@ public interface PersistentCollection<E> extends LazyInitializable {
*
* @return The owner
*/
Object getOwner();
@Nullable Object getOwner();

/**
* Set the reference to the owning entity
@@ -403,14 +404,14 @@ default boolean needsUpdating(
*
* @return the current collection key value
*/
Object getKey();
@Nullable Object getKey();

/**
* Get the current role name
*
* @return the collection role name
*/
String getRole();
@Nullable String getRole();

/**
* Is the collection unreferenced?
@@ -459,7 +460,7 @@ default boolean isDirectlyProvidedCollection(Object collection) {
*
* @return The internally stored snapshot state
*/
Serializable getStoredSnapshot();
@Nullable Serializable getStoredSnapshot();

/**
* Mark the collection as dirty
Original file line number Diff line number Diff line change
@@ -875,8 +875,10 @@ public void addUninitializedCollection(CollectionPersister persister, Persistent

@Override
public void addUninitializedDetachedCollection(CollectionPersister persister, PersistentCollection<?> collection) {
final CollectionEntry ce = new CollectionEntry( persister, collection.getKey() );
addCollection( collection, ce, collection.getKey() );
final Object key = collection.getKey();
assert key != null;
final CollectionEntry ce = new CollectionEntry( persister, key );
addCollection( collection, ce, key );
if ( persister.getBatchSize() > 1 ) {
getBatchFetchQueue().addBatchLoadableCollection( collection, ce );
}
@@ -934,7 +936,7 @@ private void addCollection(PersistentCollection<?> collection, CollectionPersist
@Override
public void addInitializedDetachedCollection(CollectionPersister collectionPersister, PersistentCollection<?> collection)
throws HibernateException {
if ( collection.isUnreferenced() ) {
if ( collection.isUnreferenced() || collection.getKey() == null ) {
//treat it just like a new collection
addCollection( collection, collectionPersister );
}
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;

@@ -118,8 +119,9 @@ public CollectionEntry(PersistentCollection<?> collection, SessionFactoryImpleme
ignore = false;

loadedKey = collection.getKey();
role = collection.getRole();
setLoadedPersister(
factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( collection.getRole() )
factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( NullnessUtil.castNonNull( role ) )
);

snapshot = collection.getStoredSnapshot();
Original file line number Diff line number Diff line change
@@ -407,7 +407,8 @@ protected void postFlush(SessionImplementor session) throws HibernateException {
persistenceContext.forEachCollectionEntry(
(persistentCollection, collectionEntry) -> {
collectionEntry.postFlush( persistentCollection );
if ( collectionEntry.getLoadedPersister() == null ) {
final Object key;
if ( collectionEntry.getLoadedPersister() == null || ( key = collectionEntry.getLoadedKey() ) == null ) {
//if the collection is dereferenced, unset its session reference and remove from the session cache
//iter.remove(); //does not work, since the entrySet is not backed by the set
persistentCollection.unsetSession( session );
@@ -417,7 +418,7 @@ protected void postFlush(SessionImplementor session) throws HibernateException {
//otherwise recreate the mapping between the collection and its key
CollectionKey collectionKey = new CollectionKey(
collectionEntry.getLoadedPersister(),
collectionEntry.getLoadedKey()
key
);
persistenceContext.addCollectionByKey( collectionKey, persistentCollection );
}
Original file line number Diff line number Diff line change
@@ -123,22 +123,24 @@ else if ( attributeInterceptor != null
entry,
session
);
PersistentCollection<?> collectionInstance = persistenceContext.getCollection(
new CollectionKey( persister, key )
);

if ( collectionInstance == null ) {
// the collection has not been initialized and new collection values have been assigned,
// we need to be sure to delete all the collection elements before inserting the new ones
collectionInstance = persister.getCollectionSemantics().instantiateWrapper(
key,
persister,
session
if ( key != null ) {
PersistentCollection<?> collectionInstance = persistenceContext.getCollection(
new CollectionKey( persister, key )
);
persistenceContext.addUninitializedCollection( persister, collectionInstance, key );
final CollectionEntry collectionEntry = persistenceContext.getCollectionEntry(
collectionInstance );
collectionEntry.setDoremove( true );

if ( collectionInstance == null ) {
// the collection has not been initialized and new collection values have been assigned,
// we need to be sure to delete all the collection elements before inserting the new ones
collectionInstance = persister.getCollectionSemantics().instantiateWrapper(
key,
persister,
session
);
persistenceContext.addUninitializedCollection( persister, collectionInstance, key );
final CollectionEntry collectionEntry =
persistenceContext.getCollectionEntry( collectionInstance );
collectionEntry.setDoremove( true );
}
}
}
}
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.cache.CacheException;
@@ -1690,7 +1691,7 @@ void cannotResolveNonNullableTransientDependencies(
+ " This is likely due to unsafe use of the session (e.g. used in multiple threads concurrently, updates during entity lifecycle hooks).",
id = 479
)
String collectionNotProcessedByFlush(String role);
String collectionNotProcessedByFlush(@Nullable String role);

@LogMessage(level = WARN)
@Message(value = "A ManagedEntity was associated with a stale PersistenceContext. A ManagedEntity may only be associated with one PersistenceContext at a time; %s", id = 480)
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.spi.CollectionLoader;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
@@ -147,7 +148,7 @@ public PersistentCollection<?> load(Object triggerKey, SharedSessionContractImpl
persistenceContext,
getLoadable().getCollectionDescriptor(),
c,
c.getKey(),
NullnessUtil.castNonNull( c.getKey() ),
true
);
}
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
import org.hibernate.Filter;
@@ -292,6 +293,8 @@
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
@@ -1463,6 +1466,7 @@ public Object initializeLazyProperty(String fieldName, Object entity, SharedSess
// see if there is already a collection instance associated with the session
// NOTE : can this ever happen?
final Object key = getCollectionKey( persister, entity, entry, session );
assert key != null;
PersistentCollection<?> collection = persistenceContext.getCollection( new CollectionKey( persister, key ) );
if ( collection == null ) {
collection = collectionType.instantiate( session, persister, key );
@@ -1531,7 +1535,7 @@ public Object initializeLazyProperty(String fieldName, Object entity, SharedSess

}

public Object getCollectionKey(
public @Nullable Object getCollectionKey(
CollectionPersister persister,
Object owner,
EntityEntry ownerEntry,
Loading