HHH-8999 : NullPointerException when updating or deleting multiple entities of same type with non-comparable IDs
(cherry picked from commit 6853fdae70
)
This commit is contained in:
parent
52733a2869
commit
cde859c57d
|
@ -13,6 +13,7 @@ import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.VersionType;
|
import org.hibernate.type.VersionType;
|
||||||
|
import org.hibernate.type.descriptor.java.IncomparableComparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard CacheDataDescription implementation.
|
* Standard CacheDataDescription implementation.
|
||||||
|
@ -37,6 +38,12 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
|
||||||
this.mutable = mutable;
|
this.mutable = mutable;
|
||||||
this.versioned = versioned;
|
this.versioned = versioned;
|
||||||
this.versionComparator = versionComparator;
|
this.versionComparator = versionComparator;
|
||||||
|
if ( versioned &&
|
||||||
|
( versionComparator == null || IncomparableComparator.class.isInstance( versionComparator ) ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"versionComparator must not be null or an instance of " + IncomparableComparator.class.getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
this.keyType = keyType;
|
this.keyType = keyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ public interface CacheDataDescription {
|
||||||
/**
|
/**
|
||||||
* Is the data to be cached considered versioned?
|
* Is the data to be cached considered versioned?
|
||||||
*
|
*
|
||||||
* If {@code true}, it is illegal for {@link #getVersionComparator} to return {@code null}.
|
* If {@code true}, it is illegal for {@link #getVersionComparator} to return {@code null}
|
||||||
|
* or an instance of {@link org.hibernate.type.descriptor.java.IncomparableComparator}.
|
||||||
*
|
*
|
||||||
* @return {@code true} if the data is versioned; {@code false} otherwise.
|
* @return {@code true} if the data is versioned; {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.io.ObjectOutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -62,6 +63,9 @@ public class ActionQueue {
|
||||||
|
|
||||||
private UnresolvedEntityInsertActions unresolvedInsertions;
|
private UnresolvedEntityInsertActions unresolvedInsertions;
|
||||||
|
|
||||||
|
// NOTE: ExecutableList fields must be instantiated via ListProvider#init or #getOrInit
|
||||||
|
// to ensure that they are instantiated consistently.
|
||||||
|
|
||||||
// Object insertions, updates, and deletions have list semantics because
|
// Object insertions, updates, and deletions have list semantics because
|
||||||
// they must happen in the right order so as to respect referential
|
// they must happen in the right order so as to respect referential
|
||||||
// integrity
|
// integrity
|
||||||
|
@ -88,84 +92,121 @@ public class ActionQueue {
|
||||||
private BeforeTransactionCompletionProcessQueue beforeTransactionProcesses;
|
private BeforeTransactionCompletionProcessQueue beforeTransactionProcesses;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array containing providers for all the ExecutableLists in execution order
|
* An LinkedHashMap containing providers for all the ExecutableLists, inserted in execution order
|
||||||
*/
|
*/
|
||||||
private static final ListProvider[] EXECUTABLE_LISTS;
|
private static final LinkedHashMap<Class<? extends Executable>,ListProvider> EXECUTABLE_LISTS_MAP;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
EXECUTABLE_LISTS = new ListProvider[8];
|
EXECUTABLE_LISTS_MAP = new LinkedHashMap<Class<? extends Executable>,ListProvider>( 8 );
|
||||||
EXECUTABLE_LISTS[0] = new ListProvider() {
|
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
|
||||||
return instance.orphanRemovals;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
return instance.orphanRemovals = new ExecutableList<OrphanRemovalAction>();
|
OrphanRemovalAction.class,
|
||||||
}
|
new ListProvider<OrphanRemovalAction>() {
|
||||||
};
|
ExecutableList<OrphanRemovalAction> get(ActionQueue instance) {
|
||||||
EXECUTABLE_LISTS[1] = new ListProvider() {
|
return instance.orphanRemovals;
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
}
|
||||||
return instance.insertions;
|
ExecutableList<OrphanRemovalAction> init(ActionQueue instance) {
|
||||||
}
|
// OrphanRemovalAction executables never require sorting.
|
||||||
|
return instance.orphanRemovals = new ExecutableList<OrphanRemovalAction>( false );
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
}
|
||||||
return instance.insertions = new ExecutableList<AbstractEntityInsertAction>( new InsertActionSorter() );
|
}
|
||||||
}
|
);
|
||||||
};
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
EXECUTABLE_LISTS[2] = new ListProvider() {
|
AbstractEntityInsertAction.class,
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
new ListProvider<AbstractEntityInsertAction>() {
|
||||||
return instance.updates;
|
ExecutableList<AbstractEntityInsertAction> get(ActionQueue instance) {
|
||||||
}
|
return instance.insertions;
|
||||||
|
}
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
ExecutableList<AbstractEntityInsertAction> init(ActionQueue instance) {
|
||||||
return instance.updates = new ExecutableList<EntityUpdateAction>();
|
if ( instance.isOrderInsertsEnabled() ) {
|
||||||
}
|
return instance.insertions = new ExecutableList<AbstractEntityInsertAction>(
|
||||||
};
|
new InsertActionSorter()
|
||||||
EXECUTABLE_LISTS[3] = new ListProvider() {
|
);
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
}
|
||||||
return instance.collectionQueuedOps;
|
else {
|
||||||
}
|
return instance.insertions = new ExecutableList<AbstractEntityInsertAction>(
|
||||||
|
false
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
);
|
||||||
return instance.collectionQueuedOps = new ExecutableList<QueuedOperationCollectionAction>();
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
EXECUTABLE_LISTS[4] = new ListProvider() {
|
);
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
return instance.collectionRemovals;
|
EntityUpdateAction.class,
|
||||||
}
|
new ListProvider<EntityUpdateAction>() {
|
||||||
|
ExecutableList<EntityUpdateAction> get(ActionQueue instance) {
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
return instance.updates;
|
||||||
return instance.collectionRemovals = new ExecutableList<CollectionRemoveAction>();
|
}
|
||||||
}
|
ExecutableList<EntityUpdateAction> init(ActionQueue instance) {
|
||||||
};
|
return instance.updates = new ExecutableList<EntityUpdateAction>(
|
||||||
EXECUTABLE_LISTS[5] = new ListProvider() {
|
instance.isOrderUpdatesEnabled()
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
);
|
||||||
return instance.collectionUpdates;
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
return instance.collectionUpdates = new ExecutableList<CollectionUpdateAction>();
|
QueuedOperationCollectionAction.class,
|
||||||
}
|
new ListProvider<QueuedOperationCollectionAction>() {
|
||||||
};
|
ExecutableList<QueuedOperationCollectionAction> get(ActionQueue instance) {
|
||||||
EXECUTABLE_LISTS[6] = new ListProvider() {
|
return instance.collectionQueuedOps;
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
}
|
||||||
return instance.collectionCreations;
|
ExecutableList<QueuedOperationCollectionAction> init(ActionQueue instance) {
|
||||||
}
|
return instance.collectionQueuedOps = new ExecutableList<QueuedOperationCollectionAction>(
|
||||||
|
instance.isOrderUpdatesEnabled()
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
);
|
||||||
return instance.collectionCreations = new ExecutableList<CollectionRecreateAction>();
|
}
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
EXECUTABLE_LISTS[7] = new ListProvider() {
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
ExecutableList<?> get(ActionQueue instance) {
|
CollectionRemoveAction.class,
|
||||||
return instance.deletions;
|
new ListProvider<CollectionRemoveAction>() {
|
||||||
}
|
ExecutableList<CollectionRemoveAction> get(ActionQueue instance) {
|
||||||
|
return instance.collectionRemovals;
|
||||||
ExecutableList<?> init(ActionQueue instance) {
|
}
|
||||||
return instance.deletions = new ExecutableList<EntityDeleteAction>();
|
ExecutableList<CollectionRemoveAction> init(ActionQueue instance) {
|
||||||
}
|
return instance.collectionRemovals = new ExecutableList<CollectionRemoveAction>(
|
||||||
};
|
instance.isOrderUpdatesEnabled()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
|
CollectionUpdateAction.class,
|
||||||
|
new ListProvider<CollectionUpdateAction>() {
|
||||||
|
ExecutableList<CollectionUpdateAction> get(ActionQueue instance) {
|
||||||
|
return instance.collectionUpdates;
|
||||||
|
}
|
||||||
|
ExecutableList<CollectionUpdateAction> init(ActionQueue instance) {
|
||||||
|
return instance.collectionUpdates = new ExecutableList<CollectionUpdateAction>(
|
||||||
|
instance.isOrderUpdatesEnabled()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
|
CollectionRecreateAction.class,
|
||||||
|
new ListProvider<CollectionRecreateAction>() {
|
||||||
|
ExecutableList<CollectionRecreateAction> get(ActionQueue instance) {
|
||||||
|
return instance.collectionCreations;
|
||||||
|
}
|
||||||
|
ExecutableList<CollectionRecreateAction> init(ActionQueue instance) {
|
||||||
|
return instance.collectionCreations = new ExecutableList<CollectionRecreateAction>(
|
||||||
|
instance.isOrderUpdatesEnabled()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
EXECUTABLE_LISTS_MAP.put(
|
||||||
|
EntityDeleteAction.class,
|
||||||
|
new ListProvider<EntityDeleteAction>() {
|
||||||
|
ExecutableList<EntityDeleteAction> get(ActionQueue instance) {
|
||||||
|
return instance.deletions;
|
||||||
|
}
|
||||||
|
ExecutableList<EntityDeleteAction> init(ActionQueue instance) {
|
||||||
|
// EntityDeleteAction executables never require sorting.
|
||||||
|
return instance.deletions = new ExecutableList<EntityDeleteAction>( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,8 +220,8 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
for ( int i = 0; i < EXECUTABLE_LISTS.length; ++i ) {
|
for ( ListProvider listProvider : EXECUTABLE_LISTS_MAP.values() ) {
|
||||||
ExecutableList<?> l = EXECUTABLE_LISTS[i].get(this);
|
ExecutableList<?> l = listProvider.get( this );
|
||||||
if( l != null ) {
|
if( l != null ) {
|
||||||
l.clear();
|
l.clear();
|
||||||
}
|
}
|
||||||
|
@ -233,10 +274,7 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG.trace( "Adding resolved non-early insert action." );
|
LOG.trace( "Adding resolved non-early insert action." );
|
||||||
if( insertions == null ) {
|
addAction( AbstractEntityInsertAction.class, insert );
|
||||||
insertions = new ExecutableList<AbstractEntityInsertAction>( new InsertActionSorter() );
|
|
||||||
}
|
|
||||||
insertions.add(insert);
|
|
||||||
}
|
}
|
||||||
insert.makeEntityManaged();
|
insert.makeEntityManaged();
|
||||||
if( unresolvedInsertions != null ) {
|
if( unresolvedInsertions != null ) {
|
||||||
|
@ -246,6 +284,11 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends Executable & Comparable & Serializable> void addAction(Class<T> executableClass, T action) {
|
||||||
|
EXECUTABLE_LISTS_MAP.get( executableClass ).getOrInit( this ).add( action );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an entity (IDENTITY) insert action
|
* Adds an entity (IDENTITY) insert action
|
||||||
*
|
*
|
||||||
|
@ -262,10 +305,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the entity deletion
|
* @param action The action representing the entity deletion
|
||||||
*/
|
*/
|
||||||
public void addAction(EntityDeleteAction action) {
|
public void addAction(EntityDeleteAction action) {
|
||||||
if( deletions == null ) {
|
addAction( EntityDeleteAction.class, action );
|
||||||
deletions = new ExecutableList<EntityDeleteAction>();
|
|
||||||
}
|
|
||||||
deletions.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -274,10 +314,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the orphan removal
|
* @param action The action representing the orphan removal
|
||||||
*/
|
*/
|
||||||
public void addAction(OrphanRemovalAction action) {
|
public void addAction(OrphanRemovalAction action) {
|
||||||
if( orphanRemovals == null ) {
|
addAction( OrphanRemovalAction.class, action );
|
||||||
orphanRemovals = new ExecutableList<OrphanRemovalAction>();
|
|
||||||
}
|
|
||||||
orphanRemovals.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,10 +323,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the entity update
|
* @param action The action representing the entity update
|
||||||
*/
|
*/
|
||||||
public void addAction(EntityUpdateAction action) {
|
public void addAction(EntityUpdateAction action) {
|
||||||
if( updates == null ) {
|
addAction( EntityUpdateAction.class, action );
|
||||||
updates = new ExecutableList<EntityUpdateAction>();
|
|
||||||
}
|
|
||||||
updates.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -298,10 +332,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the (re)creation of a collection
|
* @param action The action representing the (re)creation of a collection
|
||||||
*/
|
*/
|
||||||
public void addAction(CollectionRecreateAction action) {
|
public void addAction(CollectionRecreateAction action) {
|
||||||
if( collectionCreations == null) {
|
addAction( CollectionRecreateAction.class, action );
|
||||||
collectionCreations = new ExecutableList<CollectionRecreateAction>();
|
|
||||||
}
|
|
||||||
collectionCreations.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -310,10 +341,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the removal of a collection
|
* @param action The action representing the removal of a collection
|
||||||
*/
|
*/
|
||||||
public void addAction(CollectionRemoveAction action) {
|
public void addAction(CollectionRemoveAction action) {
|
||||||
if( collectionRemovals == null ) {
|
addAction( CollectionRemoveAction.class, action );
|
||||||
collectionRemovals = new ExecutableList<CollectionRemoveAction>();
|
|
||||||
}
|
|
||||||
collectionRemovals.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,10 +350,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the update of a collection
|
* @param action The action representing the update of a collection
|
||||||
*/
|
*/
|
||||||
public void addAction(CollectionUpdateAction action) {
|
public void addAction(CollectionUpdateAction action) {
|
||||||
if( collectionUpdates == null ) {
|
addAction( CollectionUpdateAction.class, action );
|
||||||
collectionUpdates = new ExecutableList<CollectionUpdateAction>();
|
|
||||||
}
|
|
||||||
collectionUpdates.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -334,10 +359,7 @@ public class ActionQueue {
|
||||||
* @param action The action representing the queued operation
|
* @param action The action representing the queued operation
|
||||||
*/
|
*/
|
||||||
public void addAction(QueuedOperationCollectionAction action) {
|
public void addAction(QueuedOperationCollectionAction action) {
|
||||||
if( collectionQueuedOps == null) {
|
addAction( QueuedOperationCollectionAction.class, action );
|
||||||
collectionQueuedOps = new ExecutableList<QueuedOperationCollectionAction>();
|
|
||||||
}
|
|
||||||
collectionQueuedOps.add( action );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -428,8 +450,8 @@ public class ActionQueue {
|
||||||
throw new IllegalStateException( "About to execute actions, but there are unresolved entity insert actions." );
|
throw new IllegalStateException( "About to execute actions, but there are unresolved entity insert actions." );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int i = 0; i < EXECUTABLE_LISTS.length; ++i ) {
|
for ( ListProvider listProvider : EXECUTABLE_LISTS_MAP.values() ) {
|
||||||
ExecutableList<?> l = EXECUTABLE_LISTS[i].get(this);
|
ExecutableList<?> l = listProvider.get( this );
|
||||||
if ( l != null && !l.isEmpty() ) {
|
if ( l != null && !l.isEmpty() ) {
|
||||||
executeActions( l );
|
executeActions( l );
|
||||||
}
|
}
|
||||||
|
@ -503,9 +525,9 @@ public class ActionQueue {
|
||||||
if ( tables.isEmpty() ) {
|
if ( tables.isEmpty() ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for ( int i = 0; i < EXECUTABLE_LISTS.length; ++i ) {
|
for ( ListProvider listProvider : EXECUTABLE_LISTS_MAP.values() ) {
|
||||||
ExecutableList<?> l = EXECUTABLE_LISTS[i].get(this);
|
ExecutableList<?> l = listProvider.get( this );
|
||||||
if ( areTablesToBeUpdated(l, tables) ) {
|
if ( areTablesToBeUpdated( l, tables ) ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,7 +730,7 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sortCollectionActions() {
|
public void sortCollectionActions() {
|
||||||
if ( session.getFactory().getSessionFactoryOptions().isOrderUpdatesEnabled() ) {
|
if ( isOrderUpdatesEnabled() ) {
|
||||||
// sort the updates by fk
|
// sort the updates by fk
|
||||||
if( collectionCreations != null ) {
|
if( collectionCreations != null ) {
|
||||||
collectionCreations.sort();
|
collectionCreations.sort();
|
||||||
|
@ -726,15 +748,23 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sortActions() {
|
public void sortActions() {
|
||||||
if ( session.getFactory().getSessionFactoryOptions().isOrderUpdatesEnabled() && updates != null ) {
|
if ( isOrderUpdatesEnabled() && updates != null ) {
|
||||||
// sort the updates by pk
|
// sort the updates by pk
|
||||||
updates.sort();
|
updates.sort();
|
||||||
}
|
}
|
||||||
if ( session.getFactory().getSessionFactoryOptions().isOrderInsertsEnabled() && insertions != null ) {
|
if ( isOrderInsertsEnabled() && insertions != null ) {
|
||||||
insertions.sort();
|
insertions.sort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOrderUpdatesEnabled() {
|
||||||
|
return session.getFactory().getSessionFactoryOptions().isOrderUpdatesEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOrderInsertsEnabled() {
|
||||||
|
return session.getFactory().getSessionFactoryOptions().isOrderInsertsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
public void clearFromFlushNeededCheck(int previousCollectionRemovalSize) {
|
public void clearFromFlushNeededCheck(int previousCollectionRemovalSize) {
|
||||||
if( collectionCreations != null ) {
|
if( collectionCreations != null ) {
|
||||||
collectionCreations.clear();
|
collectionCreations.clear();
|
||||||
|
@ -813,7 +843,7 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
unresolvedInsertions.serialize( oos );
|
unresolvedInsertions.serialize( oos );
|
||||||
|
|
||||||
for ( ListProvider p : EXECUTABLE_LISTS ) {
|
for ( ListProvider p : EXECUTABLE_LISTS_MAP.values() ) {
|
||||||
ExecutableList<?> l = p.get(this);
|
ExecutableList<?> l = p.get(this);
|
||||||
if( l == null ) {
|
if( l == null ) {
|
||||||
oos.writeBoolean(false);
|
oos.writeBoolean(false);
|
||||||
|
@ -843,8 +873,7 @@ public class ActionQueue {
|
||||||
|
|
||||||
rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session );
|
rtn.unresolvedInsertions = UnresolvedEntityInsertActions.deserialize( ois, session );
|
||||||
|
|
||||||
for ( int i = 0; i < EXECUTABLE_LISTS.length; ++i ) {
|
for ( ListProvider provider : EXECUTABLE_LISTS_MAP.values() ) {
|
||||||
ListProvider provider = EXECUTABLE_LISTS[i];
|
|
||||||
ExecutableList<?> l = provider.get(rtn);
|
ExecutableList<?> l = provider.get(rtn);
|
||||||
boolean notNull = ois.readBoolean();
|
boolean notNull = ois.readBoolean();
|
||||||
if( notNull ) {
|
if( notNull ) {
|
||||||
|
@ -1088,8 +1117,15 @@ public class ActionQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static abstract class ListProvider {
|
private static abstract class ListProvider<T extends Executable & Comparable & Serializable> {
|
||||||
abstract ExecutableList<?> get(ActionQueue instance);
|
abstract ExecutableList<T> get(ActionQueue instance);
|
||||||
abstract ExecutableList<?> init(ActionQueue instance);
|
abstract ExecutableList<T> init(ActionQueue instance);
|
||||||
|
ExecutableList<T> getOrInit( ActionQueue instance ) {
|
||||||
|
ExecutableList<T> list = get( instance );
|
||||||
|
if ( list == null ) {
|
||||||
|
list = init( instance );
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
|
||||||
private final ArrayList<E> executables;
|
private final ArrayList<E> executables;
|
||||||
|
|
||||||
private final Sorter<E> sorter;
|
private final Sorter<E> sorter;
|
||||||
|
private final boolean requiresSorting;
|
||||||
private boolean sorted;
|
private boolean sorted;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +78,20 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
|
||||||
* @param initialCapacity The initial capacity for instantiating the internal List
|
* @param initialCapacity The initial capacity for instantiating the internal List
|
||||||
*/
|
*/
|
||||||
public ExecutableList(int initialCapacity) {
|
public ExecutableList(int initialCapacity) {
|
||||||
this( initialCapacity, null );
|
// pass true for requiresSorting argument to maintain original behavior
|
||||||
|
this( initialCapacity, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutableList(boolean requiresSorting) {
|
||||||
|
this( INIT_QUEUE_LIST_SIZE, requiresSorting );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutableList(int initialCapacity, boolean requiresSorting) {
|
||||||
|
this.sorter = null;
|
||||||
|
this.executables = new ArrayList<E>( initialCapacity );
|
||||||
|
this.querySpaces = null;
|
||||||
|
this.requiresSorting = requiresSorting;
|
||||||
|
this.sorted = requiresSorting;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +113,8 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
|
||||||
this.sorter = sorter;
|
this.sorter = sorter;
|
||||||
this.executables = new ArrayList<E>( initialCapacity );
|
this.executables = new ArrayList<E>( initialCapacity );
|
||||||
this.querySpaces = null;
|
this.querySpaces = null;
|
||||||
|
// require sorting by default, even if sorter is null to maintain original behavior
|
||||||
|
this.requiresSorting = true;
|
||||||
this.sorted = true;
|
this.sorted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +178,7 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
|
||||||
public void clear() {
|
public void clear() {
|
||||||
executables.clear();
|
executables.clear();
|
||||||
querySpaces = null;
|
querySpaces = null;
|
||||||
sorted = true;
|
sorted = requiresSorting;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,17 +215,19 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if the addition invalidated the sorting
|
// if it was sorted before the addition, then check if the addition invalidated the sorting
|
||||||
if ( sorter != null ) {
|
if ( sorted ) {
|
||||||
// we don't have intrinsic insight into the sorter's algorithm, so invalidate sorting
|
if ( sorter != null ) {
|
||||||
sorted = false;
|
// we don't have intrinsic insight into the sorter's algorithm, so invalidate sorting
|
||||||
}
|
|
||||||
else {
|
|
||||||
// otherwise, we added to the end of the list. So check the comparison between the incoming
|
|
||||||
// executable and the one previously at the end of the list using the Comparable contract
|
|
||||||
if ( previousLast != null && previousLast.compareTo( executable ) > 0 ) {
|
|
||||||
sorted = false;
|
sorted = false;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// otherwise, we added to the end of the list. So check the comparison between the incoming
|
||||||
|
// executable and the one previously at the end of the list using the Comparable contract
|
||||||
|
if ( previousLast != null && previousLast.compareTo( executable ) > 0 ) {
|
||||||
|
sorted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Serializable[] querySpaces = executable.getPropertySpaces();
|
Serializable[] querySpaces = executable.getPropertySpaces();
|
||||||
|
@ -225,7 +243,8 @@ public class ExecutableList<E extends Executable & Comparable & Serializable> im
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void sort() {
|
public void sort() {
|
||||||
if ( sorted ) {
|
if ( sorted || !requiresSorting ) {
|
||||||
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.io.InputStream;
|
||||||
import java.sql.Blob;
|
import java.sql.Blob;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.jdbc.BinaryStream;
|
import org.hibernate.engine.jdbc.BinaryStream;
|
||||||
|
@ -71,6 +72,12 @@ public class ByteArrayTypeDescriptor extends AbstractTypeDescriptor<Byte[]> {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
public Comparator<Byte[]> getComparator() {
|
||||||
|
return IncomparableComparator.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
@Override
|
@Override
|
||||||
public <X> X unwrap(Byte[] value, Class<X> type, WrapperOptions options) {
|
public <X> X unwrap(Byte[] value, Class<X> type, WrapperOptions options) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.sql.Clob;
|
import java.sql.Clob;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.CharacterStream;
|
import org.hibernate.engine.jdbc.CharacterStream;
|
||||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||||
|
@ -51,6 +52,12 @@ public class CharacterArrayTypeDescriptor extends AbstractTypeDescriptor<Charact
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
public Comparator<Character[]> getComparator() {
|
||||||
|
return IncomparableComparator.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
@Override
|
@Override
|
||||||
public <X> X unwrap(Character[] value, Class<X> type, WrapperOptions options) {
|
public <X> X unwrap(Character[] value, Class<X> type, WrapperOptions options) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.io.InputStream;
|
||||||
import java.sql.Blob;
|
import java.sql.Blob;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.jdbc.BinaryStream;
|
import org.hibernate.engine.jdbc.BinaryStream;
|
||||||
|
@ -72,6 +73,12 @@ public class PrimitiveByteArrayTypeDescriptor extends AbstractTypeDescriptor<byt
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
public Comparator<byte[]> getComparator() {
|
||||||
|
return IncomparableComparator.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public <X> X unwrap(byte[] value, Class<X> type, WrapperOptions options) {
|
public <X> X unwrap(byte[] value, Class<X> type, WrapperOptions options) {
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.sql.Clob;
|
import java.sql.Clob;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.CharacterStream;
|
import org.hibernate.engine.jdbc.CharacterStream;
|
||||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||||
|
@ -51,6 +52,12 @@ public class PrimitiveCharacterArrayTypeDescriptor extends AbstractTypeDescripto
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
public Comparator<char[]> getComparator() {
|
||||||
|
return IncomparableComparator.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public <X> X unwrap(char[] value, Class<X> type, WrapperOptions options) {
|
public <X> X unwrap(char[] value, Class<X> type, WrapperOptions options) {
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
|
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.engine.spi;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
|
||||||
|
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
|
||||||
|
import org.hibernate.action.spi.Executable;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Anton Marsden
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class NonSortedExecutableListTest extends BaseUnitTestCase {
|
||||||
|
|
||||||
|
// For testing, we need an Executable that is also Comparable and Serializable
|
||||||
|
private static class AnExecutable implements Executable, Comparable, Serializable {
|
||||||
|
|
||||||
|
private final int n;
|
||||||
|
private Serializable[] spaces;
|
||||||
|
private transient boolean afterDeserializeCalled;
|
||||||
|
|
||||||
|
public AnExecutable(int n, String... spaces) {
|
||||||
|
this.n = n;
|
||||||
|
this.spaces = spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
return new Integer(n).compareTo( new Integer(( (AnExecutable) o ).n ));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if ( this == obj )
|
||||||
|
return true;
|
||||||
|
if ( obj == null )
|
||||||
|
return false;
|
||||||
|
AnExecutable other = (AnExecutable) obj;
|
||||||
|
return n == other.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable[] getPropertySpaces() {
|
||||||
|
return spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeExecutions() throws HibernateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws HibernateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AfterTransactionCompletionProcess getAfterTransactionCompletionProcess() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BeforeTransactionCompletionProcess getBeforeTransactionCompletionProcess() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterDeserialize(SharedSessionContractImplementor session) {
|
||||||
|
this.afterDeserializeCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.valueOf(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExecutableList<AnExecutable> l;
|
||||||
|
|
||||||
|
private AnExecutable action1 = new AnExecutable( 0, "a" );
|
||||||
|
private AnExecutable action2 = new AnExecutable( 1, "b", "c" );
|
||||||
|
private AnExecutable action3 = new AnExecutable( 2, "b", "d" );
|
||||||
|
private AnExecutable action4 = new AnExecutable( 3 );
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
// false indicates sorting is not required.
|
||||||
|
l = new ExecutableList<AnExecutable>( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
l = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd() {
|
||||||
|
Assert.assertEquals( 0, l.size() );
|
||||||
|
l.add( action1 );
|
||||||
|
Assert.assertEquals( action1, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( 1, l.size() );
|
||||||
|
l.add( action2 );
|
||||||
|
Assert.assertEquals( action2, l.get( 1 ) );
|
||||||
|
l.add( action3 );
|
||||||
|
Assert.assertEquals( action3, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( 3, l.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClear() {
|
||||||
|
Assert.assertTrue( l.isEmpty() );
|
||||||
|
l.add( action1 );
|
||||||
|
Assert.assertFalse( l.isEmpty() );
|
||||||
|
l.add( action2 );
|
||||||
|
l.clear();
|
||||||
|
Assert.assertTrue( l.isEmpty() );
|
||||||
|
Assert.assertEquals( 0, l.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIterator() {
|
||||||
|
l.add( action1 );
|
||||||
|
l.add( action2 );
|
||||||
|
l.add( action3 );
|
||||||
|
Iterator<AnExecutable> iterator = l.iterator();
|
||||||
|
Assert.assertEquals(action1, iterator.next());
|
||||||
|
Assert.assertEquals(action2, iterator.next());
|
||||||
|
Assert.assertEquals(action3, iterator.next());
|
||||||
|
Assert.assertFalse(iterator.hasNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveLastN() {
|
||||||
|
l.add( action1 );
|
||||||
|
l.add( action2 );
|
||||||
|
l.add( action3 );
|
||||||
|
l.removeLastN( 0 );
|
||||||
|
Assert.assertEquals( 3, l.size() );
|
||||||
|
l.removeLastN( 2 );
|
||||||
|
Assert.assertEquals( 1, l.size() );
|
||||||
|
Assert.assertEquals( action1, l.get( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSpaces() {
|
||||||
|
l.add( action1 );
|
||||||
|
Set<Serializable> ss = l.getQuerySpaces();
|
||||||
|
Assert.assertEquals( 1, ss.size() );
|
||||||
|
Assert.assertTrue( ss.contains( "a" ) );
|
||||||
|
l.add( action2 );
|
||||||
|
l.add( action3 );
|
||||||
|
l.add( action4 );
|
||||||
|
Set<Serializable> ss2 = l.getQuerySpaces();
|
||||||
|
Assert.assertEquals( 4, ss2.size() );
|
||||||
|
Assert.assertTrue( ss2.contains( "a" ) );
|
||||||
|
Assert.assertTrue( ss2.contains( "b" ) );
|
||||||
|
Assert.assertTrue( ss2.contains( "c" ) );
|
||||||
|
Assert.assertTrue( ss2.contains( "d" ) );
|
||||||
|
Assert.assertTrue( ss == ss2 ); // same Set (cached)
|
||||||
|
// now remove action4
|
||||||
|
l.remove( 3 );
|
||||||
|
ss2 = l.getQuerySpaces();
|
||||||
|
Assert.assertTrue( ss == ss2 ); // same Set (action4 has no spaces)
|
||||||
|
Assert.assertEquals( 4, ss2.size() );
|
||||||
|
l.remove( 2 );
|
||||||
|
ss2 = l.getQuerySpaces();
|
||||||
|
Assert.assertTrue( ss != ss2 ); // Different Set because it has been rebuilt. This would be incorrect if
|
||||||
|
// Set.clear() was used
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSort() {
|
||||||
|
l.add( action4 );
|
||||||
|
l.add( action3 );
|
||||||
|
l.add( action2 );
|
||||||
|
l.add( action1 );
|
||||||
|
// sort should have no affect
|
||||||
|
l.sort();
|
||||||
|
Assert.assertEquals( action4, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( action3, l.get( 1 ) );
|
||||||
|
Assert.assertEquals( action2, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( action1, l.get( 3 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializeDeserialize() throws IOException, ClassNotFoundException {
|
||||||
|
l.add( action4 );
|
||||||
|
l.add( action3 );
|
||||||
|
l.add( action2 );
|
||||||
|
l.add( action1 );
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream( baos );
|
||||||
|
l.writeExternal( oos );
|
||||||
|
// this OOS stream needs to be flushed...
|
||||||
|
oos.flush();
|
||||||
|
ByteArrayInputStream bin = new ByteArrayInputStream( baos.toByteArray() );
|
||||||
|
ObjectInputStream ois = new ObjectInputStream( bin );
|
||||||
|
l = new ExecutableList<NonSortedExecutableListTest.AnExecutable>( false );
|
||||||
|
l.readExternal( ois );
|
||||||
|
|
||||||
|
Assert.assertEquals( 4, l.size() );
|
||||||
|
Assert.assertEquals( action4, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( action3, l.get( 1 ) );
|
||||||
|
Assert.assertEquals( action2, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( action1, l.get( 3 ) );
|
||||||
|
|
||||||
|
Assert.assertFalse( l.get( 0 ).afterDeserializeCalled );
|
||||||
|
Assert.assertFalse( l.get( 1 ).afterDeserializeCalled );
|
||||||
|
Assert.assertFalse( l.get( 2 ).afterDeserializeCalled );
|
||||||
|
Assert.assertFalse( l.get( 3 ).afterDeserializeCalled );
|
||||||
|
|
||||||
|
l.afterDeserialize( null );
|
||||||
|
|
||||||
|
Assert.assertTrue( l.get( 0 ).afterDeserializeCalled );
|
||||||
|
Assert.assertTrue( l.get( 1 ).afterDeserializeCalled );
|
||||||
|
Assert.assertTrue( l.get( 2 ).afterDeserializeCalled );
|
||||||
|
Assert.assertTrue( l.get( 3 ).afterDeserializeCalled );
|
||||||
|
|
||||||
|
Assert.assertEquals( action4, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( action3, l.get( 1 ) );
|
||||||
|
Assert.assertEquals( action2, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( action1, l.get( 3 ) );
|
||||||
|
|
||||||
|
// sort after deserializing; it should still have no affect
|
||||||
|
l.sort();
|
||||||
|
Assert.assertEquals( action4, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( action3, l.get( 1 ) );
|
||||||
|
Assert.assertEquals( action2, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( action1, l.get( 3 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.junit.Test;
|
||||||
/**
|
/**
|
||||||
* @author Anton Marsden
|
* @author Anton Marsden
|
||||||
*/
|
*/
|
||||||
public class ExecutableListTest extends BaseUnitTestCase {
|
public class SortedExecutableListTest extends BaseUnitTestCase {
|
||||||
|
|
||||||
// For testing, we need an Executable that is also Comparable and Serializable
|
// For testing, we need an Executable that is also Comparable and Serializable
|
||||||
private static class AnExecutable implements Executable, Comparable, Serializable {
|
private static class AnExecutable implements Executable, Comparable, Serializable {
|
||||||
|
@ -214,7 +214,7 @@ public class ExecutableListTest extends BaseUnitTestCase {
|
||||||
oos.flush();
|
oos.flush();
|
||||||
ByteArrayInputStream bin = new ByteArrayInputStream( baos.toByteArray() );
|
ByteArrayInputStream bin = new ByteArrayInputStream( baos.toByteArray() );
|
||||||
ObjectInputStream ois = new ObjectInputStream( bin );
|
ObjectInputStream ois = new ObjectInputStream( bin );
|
||||||
l = new ExecutableList<ExecutableListTest.AnExecutable>();
|
l = new ExecutableList<SortedExecutableListTest.AnExecutable>();
|
||||||
l.readExternal( ois );
|
l.readExternal( ois );
|
||||||
|
|
||||||
Assert.assertEquals( 4, l.size() );
|
Assert.assertEquals( 4, l.size() );
|
||||||
|
@ -226,15 +226,26 @@ public class ExecutableListTest extends BaseUnitTestCase {
|
||||||
Assert.assertFalse(l.get(0).afterDeserializeCalled);
|
Assert.assertFalse(l.get(0).afterDeserializeCalled);
|
||||||
Assert.assertFalse(l.get(1).afterDeserializeCalled);
|
Assert.assertFalse(l.get(1).afterDeserializeCalled);
|
||||||
Assert.assertFalse(l.get(2).afterDeserializeCalled);
|
Assert.assertFalse(l.get(2).afterDeserializeCalled);
|
||||||
Assert.assertFalse(l.get(3).afterDeserializeCalled);
|
Assert.assertFalse( l.get( 3 ).afterDeserializeCalled );
|
||||||
|
|
||||||
l.afterDeserialize( null );
|
l.afterDeserialize( null );
|
||||||
|
|
||||||
Assert.assertTrue(l.get(0).afterDeserializeCalled);
|
Assert.assertTrue( l.get( 0 ).afterDeserializeCalled );
|
||||||
Assert.assertTrue(l.get(1).afterDeserializeCalled);
|
Assert.assertTrue( l.get( 1 ).afterDeserializeCalled );
|
||||||
Assert.assertTrue(l.get(2).afterDeserializeCalled);
|
Assert.assertTrue( l.get( 2 ).afterDeserializeCalled );
|
||||||
Assert.assertTrue(l.get(3).afterDeserializeCalled);
|
Assert.assertTrue( l.get( 3 ).afterDeserializeCalled );
|
||||||
|
|
||||||
|
Assert.assertEquals( action4, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( action3, l.get( 1 ) );
|
||||||
|
Assert.assertEquals( action2, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( action1, l.get( 3 ) );
|
||||||
|
|
||||||
|
// sort after deserializing
|
||||||
|
l.sort();
|
||||||
|
Assert.assertEquals( action1, l.get( 0 ) );
|
||||||
|
Assert.assertEquals( action2, l.get( 1 ) );
|
||||||
|
Assert.assertEquals( action3, l.get( 2 ) );
|
||||||
|
Assert.assertEquals( action4, l.get( 3 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ public class ByteArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleDeletions() {
|
public void testMultipleDeletions() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
@ -94,7 +92,6 @@ public class ByteArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleUpdates() {
|
public void testMultipleUpdates() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ public class CharacterArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleDeletions() {
|
public void testMultipleDeletions() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
@ -94,7 +92,6 @@ public class CharacterArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleUpdates() {
|
public void testMultipleUpdates() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ public class PrimitiveByteArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleDeletions() {
|
public void testMultipleDeletions() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
@ -94,7 +92,6 @@ public class PrimitiveByteArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleUpdates() {
|
public void testMultipleUpdates() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ public class PrimitiveCharacterArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleDeletions() {
|
public void testMultipleDeletions() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
@ -94,7 +92,6 @@ public class PrimitiveCharacterArrayIdTest extends BaseCoreFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testMultipleUpdates() {
|
public void testMultipleUpdates() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.getTransaction().begin();
|
s.getTransaction().begin();
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.hibernate.Session;
|
||||||
import org.hibernate.annotations.Type;
|
import org.hibernate.annotations.Type;
|
||||||
import org.hibernate.annotations.TypeDef;
|
import org.hibernate.annotations.TypeDef;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
import org.hibernate.type.LongType;
|
import org.hibernate.type.LongType;
|
||||||
|
@ -34,7 +33,6 @@ public class UserTypeNonComparableIdTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-8999")
|
@TestForIssue(jiraKey = "HHH-8999")
|
||||||
@FailureExpected(jiraKey = "HHH-8999")
|
|
||||||
public void testUserTypeId() {
|
public void testUserTypeId() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
|
|
Loading…
Reference in New Issue