fix the typing in ReplicationMode

and improve readability in DefaultReplicateEventListener

even though they are deprecated

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-08-30 14:42:38 +02:00
parent e351a00c19
commit 8aa37a9d85
2 changed files with 55 additions and 66 deletions

View File

@ -25,10 +25,9 @@ public enum ReplicationMode {
*/
EXCEPTION {
@Override
public boolean shouldOverwriteCurrentVersion(
Object entity,
Object currentVersion, Object newVersion,
BasicType<Object> versionType) {
public <T> boolean shouldOverwriteCurrentVersion(
T currentVersion, T newVersion,
BasicType<T> versionType) {
throw new AssertionFailure( "should not be called" );
}
},
@ -37,10 +36,9 @@ public enum ReplicationMode {
*/
IGNORE {
@Override
public boolean shouldOverwriteCurrentVersion(
Object entity,
Object currentVersion, Object newVersion,
BasicType<Object> versionType) {
public <T> boolean shouldOverwriteCurrentVersion(
T currentVersion, T newVersion,
BasicType<T> versionType) {
return false;
}
},
@ -49,10 +47,9 @@ public enum ReplicationMode {
*/
OVERWRITE {
@Override
public boolean shouldOverwriteCurrentVersion(
Object entity,
Object currentVersion, Object newVersion,
BasicType<Object> versionType) {
public <T> boolean shouldOverwriteCurrentVersion(
T currentVersion, T newVersion,
BasicType<T> versionType) {
return true;
}
},
@ -61,10 +58,9 @@ public enum ReplicationMode {
*/
LATEST_VERSION {
@Override
public boolean shouldOverwriteCurrentVersion(
Object entity,
Object currentVersion, Object newVersion,
BasicType<Object> versionType) {
public <T> boolean shouldOverwriteCurrentVersion(
T currentVersion, T newVersion,
BasicType<T> versionType) {
// always overwrite non-versioned data (because we don't know which is newer)
return versionType == null
|| versionType.getJavaTypeDescriptor().getComparator()
@ -82,9 +78,7 @@ public enum ReplicationMode {
*
* @return {@code true} indicates the data should be overwritten; {@code false} indicates it should not.
*/
public abstract boolean shouldOverwriteCurrentVersion(
Object entity,
Object currentVersion, Object newVersion,
BasicType<Object> versionType);
public abstract <T> boolean shouldOverwriteCurrentVersion(
T currentVersion, T newVersion,
BasicType<T> versionType);
}

View File

@ -24,10 +24,11 @@ import org.hibernate.event.spi.ReplicateEventListener;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.BasicType;
import org.hibernate.type.Type;
import static org.hibernate.pretty.MessageHelper.infoString;
/**
* Defines the default replicate event listener used by Hibernate to replicate
* entities in response to generated replicate events.
@ -55,79 +56,72 @@ public class DefaultReplicateEventListener
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
if ( persistenceContext.reassociateIfUninitializedProxy( event.getObject() ) ) {
LOG.trace( "Uninitialized proxy passed to replicate()" );
return;
}
Object entity = persistenceContext.unproxyAndReassociate( event.getObject() );
if ( persistenceContext.isEntryFor( entity ) ) {
LOG.trace( "Ignoring persistent instance passed to replicate()" );
//hum ... should we cascade anyway? throw an exception? fine like it is?
return;
else {
final Object entity = persistenceContext.unproxyAndReassociate( event.getObject() );
if ( persistenceContext.isEntryFor( entity ) ) {
LOG.trace( "Ignoring persistent instance passed to replicate()" );
//hum ... should we cascade anyway? throw an exception? fine like it is?
}
else {
doReplicate( event, source, entity );
}
}
}
EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
private void doReplicate(ReplicateEvent event, EventSource source, Object entity) {
final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity);
final ReplicationMode replicationMode = event.getReplicationMode();
// get the id from the object
/*if ( persister.isUnsaved(entity, source) ) {
throw new TransientObjectException("transient instance passed to replicate()");
}*/
Object id = persister.getIdentifier( entity, source );
// get the id from the object - we accept almost anything at all,
// except null (that is, even ids which look like they're unsaved)
final Object id = persister.getIdentifier( entity, source );
if ( id == null ) {
throw new TransientObjectException( "instance with null id passed to replicate()" );
}
final ReplicationMode replicationMode = event.getReplicationMode();
final Object oldVersion = replicationMode == ReplicationMode.EXCEPTION
? null //always do an INSERT, and let it fail by constraint violation
: persister.getCurrentVersion(id, source); //what is the version on the database?
? null // always do an INSERT, and let it fail by constraint violation
: persister.getCurrentVersion( id, source); // what is the version on the database?
if ( oldVersion != null ) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"Found existing row for {0}",
MessageHelper.infoString( persister, id, event.getFactory() )
);
LOG.tracev("Found existing row for {0}",
infoString( persister, id, event.getFactory() ) );
}
@SuppressWarnings("unchecked")
final BasicType<Object> versionType = (BasicType<Object>) persister.getVersionType();
final Object realOldVersion = persister.isVersioned() ? oldVersion : null; /// HHH-2378
boolean canReplicate = replicationMode.shouldOverwriteCurrentVersion(
entity,
realOldVersion,
persister.getVersion( entity ),
versionType
);
// if can replicate, will result in a SQL UPDATE
// else do nothing (don't even re-associate object!)
if ( canReplicate ) {
// If the entity has no version, getCurrentVersion() just returns
// a meaningless value to indicate that the row exists (HHH-2378)
final Object realOldVersion = persister.isVersioned() ? oldVersion : null;
if ( shouldOverwrite( replicationMode,
persister.getVersion( entity ), realOldVersion,
persister.getVersionType() ) ) {
// execute a SQL UPDATE
performReplication( entity, id, realOldVersion, persister, replicationMode, source );
}
else if ( LOG.isTraceEnabled() ) {
// do nothing (don't even re-associate object!)
LOG.trace( "No need to replicate" );
}
//TODO: would it be better to do a refresh from db?
}
else {
// no existing row - do an insert
// no existing row - execute a SQL INSERT
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"No existing row, replicating new instance {0}",
MessageHelper.infoString( persister, id, event.getFactory() )
);
LOG.tracev( "No existing row, replicating new instance {0}",
infoString( persister, id, event.getFactory() ) );
}
final boolean regenerate = persister.isIdentifierAssignedByInsert(); // prefer re-generation of identity!
final EntityKey key = regenerate ? null : source.generateEntityKey( id, persister );
performSaveOrReplicate( entity, key, persister, regenerate, replicationMode, source, false );
}
}
private static <T> boolean shouldOverwrite(
ReplicationMode replicationMode, Object entityVersion, Object realOldVersion, BasicType<T> versionType) {
return replicationMode.shouldOverwriteCurrentVersion( (T) realOldVersion, (T) entityVersion, versionType );
}
@Override
protected boolean visitCollectionsBeforeSave(
Object entity,
@ -165,7 +159,8 @@ public class DefaultReplicateEventListener
EventSource source) throws HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Replicating changes to {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
LOG.tracev( "Replicating changes to {0}",
infoString( persister, id, source.getFactory() ) );
}
new OnReplicateVisitor( source, id, entity, true ).process( entity, persister );