Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ version = projectVersion
// ./gradlew clean build -PhibernateOrmVersion=5.6.15-SNAPSHOT
ext {
if ( !project.hasProperty('hibernateOrmVersion') ) {
hibernateOrmVersion = '6.2.7.Final'
hibernateOrmVersion = '6.3.0.CR1'
}
if ( !project.hasProperty( 'hibernateOrmGradlePluginVersion' ) ) {
// Same as ORM as default
Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ org.gradle.java.installations.auto-download=false
#db = MSSQL

# Enable the SonatypeOS maven repository (mainly for Vert.x snapshots) when present (value ignored)
#enableSonatypeOpenSourceSnapshotsRep = true
enableSonatypeOpenSourceSnapshotsRep = true

# Enable the maven local repository (for local development when needed) when present (value ignored)
#enableMavenLocalRepo = true
# enableMavenLocalRepo = true

# Override default Hibernate ORM version
#hibernateOrmVersion = 6.2.3.Final
hibernateOrmVersion = 6.3.0-SNAPSHOT

# Override default Hibernate ORM Gradle plugin version
# Using the stable version because I don't know how to configure the build to download the snapshot version from
# a remote repository
#hibernateOrmGradlePluginVersion = 6.2.3.Final
hibernateOrmGradlePluginVersion = 6.3.0.CR1

# If set to true, skip Hibernate ORM version parsing (default is true, if set to null)
# this is required when using intervals or weird versions or the build will fail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.hibernate.Incubating;

import jakarta.persistence.metamodel.SingularAttribute;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -16,90 +17,89 @@
* Represents a value of an attribute that forms part of the
* natural key of an entity.
*
* @see org.hibernate.annotations.NaturalId
*
* @param <T> the owning entity class
* @see org.hibernate.annotations.NaturalId
*/
@Incubating
public abstract class Identifier<T> {

public abstract Id<T>[] ids();

public abstract Map<String,Object> namedValues();

public static class Id<T> extends Identifier<T> {
private <I> Id(SingularAttribute<T,I> attribute, I id) {
this.id = id;
this.attributeName = attribute.getName();
}

private Id(String attributeName, Object id) {
this.attributeName = attributeName;
this.id = id;
}

private final String attributeName;
private final Object id;

public Object getId() {
return id;
}

public String getAttributeName() {
return attributeName;
}

@Override
public Id<T>[] ids() {
return new Id[]{this};
}

@Override
public Map<String, Object> namedValues() {
return Collections.singletonMap(attributeName, id);
}
}

public static class Composite<T> extends Identifier<T> {
Id<T>[] ids;

public Composite(Id<T>[] ids) {
this.ids = ids;
}

public Id<T>[] getValues() {
return ids;
}

@Override
public Id<T>[] ids() {
return ids;
}

@Override
public Map<String, Object> namedValues() {
Map<String, Object> namedValues = new HashMap<>();
for (Id<T> id : ids) {
namedValues.put( id.getAttributeName(), id.getId() );
}
return namedValues;
}
}

public static <T,I> Id<T> id(SingularAttribute<T,I> attribute, I id) {
return new Id<>(attribute, id);
}

public static <T> Id<T> id(String attributeName, Object id) {
return new Id<>(attributeName, id);
}

public static <T> Id<T> id(Class<T> entityClass, String attributeName, Object id) {
return new Id<>(attributeName, id);
}

@SafeVarargs
public static <T> Identifier<T> composite(Id<T>... ids) {
return new Composite<>(ids);
}
public abstract Id<T>[] ids();

public abstract Map<String, Object> namedValues();

public static class Id<T> extends Identifier<T> {
private <I> Id(SingularAttribute<T, I> attribute, I id) {
this.id = id;
this.attributeName = attribute.getName();
}

private Id(String attributeName, Object id) {
this.attributeName = attributeName;
this.id = id;
}

private final String attributeName;
private final Object id;

public Object getId() {
return id;
}

public String getAttributeName() {
return attributeName;
}

@Override
public Id<T>[] ids() {
return new Id[] {this};
}

@Override
public Map<String, Object> namedValues() {
return Collections.singletonMap( attributeName, id );
}
}

public static class Composite<T> extends Identifier<T> {
Id<T>[] ids;

public Composite(Id<T>[] ids) {
this.ids = ids;
}

public Id<T>[] getValues() {
return ids;
}

@Override
public Id<T>[] ids() {
return ids;
}

@Override
public Map<String, Object> namedValues() {
Map<String, Object> namedValues = new HashMap<>();
for ( Id<T> id : ids ) {
namedValues.put( id.getAttributeName(), id.getId() );
}
return namedValues;
}
}

public static <T, I> Id<T> id(SingularAttribute<T, I> attribute, I id) {
return new Id<>( attribute, id );
}

public static <T> Id<T> id(String attributeName, Object id) {
return new Id<>( attributeName, id );
}

public static <T> Id<T> id(Class<T> entityClass, String attributeName, Object id) {

Check notice

Code scanning / CodeQL

Useless parameter

The parameter 'entityClass' is never used.
return new Id<>( attributeName, id );
}

@SafeVarargs
public static <T> Identifier<T> composite(Id<T>... ids) {
return new Composite<>( ids );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ReactiveEntityInsertActionHolder(ReactiveEntityInsertAction delegate) {
}

@Override
public Serializable[] getPropertySpaces() {
public String[] getPropertySpaces() {
return delegate.getPropertySpaces();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@
import org.hibernate.HibernateException;
import org.hibernate.action.internal.AbstractEntityInsertAction;
import org.hibernate.action.internal.EntityInsertAction;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
import org.hibernate.stat.internal.StatsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;

import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
Expand Down Expand Up @@ -88,7 +84,7 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
postInsert();

final StatisticsImplementor statistics = session.getFactory().getStatistics();
if ( statistics.isStatisticsEnabled() && !veto ) {
if ( statistics.isStatisticsEnabled() ) {
statistics.insertEntity( getPersister().getEntityName() );
}

Expand All @@ -104,28 +100,6 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
}
}

//TODO: copy/paste from superclass (make it protected)
private void putCacheIfNecessary() {
final EntityPersister persister = getPersister();
final SharedSessionContractImplementor session = getSession();
if ( isCachePutEnabled( persister, session ) ) {
final SessionFactoryImplementor factory = session.getFactory();
final CacheEntry ce = persister.buildCacheEntry( getInstance(), getState(), getVersion(), session );
setCacheEntry( persister.getCacheEntryStructure().structure( ce ) );
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey( getId(), persister, factory, session.getTenantIdentifier() );
final boolean put = cacheInsert( persister, ck );

final StatisticsImplementor statistics = factory.getStatistics();
if ( put && statistics.isStatisticsEnabled() ) {
statistics.entityCachePut(
StatsHelper.INSTANCE.getRootEntityRole( persister ),
cache.getRegion().getName()
);
}
}
}

private CompletionStage<Void> processInsertGeneratedProperties(
ReactiveEntityPersister persister,
SharedSessionContractImplementor session,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,15 @@
import java.util.concurrent.CompletionStage;

import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
import org.hibernate.action.internal.EntityUpdateAction;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.engine.ReactiveExecutable;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
import org.hibernate.stat.internal.StatsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.TypeHelper;
Expand Down Expand Up @@ -101,7 +95,7 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
} )
.thenCompose( this::handleGeneratedProperties )
.thenAccept( entry -> {
handleDeleted( entry, persister, instance );
handleDeleted( entry );
updateCacheItem( persister, ck, entry );
handleNaturalIdResolutions( persister, session, id );
postUpdate();
Expand Down Expand Up @@ -142,88 +136,20 @@ private CompletionStage<EntityEntry> handleGeneratedProperties(EntityEntry entry
}

// TODO: copy/paste from superclass (make it protected)
private void handleDeleted(EntityEntry entry, EntityPersister persister, Object instance) {
private void handleDeleted(EntityEntry entry) {
if ( entry.getStatus() == Status.DELETED ) {
final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
final EntityMetamodel entityMetamodel = getPersister().getEntityMetamodel();
final boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned()
&& entityMetamodel.getOptimisticLockStyle().isAllOrDirty();
if ( isImpliedOptimisticLocking && entry.getLoadedState() != null ) {
// The entity will be deleted and because we are going to create a delete statement
// that uses all the state values in the where clause, the entry state needs to be
// updated otherwise the statement execution will not delete any row (see HHH-15218).
entry.postUpdate(instance, getState(), getNextVersion() );
entry.postUpdate( getInstance(), getState(), getNextVersion() );
}
}
}

// TODO: copy/paste from superclass (make it protected)
private void handleNaturalIdResolutions(EntityPersister persister, SharedSessionContractImplementor session, Object id) {
NaturalIdMapping naturalIdMapping = getNaturalIdMapping();
if ( naturalIdMapping != null ) {
session.getPersistenceContextInternal().getNaturalIdResolutions().manageSharedResolution(
id,
naturalIdMapping.extractNaturalIdFromEntityState( getState() ),
getPreviousNaturalIdValues(),
persister,
CachedNaturalIdValueSource.UPDATE
);
}
}

// TODO: copy/paste from superclass (make it protected)
private void updateCacheItem(Object previousVersion, Object ck, EntityEntry entry) {
final EntityPersister persister = getPersister();
if ( persister.canWriteToCache() ) {
final SharedSessionContractImplementor session = getSession();
if ( isCacheInvalidationRequired( persister, session ) || entry.getStatus() != Status.MANAGED ) {
persister.getCacheAccessStrategy().remove( session, ck );
}
else if ( session.getCacheMode().isPutEnabled() ) {
//TODO: inefficient if that cache is just going to ignore the updated state!
final CacheEntry ce = persister.buildCacheEntry( getInstance(), getState(), getNextVersion(), getSession() );
setCacheEntry( persister.getCacheEntryStructure().structure( ce ) );
final boolean put = updateCache( persister, previousVersion, ck );

final StatisticsImplementor statistics = session.getFactory().getStatistics();
if ( put && statistics.isStatisticsEnabled() ) {
statistics.entityCachePut(
StatsHelper.INSTANCE.getRootEntityRole(persister),
getPersister().getCacheAccessStrategy().getRegion().getName()
);
}
}
}
}

private static boolean isCacheInvalidationRequired(
EntityPersister persister,
SharedSessionContractImplementor session) {
// the cache has to be invalidated when CacheMode is equal to GET or IGNORE
return persister.isCacheInvalidationRequired()
|| session.getCacheMode() == CacheMode.GET
|| session.getCacheMode() == CacheMode.IGNORE;
}

// TODO: copy/paste from superclass (make it protected)
private Object lockCacheItem(Object previousVersion) {
final EntityPersister persister = getPersister();
if ( persister.canWriteToCache() ) {
final SharedSessionContractImplementor session = getSession();
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
getId(),
persister,
session.getFactory(),
session.getTenantIdentifier()
);
setLock( cache.lockItem( session, ck, previousVersion ) );
return ck;
}
else {
return null;
}
}

private CompletionStage<Void> processGeneratedProperties(
Object id,
ReactiveEntityPersister persister,
Expand Down
Loading