HHH-16515 - Add o.h.engine.spi to nullness checking

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2023-08-08 23:46:35 +02:00 committed by Christian Beikov
parent f84c2b56db
commit 7ff76bf6eb
30 changed files with 252 additions and 164 deletions

View File

@ -8,7 +8,18 @@ public final class Method extends Executable {
void invoke(@Nullable Object obj, @Nullable Object @Nullable ... args); void invoke(@Nullable Object obj, @Nullable Object @Nullable ... args);
} }
public final public final class Field extends AccessibleObject implements Member {
class Field extends AccessibleObject implements Member {
public void set(Object obj, @Nullable Object value); public void set(Object obj, @Nullable Object value);
} }
package java.util;
public interface Queue<E> extends Collection<E> {
@Override
@EnsuresNonNullIf(expression="poll()", result=false)
@EnsuresNonNullIf(expression="peek()", result=false)
boolean isEmpty();
E poll();
E peek();
}

View File

@ -7,3 +7,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public interface BasicLogger { public interface BasicLogger {
void tracef(String format, @Nullable Object param1, @Nullable Object param2); void tracef(String format, @Nullable Object param1, @Nullable Object param2);
} }
public interface Logger {
void tracev(String format, @Nullable Object param1);
}

View File

@ -487,7 +487,7 @@ checkerFramework {
extraJavacArgs = [ extraJavacArgs = [
'-AsuppressWarnings=initialization', '-AsuppressWarnings=initialization',
// stubs is passed directly through options.compilerArgumentProviders // stubs is passed directly through options.compilerArgumentProviders
'-AonlyDefs=^org\\.hibernate\\.(jdbc|exception|integrator|jpamodelgen|service|spi|pretty|property\\.access|stat|engine\\.(config|jndi|profile|transaction)|(action|context|bytecode)\\.spi)\\.' '-AonlyDefs=^org\\.hibernate\\.(jdbc|exception|integrator|jpamodelgen|service|spi|pretty|property\\.access|stat|engine\\.(config|jndi|profile|spi|transaction)|(action|context|bytecode)\\.spi)\\.'
] ]
} }

View File

@ -19,6 +19,8 @@ import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.mutation.InsertRowsCoordinator; import org.hibernate.persister.collection.mutation.InsertRowsCoordinator;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Persistent collections are treated as value objects by Hibernate. * Persistent collections are treated as value objects by Hibernate.
* They have no independent existence beyond the entity holding a * They have no independent existence beyond the entity holding a
@ -82,7 +84,7 @@ public interface PersistentCollection<E> extends LazyInitializable {
* @param role The collection role * @param role The collection role
* @param snapshot The snapshot state * @param snapshot The snapshot state
*/ */
void setSnapshot(Object key, String role, Serializable snapshot); void setSnapshot(@Nullable Object key, @Nullable String role, @Nullable Serializable snapshot);
/** /**
* After flushing, clear any "queued" additions, since the * After flushing, clear any "queued" additions, since the

View File

@ -10,6 +10,8 @@ import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.AppliedGraph; import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Encapsulates a JPA EntityGraph provided through a JPQL query hint. Converts the fetches into a list of AST * Encapsulates a JPA EntityGraph provided through a JPQL query hint. Converts the fetches into a list of AST
* FromElements. The logic is kept here as much as possible in order to make it easy to remove this in the future, * FromElements. The logic is kept here as much as possible in order to make it easy to remove this in the future,
@ -28,12 +30,12 @@ public class EntityGraphQueryHint implements AppliedGraph {
} }
@Override @Override
public GraphSemantic getSemantic() { public @Nullable GraphSemantic getSemantic() {
return delegate.getSemantic(); return delegate.getSemantic();
} }
@Override @Override
public RootGraphImplementor<?> getGraph() { public @Nullable RootGraphImplementor<?> getGraph() {
return delegate.getGraph(); return delegate.getGraph();
} }
} }

View File

@ -46,7 +46,6 @@ import org.hibernate.engine.internal.NonNullableTransientDependencies;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
@ -57,6 +56,8 @@ import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/** /**
@ -511,7 +512,7 @@ public class ActionQueue {
prepareActions( collectionQueuedOps ); prepareActions( collectionQueuedOps );
} }
private void prepareActions(ExecutableList<?> queue) throws HibernateException { private void prepareActions(@Nullable ExecutableList<?> queue) throws HibernateException {
if ( queue == null ) { if ( queue == null ) {
return; return;
} }
@ -583,7 +584,7 @@ public class ActionQueue {
return areTablesToBeUpdated( unresolvedInsertions, tables ); return areTablesToBeUpdated( unresolvedInsertions, tables );
} }
private static boolean areTablesToBeUpdated(ExecutableList<?> actions, Set<? extends Serializable> tableSpaces) { private static boolean areTablesToBeUpdated(@Nullable ExecutableList<?> actions, Set<? extends Serializable> tableSpaces) {
if ( actions == null || actions.isEmpty() ) { if ( actions == null || actions.isEmpty() ) {
return false; return false;
} }
@ -617,7 +618,7 @@ public class ActionQueue {
* @param list The list of Executable elements to be performed * @param list The list of Executable elements to be performed
* *
*/ */
private <E extends ComparableExecutable> void executeActions(ExecutableList<E> list) private <E extends ComparableExecutable> void executeActions(@Nullable ExecutableList<E> list)
throws HibernateException { throws HibernateException {
if ( list == null || list.isEmpty() ) { if ( list == null || list.isEmpty() ) {
return; return;
@ -651,8 +652,10 @@ public class ActionQueue {
// Strictly speaking, only a subset of the list may have been processed if a RuntimeException occurs. // Strictly speaking, only a subset of the list may have been processed if a RuntimeException occurs.
// We still invalidate all spaces. I don't see this as a big deal - after all, RuntimeExceptions are // We still invalidate all spaces. I don't see this as a big deal - after all, RuntimeExceptions are
// unexpected. // unexpected.
invalidateSpaces( list.getQuerySpaces().toArray(StringHelper.EMPTY_STRINGS) ); invalidateSpaces( list.getQuerySpaces().toArray(new String[0]) );
} }
// @NonNull String @Nullable [] - array nullable, elements not
// @Nullable String @NonNull [] - elements nullable, array not
} }
list.clear(); list.clear();
@ -676,7 +679,7 @@ public class ActionQueue {
* *
* @param spaces The spaces to invalidate * @param spaces The spaces to invalidate
*/ */
private void invalidateSpaces(String[] spaces) { private void invalidateSpaces(String @Nullable [] spaces) {
if ( spaces != null && spaces.length > 0 ) { if ( spaces != null && spaces.length > 0 ) {
for ( String space : spaces ) { for ( String space : spaces ) {
if ( afterTransactionProcesses == null ) { if ( afterTransactionProcesses == null ) {
@ -708,7 +711,7 @@ public class ActionQueue {
+ "]"; + "]";
} }
private static String toString(ExecutableList<?> q) { private static String toString(@Nullable ExecutableList<?> q) {
return q == null ? "ExecutableList{size=0}" : q.toString(); return q == null ? "ExecutableList{size=0}" : q.toString();
} }
@ -858,7 +861,7 @@ public class ActionQueue {
|| nonempty( collectionCreations ); || nonempty( collectionCreations );
} }
private boolean nonempty(ExecutableList<?> list) { private boolean nonempty(@Nullable ExecutableList<?> list) {
return list != null && !list.isEmpty(); return list != null && !list.isEmpty();
} }
@ -984,7 +987,7 @@ public class ActionQueue {
this.session = session; this.session = session;
} }
public void register(T process) { public void register(@Nullable T process) {
if ( process != null ) { if ( process != null ) {
processes.add( process ); processes.add( process );
} }
@ -1051,7 +1054,7 @@ public class ActionQueue {
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) { if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
session.getFactory().getCache().getTimestampsCache().invalidate( session.getFactory().getCache().getTimestampsCache().invalidate(
querySpacesToInvalidate.toArray(StringHelper.EMPTY_STRINGS), querySpacesToInvalidate.toArray(new String[0]),
session session
); );
} }
@ -1149,7 +1152,7 @@ public class ActionQueue {
} }
} }
private void addDirectDependency(Type type, Object value, IdentityHashMap<Object, InsertInfo> insertInfosByEntity) { private void addDirectDependency(Type type, @Nullable Object value, IdentityHashMap<Object, InsertInfo> insertInfosByEntity) {
if ( type.isEntityType() && value != null ) { if ( type.isEntityType() && value != null ) {
final EntityType entityType = (EntityType) type; final EntityType entityType = (EntityType) type;
final InsertInfo insertInfo = insertInfosByEntity.get( value ); final InsertInfo insertInfo = insertInfosByEntity.get( value );
@ -1209,7 +1212,7 @@ public class ActionQueue {
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(@Nullable Object o) {
if ( this == o ) { if ( this == o ) {
return true; return true;
} }
@ -1305,7 +1308,7 @@ public class ActionQueue {
} }
} }
private int schedule(InsertInfo[] insertInfos, List<InsertInfo> insertInfosToSchedule, int schedulePosition) { private int schedule(InsertInfo [] insertInfos, List<InsertInfo> insertInfosToSchedule, int schedulePosition) {
final InsertInfo[] newInsertInfos = new InsertInfo[insertInfos.length]; final InsertInfo[] newInsertInfos = new InsertInfo[insertInfos.length];
// The bitset is there to quickly query if an index is already scheduled // The bitset is there to quickly query if an index is already scheduled
final BitSet bitSet = new BitSet(insertInfos.length); final BitSet bitSet = new BitSet(insertInfos.length);

View File

@ -8,6 +8,8 @@ package org.hibernate.engine.spi;
import java.io.Serializable; import java.io.Serializable;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Identifies a named association belonging to a particular * Identifies a named association belonging to a particular
* entity instance. Used to record the fact that an association * entity instance. Used to record the fact that an association
@ -31,7 +33,7 @@ public final class AssociationKey implements Serializable {
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(@Nullable Object o) {
if ( this == o ) { if ( this == o ) {
return true; return true;
} }

View File

@ -26,6 +26,9 @@ import org.hibernate.persister.entity.EntityPersister;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Keeps track of:<ul> * Keeps track of:<ul>
* <li>entity and collection keys that are available for batch fetching</li> * <li>entity and collection keys that are available for batch fetching</li>
@ -45,7 +48,7 @@ public class BatchFetchQueue {
* A map of {@link SubselectFetch subselect-fetch descriptors} keyed by the * A map of {@link SubselectFetch subselect-fetch descriptors} keyed by the
* {@link EntityKey} against which the descriptor is registered. * {@link EntityKey} against which the descriptor is registered.
*/ */
private Map<EntityKey, SubselectFetch> subselectsByEntityKey; private @Nullable Map<EntityKey, SubselectFetch> subselectsByEntityKey;
/** /**
* Used to hold information about the entities that are currently eligible for batch-fetching. Ultimately * Used to hold information about the entities that are currently eligible for batch-fetching. Ultimately
@ -54,13 +57,13 @@ public class BatchFetchQueue {
* A Map structure is used to segment the keys by entity type since loading can only be done for a particular entity * A Map structure is used to segment the keys by entity type since loading can only be done for a particular entity
* type at a time. * type at a time.
*/ */
private Map <String,LinkedHashSet<EntityKey>> batchLoadableEntityKeys; private @Nullable Map <String,LinkedHashSet<EntityKey>> batchLoadableEntityKeys;
/** /**
* Used to hold information about the collections that are currently eligible for batch-fetching. Ultimately * Used to hold information about the collections that are currently eligible for batch-fetching. Ultimately
* used by {@link #getCollectionBatch} to build collection load batches. * used by {@link #getCollectionBatch} to build collection load batches.
*/ */
private Map<String, LinkedHashMap<CollectionEntry, PersistentCollection<?>>> batchLoadableCollections; private @Nullable Map<String, LinkedHashMap<CollectionEntry, PersistentCollection<?>>> batchLoadableCollections;
/** /**
* Constructs a queue for the given context. * Constructs a queue for the given context.
@ -92,7 +95,7 @@ public class BatchFetchQueue {
* @return The fetch descriptor; may return null if no subselect fetch queued for * @return The fetch descriptor; may return null if no subselect fetch queued for
* this entity key. * this entity key.
*/ */
public SubselectFetch getSubselect(EntityKey key) { public @Nullable SubselectFetch getSubselect(EntityKey key) {
if ( subselectsByEntityKey == null ) { if ( subselectsByEntityKey == null ) {
return null; return null;
} }
@ -165,8 +168,8 @@ public class BatchFetchQueue {
* if necessary * if necessary
*/ */
public void removeBatchLoadableEntityKey(EntityKey key) { public void removeBatchLoadableEntityKey(EntityKey key) {
if ( batchLoadableEntityKeys != null if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() )
&& key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) { && batchLoadableEntityKeys != null ) {
final LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() ); final LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
if ( set != null ) { if ( set != null ) {
set.remove( key ); set.remove( key );
@ -178,8 +181,7 @@ public class BatchFetchQueue {
* Intended for test usage. Really has no use-case in Hibernate proper. * Intended for test usage. Really has no use-case in Hibernate proper.
*/ */
public boolean containsEntityKey(EntityKey key) { public boolean containsEntityKey(EntityKey key) {
if ( batchLoadableEntityKeys != null if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) && batchLoadableEntityKeys != null ) {
&& key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) {
LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() ); LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
if ( set != null ) { if ( set != null ) {
return set.contains( key ); return set.contains( key );
@ -197,7 +199,7 @@ public class BatchFetchQueue {
public <T> void collectBatchLoadableEntityIds( public <T> void collectBatchLoadableEntityIds(
final int domainBatchSize, final int domainBatchSize,
IndexedConsumer<T> collector, IndexedConsumer<T> collector,
final T loadingId, final @NonNull T loadingId,
final EntityMappingType entityDescriptor) { final EntityMappingType entityDescriptor) {
// make sure we load the id being loaded in the batch! // make sure we load the id being loaded in the batch!
collector.accept( 0, loadingId ); collector.accept( 0, loadingId );
@ -248,7 +250,7 @@ public class BatchFetchQueue {
* complex algorithm that tries to grab keys registered immediately after * complex algorithm that tries to grab keys registered immediately after
* the given key. * the given key.
*/ */
public Object[] getBatchLoadableEntityIds( public Object [] getBatchLoadableEntityIds(
final EntityMappingType entityDescriptor, final EntityMappingType entityDescriptor,
final Object loadingId, final Object loadingId,
final int maxBatchSize) { final int maxBatchSize) {
@ -328,6 +330,7 @@ public class BatchFetchQueue {
batchLoadableCollections = CollectionHelper.mapOfSize( 12 ); batchLoadableCollections = CollectionHelper.mapOfSize( 12 );
} }
assert persister != null : "@AssumeAssertion(nullness)";
final LinkedHashMap<CollectionEntry, PersistentCollection<?>> map = final LinkedHashMap<CollectionEntry, PersistentCollection<?>> map =
batchLoadableCollections.computeIfAbsent( batchLoadableCollections.computeIfAbsent(
persister.getRole(), persister.getRole(),
@ -343,11 +346,13 @@ public class BatchFetchQueue {
* if necessary * if necessary
*/ */
public void removeBatchLoadableCollection(CollectionEntry ce) { public void removeBatchLoadableCollection(CollectionEntry ce) {
final CollectionPersister persister = ce.getLoadedPersister();
if ( batchLoadableCollections == null ) { if ( batchLoadableCollections == null ) {
return; return;
} }
assert persister != null : "@AssumeAssertion(nullness)";
LinkedHashMap<CollectionEntry, PersistentCollection<?>> map = LinkedHashMap<CollectionEntry, PersistentCollection<?>> map =
batchLoadableCollections.get( ce.getLoadedPersister().getRole() ); batchLoadableCollections.get( persister.getRole() );
if ( map != null ) { if ( map != null ) {
map.remove( ce ); map.remove( ce );
} }
@ -363,7 +368,7 @@ public class BatchFetchQueue {
public <T> void collectBatchLoadableCollectionKeys( public <T> void collectBatchLoadableCollectionKeys(
int batchSize, int batchSize,
IndexedConsumer<T> collector, IndexedConsumer<T> collector,
T keyBeingLoaded, @NonNull T keyBeingLoaded,
PluralAttributeMapping pluralAttributeMapping) { PluralAttributeMapping pluralAttributeMapping) {
collector.accept( 0, keyBeingLoaded ); collector.accept( 0, keyBeingLoaded );
@ -383,9 +388,10 @@ public class BatchFetchQueue {
for ( Entry<CollectionEntry, PersistentCollection<?>> me : map.entrySet() ) { for ( Entry<CollectionEntry, PersistentCollection<?>> me : map.entrySet() ) {
final CollectionEntry ce = me.getKey(); final CollectionEntry ce = me.getKey();
final Object loadedKey = ce.getLoadedKey();
final PersistentCollection<?> collection = me.getValue(); final PersistentCollection<?> collection = me.getValue();
if ( ce.getLoadedKey() == null ) { if ( loadedKey == null ) {
// the loadedKey of the collectionEntry might be null as it might have been reset to null // the loadedKey of the collectionEntry might be null as it might have been reset to null
// (see for example Collections.processDereferencedCollection() // (see for example Collections.processDereferencedCollection()
// and CollectionEntry.afterAction()) // and CollectionEntry.afterAction())
@ -407,21 +413,21 @@ public class BatchFetchQueue {
final boolean isEqual = pluralAttributeMapping.getKeyDescriptor().areEqual( final boolean isEqual = pluralAttributeMapping.getKeyDescriptor().areEqual(
keyBeingLoaded, keyBeingLoaded,
ce.getLoadedKey(), loadedKey,
context.getSession() context.getSession()
); );
// final boolean isEqual = collectionPersister.getKeyType().isEqual( // final boolean isEqual = collectionPersister.getKeyType().isEqual(
// id, // id,
// ce.getLoadedKey(), // loadedKey,
// collectionPersister.getFactory() // collectionPersister.getFactory()
// ); // );
if ( isEqual ) { if ( isEqual ) {
end = i; end = i;
} }
else if ( !isCached( ce.getLoadedKey(), pluralAttributeMapping.getCollectionDescriptor() ) ) { else if ( !isCached( loadedKey, pluralAttributeMapping.getCollectionDescriptor() ) ) {
//noinspection unchecked //noinspection unchecked
collector.accept( i++, (T) ce.getLoadedKey() ); collector.accept( i++, (T) loadedKey );
} }
if ( i == batchSize ) { if ( i == batchSize ) {
@ -444,7 +450,7 @@ public class BatchFetchQueue {
* @param batchSize the maximum number of keys to return * @param batchSize the maximum number of keys to return
* @return an array of collection keys, of length batchSize (padded with nulls) * @return an array of collection keys, of length batchSize (padded with nulls)
*/ */
public Object[] getCollectionBatch( public Object [] getCollectionBatch(
final CollectionPersister collectionPersister, final CollectionPersister collectionPersister,
final Object id, final Object id,
final int batchSize) { final int batchSize) {
@ -465,9 +471,10 @@ public class BatchFetchQueue {
if ( map != null ) { if ( map != null ) {
for ( Entry<CollectionEntry, PersistentCollection<?>> me : map.entrySet() ) { for ( Entry<CollectionEntry, PersistentCollection<?>> me : map.entrySet() ) {
final CollectionEntry ce = me.getKey(); final CollectionEntry ce = me.getKey();
final Object loadedKey = ce.getLoadedKey();
final PersistentCollection<?> collection = me.getValue(); final PersistentCollection<?> collection = me.getValue();
if ( ce.getLoadedKey() == null ) { if ( loadedKey == null ) {
// the loadedKey of the collectionEntry might be null as it might have been reset to null // the loadedKey of the collectionEntry might be null as it might have been reset to null
// (see for example Collections.processDereferencedCollection() // (see for example Collections.processDereferencedCollection()
// and CollectionEntry.afterAction()) // and CollectionEntry.afterAction())
@ -488,7 +495,7 @@ public class BatchFetchQueue {
final boolean isEqual = collectionPersister.getKeyType().isEqual( final boolean isEqual = collectionPersister.getKeyType().isEqual(
id, id,
ce.getLoadedKey(), loadedKey,
collectionPersister.getFactory() collectionPersister.getFactory()
); );
@ -496,8 +503,8 @@ public class BatchFetchQueue {
end = i; end = i;
//checkForEnd = false; //checkForEnd = false;
} }
else if ( !isCached( ce.getLoadedKey(), collectionPersister ) ) { else if ( !isCached( loadedKey, collectionPersister ) ) {
keys[i++] = ce.getLoadedKey(); keys[i++] = loadedKey;
//count++; //count++;
} }

View File

@ -12,6 +12,7 @@ import org.hibernate.collection.spi.AbstractPersistentCollection;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
@ -21,6 +22,9 @@ import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import org.checkerframework.checker.initialization.qual.UnderInitialization;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* We need an entry to tell us all about the current state * We need an entry to tell us all about the current state
* of a collection with respect to its persistent state * of a collection with respect to its persistent state
@ -33,14 +37,14 @@ public final class CollectionEntry implements Serializable {
//ATTRIBUTES MAINTAINED BETWEEN FLUSH CYCLES //ATTRIBUTES MAINTAINED BETWEEN FLUSH CYCLES
// session-start/post-flush persistent state // session-start/post-flush persistent state
private Serializable snapshot; private @Nullable Serializable snapshot;
// allow the CollectionSnapshot to be serialized // allow the CollectionSnapshot to be serialized
private String role; private @Nullable String role;
// "loaded" means the reference that is consistent // "loaded" means the reference that is consistent
// with the current database state // with the current database state
private transient CollectionPersister loadedPersister; private transient @Nullable CollectionPersister loadedPersister;
private Object loadedKey; private @Nullable Object loadedKey;
// ATTRIBUTES USED ONLY DURING FLUSH CYCLE // ATTRIBUTES USED ONLY DURING FLUSH CYCLE
@ -56,8 +60,8 @@ public final class CollectionEntry implements Serializable {
private transient boolean ignore; private transient boolean ignore;
// "current" means the reference that was found during flush() // "current" means the reference that was found during flush()
private transient CollectionPersister currentPersister; private transient @Nullable CollectionPersister currentPersister;
private transient Object currentKey; private transient @Nullable Object currentKey;
/** /**
* For newly wrapped collections, or dereferenced collection wrappers * For newly wrapped collections, or dereferenced collection wrappers
@ -88,7 +92,9 @@ public final class CollectionEntry implements Serializable {
//collection.clearDirty() //collection.clearDirty()
this.loadedKey = loadedKey; this.loadedKey = loadedKey;
setLoadedPersister( loadedPersister );
this.loadedPersister = loadedPersister;
this.role = ( loadedPersister == null ? null : loadedPersister.getRole() );
collection.setSnapshot( loadedKey, role, null ); collection.setSnapshot( loadedKey, role, null );
@ -106,7 +112,8 @@ public final class CollectionEntry implements Serializable {
//collection.clearDirty() //collection.clearDirty()
this.loadedKey = loadedKey; this.loadedKey = loadedKey;
setLoadedPersister( loadedPersister ); this.loadedPersister = loadedPersister;
this.role = ( loadedPersister == null ? null : loadedPersister.getRole() );
} }
/** /**
@ -118,9 +125,8 @@ public final class CollectionEntry implements Serializable {
ignore = false; ignore = false;
loadedKey = collection.getKey(); loadedKey = collection.getKey();
setLoadedPersister( loadedPersister = factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( collection.getRole() );
factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( collection.getRole() ) this.role = ( loadedPersister == null ? null : loadedPersister.getRole() );
);
snapshot = collection.getStoredSnapshot(); snapshot = collection.getStoredSnapshot();
} }
@ -132,10 +138,10 @@ public final class CollectionEntry implements Serializable {
* @see #deserialize * @see #deserialize
*/ */
private CollectionEntry( private CollectionEntry(
String role, @Nullable String role,
Serializable snapshot, Serializable snapshot,
Object loadedKey, Object loadedKey,
SessionFactoryImplementor factory) { @Nullable SessionFactoryImplementor factory) {
this.role = role; this.role = role;
this.snapshot = snapshot; this.snapshot = snapshot;
this.loadedKey = loadedKey; this.loadedKey = loadedKey;
@ -176,7 +182,7 @@ public final class CollectionEntry implements Serializable {
if ( nonMutableChange ) { if ( nonMutableChange ) {
throw new HibernateException( throw new HibernateException(
"changed an immutable collection instance: " + "changed an immutable collection instance: " +
MessageHelper.collectionInfoString( loadedPersister.getRole(), getLoadedKey() ) MessageHelper.collectionInfoString( NullnessUtil.castNonNull( loadedPersister ).getRole(), getLoadedKey() )
); );
} }
@ -199,12 +205,12 @@ public final class CollectionEntry implements Serializable {
public void postInitialize(PersistentCollection<?> collection) throws HibernateException { public void postInitialize(PersistentCollection<?> collection) throws HibernateException {
final CollectionPersister loadedPersister = getLoadedPersister(); final CollectionPersister loadedPersister = getLoadedPersister();
snapshot = loadedPersister.isMutable() snapshot = loadedPersister != null && loadedPersister.isMutable()
? collection.getSnapshot( loadedPersister ) ? collection.getSnapshot( loadedPersister )
: null; : null;
collection.setSnapshot( loadedKey, role, snapshot ); collection.setSnapshot( loadedKey, role, snapshot );
final SharedSessionContractImplementor session = ((AbstractPersistentCollection<?>) collection).getSession(); final SharedSessionContractImplementor session = ((AbstractPersistentCollection<?>) collection).getSession();
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( loadedPersister ) ) { if ( loadedPersister != null && session.getLoadQueryInfluencers().effectivelyBatchLoadable( loadedPersister ) ) {
session.getPersistenceContextInternal() session.getPersistenceContextInternal()
.getBatchFetchQueue() .getBatchFetchQueue()
.removeBatchLoadableCollection( this ); .removeBatchLoadableCollection( this );
@ -236,21 +242,21 @@ public final class CollectionEntry implements Serializable {
if ( resnapshot ) { if ( resnapshot ) {
snapshot = loadedPersister == null || !loadedPersister.isMutable() ? snapshot = loadedPersister == null || !loadedPersister.isMutable() ?
null : null :
collection.getSnapshot( loadedPersister ); //re-snapshot collection.getSnapshot( NullnessUtil.castNonNull( loadedPersister ) ); //re-snapshot
} }
collection.postAction(); collection.postAction();
} }
public Object getKey() { public @Nullable Object getKey() {
return getLoadedKey(); return getLoadedKey();
} }
public String getRole() { public @Nullable String getRole() {
return role; return role;
} }
public Serializable getSnapshot() { public @Nullable Serializable getSnapshot() {
return snapshot; return snapshot;
} }
@ -275,17 +281,17 @@ public final class CollectionEntry implements Serializable {
fromMerge = true; fromMerge = true;
} }
private void setLoadedPersister(CollectionPersister persister) { private void setLoadedPersister(@Nullable CollectionPersister persister) {
loadedPersister = persister; loadedPersister = persister;
setRole( persister == null ? null : persister.getRole() ); setRole( persister == null ? null : persister.getRole() );
} }
void afterDeserialize(SessionFactoryImplementor factory) { void afterDeserialize(@Nullable SessionFactoryImplementor factory) {
if ( factory == null ) { if ( factory == null ) {
loadedPersister = null; loadedPersister = null;
} }
else { else {
loadedPersister = factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( role ); loadedPersister = factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( NullnessUtil.castNonNull( role ) );
} }
} }
@ -337,11 +343,11 @@ public final class CollectionEntry implements Serializable {
return ignore; return ignore;
} }
public CollectionPersister getCurrentPersister() { public @Nullable CollectionPersister getCurrentPersister() {
return currentPersister; return currentPersister;
} }
public void setCurrentPersister(CollectionPersister currentPersister) { public void setCurrentPersister(@Nullable CollectionPersister currentPersister) {
this.currentPersister = currentPersister; this.currentPersister = currentPersister;
} }
@ -349,26 +355,26 @@ public final class CollectionEntry implements Serializable {
* This is only available late during the flush * This is only available late during the flush
* cycle * cycle
*/ */
public Object getCurrentKey() { public @Nullable Object getCurrentKey() {
return currentKey; return currentKey;
} }
public void setCurrentKey(Object currentKey) { public void setCurrentKey(@Nullable Object currentKey) {
this.currentKey = currentKey; this.currentKey = currentKey;
} }
/** /**
* This is only available late during the flush cycle * This is only available late during the flush cycle
*/ */
public CollectionPersister getLoadedPersister() { public @Nullable CollectionPersister getLoadedPersister() {
return loadedPersister; return loadedPersister;
} }
public Object getLoadedKey() { public @Nullable Object getLoadedKey() {
return loadedKey; return loadedKey;
} }
public void setRole(String role) { public void setRole(@Nullable String role) {
this.role = role; this.role = role;
} }
@ -398,9 +404,10 @@ public final class CollectionEntry implements Serializable {
// does the collection already have // does the collection already have
// it's own up-to-date snapshot? // it's own up-to-date snapshot?
final CollectionPersister loadedPersister = getLoadedPersister(); final CollectionPersister loadedPersister = getLoadedPersister();
Serializable snapshot = getSnapshot();
return collection.wasInitialized() && return collection.wasInitialized() &&
( loadedPersister ==null || loadedPersister.isMutable() ) && ( loadedPersister == null || loadedPersister.isMutable() ) &&
collection.isSnapshotEmpty( getSnapshot() ); (snapshot != null ? collection.isSnapshotEmpty( snapshot ) : true);
} }

View File

@ -16,6 +16,8 @@ import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Uniquely identifies a collection instance in a particular session. * Uniquely identifies a collection instance in a particular session.
* *
@ -39,7 +41,7 @@ public final class CollectionKey implements Serializable {
private CollectionKey( private CollectionKey(
String role, String role,
Object key, @Nullable Object key,
Type keyType, Type keyType,
SessionFactoryImplementor factory) { SessionFactoryImplementor factory) {
this.role = role; this.role = role;
@ -77,7 +79,7 @@ public final class CollectionKey implements Serializable {
} }
@Override @Override
public boolean equals(final Object other) { public boolean equals(final @Nullable Object other) {
if ( this == other ) { if ( this == other ) {
return true; return true;
} }
@ -127,7 +129,8 @@ public final class CollectionKey implements Serializable {
(String) ois.readObject(), (String) ois.readObject(),
ois.readObject(), ois.readObject(),
(Type) ois.readObject(), (Type) ois.readObject(),
(session == null ? null : session.getFactory()) // Should never be able to be null
session.getFactory()
); );
} }
} }

View File

@ -13,9 +13,12 @@ import org.hibernate.Incubating;
import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.AppliedGraph; import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.util.NullnessUtil;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Think of this as the composite modeling of a graph * Think of this as the composite modeling of a graph
* and the semantic. * and the semantic.
@ -33,8 +36,8 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
private final boolean allowOverwrite; private final boolean allowOverwrite;
private GraphSemantic semantic; private @Nullable GraphSemantic semantic;
private RootGraphImplementor<?> graph; private @Nullable RootGraphImplementor<?> graph;
/** /**
* @implSpec I explicitly made this constructor package protected * @implSpec I explicitly made this constructor package protected
@ -59,12 +62,12 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
} }
@Override @Override
public GraphSemantic getSemantic() { public @Nullable GraphSemantic getSemantic() {
return semantic; return semantic;
} }
@Override @Override
public RootGraphImplementor<?> getGraph() { public @Nullable RootGraphImplementor<?> getGraph() {
return graph; return graph;
} }
@ -75,7 +78,7 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
* @throws IllegalArgumentException Thrown if the semantic is null * @throws IllegalArgumentException Thrown if the semantic is null
* @throws IllegalStateException If previous state is still available (hasn't been cleared). * @throws IllegalStateException If previous state is still available (hasn't been cleared).
*/ */
public void applyGraph(RootGraphImplementor<?> graph, GraphSemantic semantic) { public void applyGraph(RootGraphImplementor<?> graph, @Nullable GraphSemantic semantic) {
if ( semantic == null ) { if ( semantic == null ) {
throw new IllegalArgumentException( "Graph semantic cannot be null" ); throw new IllegalArgumentException( "Graph semantic cannot be null" );
} }
@ -107,7 +110,7 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
* @throws IllegalArgumentException If both kinds of graphs were present in the properties/hints * @throws IllegalArgumentException If both kinds of graphs were present in the properties/hints
* @throws IllegalStateException If previous state is still available (hasn't been cleared). * @throws IllegalStateException If previous state is still available (hasn't been cleared).
*/ */
public void applyConfiguredGraph(Map<String,?> properties) { public void applyConfiguredGraph(@Nullable Map<String,?> properties) {
if ( properties == null || properties.isEmpty() ) { if ( properties == null || properties.isEmpty() ) {
return; return;
} }
@ -138,6 +141,7 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
applyGraph( fetchHint, GraphSemantic.FETCH ); applyGraph( fetchHint, GraphSemantic.FETCH );
} }
else { else {
assert loadHint != null : "@AssumeAssertion(nullness)";
applyGraph( loadHint, GraphSemantic.LOAD ); applyGraph( loadHint, GraphSemantic.LOAD );
} }
} }

View File

@ -15,6 +15,8 @@ import org.hibernate.AssertionFailure;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Uniquely identifies of an entity instance in a particular Session by identifier. * Uniquely identifies of an entity instance in a particular Session by identifier.
* Note that it's only safe to be used within the scope of a Session: it doesn't consider for example the tenantId * Note that it's only safe to be used within the scope of a Session: it doesn't consider for example the tenantId
@ -44,7 +46,7 @@ public final class EntityKey implements Serializable {
* @param id The entity id * @param id The entity id
* @param persister The entity persister * @param persister The entity persister
*/ */
public EntityKey(Object id, EntityPersister persister) { public EntityKey(@Nullable Object id, EntityPersister persister) {
this.persister = persister; this.persister = persister;
if ( id == null ) { if ( id == null ) {
throw new AssertionFailure( "null identifier (" + persister.getEntityName() + ")" ); throw new AssertionFailure( "null identifier (" + persister.getEntityName() + ")" );
@ -82,7 +84,7 @@ public final class EntityKey implements Serializable {
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(@Nullable Object other) {
if ( this == other ) { if ( this == other ) {
return true; return true;
} }

View File

@ -14,6 +14,10 @@ import java.io.Serializable;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.checkerframework.checker.initialization.qual.UnderInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Used to uniquely key an entity instance in relation to a particular session * Used to uniquely key an entity instance in relation to a particular session
* by some unique property reference, as opposed to identifier. * by some unique property reference, as opposed to identifier.
@ -41,7 +45,7 @@ public class EntityUniqueKey implements Serializable {
this.entityName = entityName; this.entityName = entityName;
this.key = key; this.key = key;
this.keyType = keyType; this.keyType = keyType;
this.hashCode = generateHashCode( factory ); this.hashCode = generateHashCode( entityName, uniqueKeyName, keyType, key, factory );
} }
public String getEntityName() { public String getEntityName() {
@ -56,7 +60,7 @@ public class EntityUniqueKey implements Serializable {
return uniqueKeyName; return uniqueKeyName;
} }
public int generateHashCode(SessionFactoryImplementor factory) { public static int generateHashCode(String entityName, String uniqueKeyName, Type keyType, Object key, SessionFactoryImplementor factory) {
int result = 17; int result = 17;
result = 37 * result + entityName.hashCode(); result = 37 * result + entityName.hashCode();
result = 37 * result + uniqueKeyName.hashCode(); result = 37 * result + uniqueKeyName.hashCode();
@ -70,7 +74,10 @@ public class EntityUniqueKey implements Serializable {
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(@Nullable Object other) {
if ( other == null || other.getClass() != EntityUniqueKey.class ) {
return false;
}
EntityUniqueKey that = (EntityUniqueKey) other; EntityUniqueKey that = (EntityUniqueKey) other;
return that != null && that.entityName.equals( entityName ) return that != null && that.entityName.equals( entityName )
&& that.uniqueKeyName.equals( uniqueKeyName ) && that.uniqueKeyName.equals( uniqueKeyName )

View File

@ -22,6 +22,8 @@ import org.hibernate.action.spi.Executable;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* A list of {@link Executable executeble actions}. Responsible for * A list of {@link Executable executeble actions}. Responsible for
* {@linkplain #sort() sorting} the executables, and calculating the * {@linkplain #sort() sorting} the executables, and calculating the
@ -47,7 +49,7 @@ public class ExecutableList<E extends ComparableExecutable>
private final ArrayList<E> executables; private final ArrayList<E> executables;
private final Sorter<E> sorter; private final @Nullable Sorter<E> sorter;
private final boolean requiresSorting; private final boolean requiresSorting;
private boolean sorted; private boolean sorted;
@ -57,7 +59,7 @@ public class ExecutableList<E extends ComparableExecutable>
* invalidate cache regions as it is exposed from {@link #getQuerySpaces}. This value * invalidate cache regions as it is exposed from {@link #getQuerySpaces}. This value
* being {@code null} indicates that the query spaces should be calculated. * being {@code null} indicates that the query spaces should be calculated.
*/ */
private transient Set<Serializable> querySpaces; private transient @Nullable Set<Serializable> querySpaces;
/** /**
* Creates a new instance with the default settings. * Creates a new instance with the default settings.
@ -296,9 +298,10 @@ public class ExecutableList<E extends ComparableExecutable>
oos.writeInt( -1 ); oos.writeInt( -1 );
} }
else { else {
final Set<Serializable> qs = querySpaces;
oos.writeInt( querySpaces.size() ); oos.writeInt( querySpaces.size() );
// these are always String, why we treat them as Serializable instead is beyond me... // these are always String, why we treat them as Serializable instead is beyond me...
for ( Serializable querySpace : querySpaces ) { for ( Serializable querySpace : qs ) {
oos.writeUTF( querySpace.toString() ); oos.writeUTF( querySpace.toString() );
} }
} }
@ -329,10 +332,12 @@ public class ExecutableList<E extends ComparableExecutable>
this.querySpaces = null; this.querySpaces = null;
} }
else { else {
querySpaces = CollectionHelper.setOfSize( numberOfQuerySpaces ); // The line below is for CF nullness checking purposes.
final Set<Serializable> querySpaces = CollectionHelper.setOfSize( numberOfQuerySpaces );
for ( int i = 0; i < numberOfQuerySpaces; i++ ) { for ( int i = 0; i < numberOfQuerySpaces; i++ ) {
querySpaces.add( in.readUTF() ); querySpaces.add( in.readUTF() );
} }
this.querySpaces = querySpaces;
} }
} }

View File

@ -8,6 +8,8 @@ package org.hibernate.engine.spi;
import org.hibernate.annotations.ResultCheckStyle; import org.hibernate.annotations.ResultCheckStyle;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* For persistence operations (INSERT, UPDATE, DELETE) what style of * For persistence operations (INSERT, UPDATE, DELETE) what style of
* determining results (success/failure) is to be used. * determining results (success/failure) is to be used.
@ -54,7 +56,7 @@ public enum ExecuteUpdateResultCheckStyle {
return name; return name;
} }
public static ExecuteUpdateResultCheckStyle fromResultCheckStyle(ResultCheckStyle style) { public static @Nullable ExecuteUpdateResultCheckStyle fromResultCheckStyle(ResultCheckStyle style) {
switch (style) { switch (style) {
case NONE: case NONE:
return NONE; return NONE;
@ -67,7 +69,7 @@ public enum ExecuteUpdateResultCheckStyle {
} }
} }
public static ExecuteUpdateResultCheckStyle fromExternalName(String name) { public static @Nullable ExecuteUpdateResultCheckStyle fromExternalName(String name) {
if ( name.equalsIgnoreCase( NONE.name ) ) { if ( name.equalsIgnoreCase( NONE.name ) ) {
return NONE; return NONE;
} }
@ -82,7 +84,7 @@ public enum ExecuteUpdateResultCheckStyle {
} }
} }
public static ExecuteUpdateResultCheckStyle determineDefault(String customSql, boolean callable) { public static ExecuteUpdateResultCheckStyle determineDefault(@Nullable String customSql, boolean callable) {
return customSql != null && callable ? PARAM : COUNT; return customSql != null && callable ? PARAM : COUNT;
} }
} }

View File

@ -13,6 +13,8 @@ import java.util.Set;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Represents the definition of a {@link org.hibernate.Filter filter}. * Represents the definition of a {@link org.hibernate.Filter filter}.
* This information includes the {@linkplain #filterName name} of the * This information includes the {@linkplain #filterName name} of the
@ -36,7 +38,7 @@ public class FilterDefinition implements Serializable {
* *
* @param name The name of the filter for which this configuration is in effect. * @param name The name of the filter for which this configuration is in effect.
*/ */
public FilterDefinition(String name, String defaultCondition, Map<String, JdbcMapping> explicitParamJaMappings) { public FilterDefinition(String name, String defaultCondition, @Nullable Map<String, JdbcMapping> explicitParamJaMappings) {
this.filterName = name; this.filterName = name;
this.defaultFilterCondition = defaultCondition; this.defaultFilterCondition = defaultCondition;
if ( explicitParamJaMappings != null ) { if ( explicitParamJaMappings != null ) {
@ -59,7 +61,9 @@ public class FilterDefinition implements Serializable {
* @return The parameters named by this configuration. * @return The parameters named by this configuration.
*/ */
public Set<String> getParameterNames() { public Set<String> getParameterNames() {
return explicitParamJaMappings.keySet(); // local variable instantiated for checkerframework nullness inference reasons
Set<String> keys = explicitParamJaMappings.keySet();
return keys;
} }
/** /**
@ -69,7 +73,7 @@ public class FilterDefinition implements Serializable {
* *
* @return The type of the named parameter. * @return The type of the named parameter.
*/ */
public JdbcMapping getParameterJdbcMapping(String parameterName) { public @Nullable JdbcMapping getParameterJdbcMapping(String parameterName) {
return explicitParamJaMappings.get( parameterName ); return explicitParamJaMappings.get( parameterName );
} }

View File

@ -12,6 +12,8 @@ import org.hibernate.internal.CoreLogging;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* A strategy for determining if an identifier value is an identifier of * A strategy for determining if an identifier value is an identifier of
* a new transient instance or a previously persistent transient instance. * a new transient instance or a previously persistent transient instance.
@ -23,7 +25,7 @@ import org.jboss.logging.Logger;
public class IdentifierValue implements UnsavedValueStrategy { public class IdentifierValue implements UnsavedValueStrategy {
private static final Logger LOG = CoreLogging.logger( IdentifierValue.class ); private static final Logger LOG = CoreLogging.logger( IdentifierValue.class );
private final Object value; private final @Nullable Object value;
/** /**
* Always assume the transient instance is newly instantiated * Always assume the transient instance is newly instantiated
@ -73,13 +75,13 @@ public class IdentifierValue implements UnsavedValueStrategy {
*/ */
public static final IdentifierValue NULL = new IdentifierValue() { public static final IdentifierValue NULL = new IdentifierValue() {
@Override @Override
public Boolean isUnsaved(Object id) { public Boolean isUnsaved(@Nullable Object id) {
LOG.trace( "ID unsaved-value strategy NULL" ); LOG.trace( "ID unsaved-value strategy NULL" );
return id == null; return id == null;
} }
@Override @Override
public Serializable getDefaultValue(Object currentValue) { public @Nullable Serializable getDefaultValue(Object currentValue) {
return null; return null;
} }
@ -94,13 +96,13 @@ public class IdentifierValue implements UnsavedValueStrategy {
*/ */
public static final IdentifierValue UNDEFINED = new IdentifierValue() { public static final IdentifierValue UNDEFINED = new IdentifierValue() {
@Override @Override
public Boolean isUnsaved(Object id) { public @Nullable Boolean isUnsaved(Object id) {
LOG.trace( "ID unsaved-value strategy UNDEFINED" ); LOG.trace( "ID unsaved-value strategy UNDEFINED" );
return null; return null;
} }
@Override @Override
public Serializable getDefaultValue(Object currentValue) { public @Nullable Serializable getDefaultValue(Object currentValue) {
return null; return null;
} }
@ -126,13 +128,13 @@ public class IdentifierValue implements UnsavedValueStrategy {
* Does the given identifier belong to a new instance? * Does the given identifier belong to a new instance?
*/ */
@Override @Override
public Boolean isUnsaved(Object id) { public @Nullable Boolean isUnsaved(@Nullable Object id) {
LOG.tracev( "ID unsaved-value: {0}", value ); LOG.tracev( "ID unsaved-value: {0}", value );
return id == null || id.equals( value ); return id == null || id.equals( value );
} }
@Override @Override
public Object getDefaultValue(Object currentValue) { public @Nullable Object getDefaultValue(@Nullable Object currentValue) {
return value; return value;
} }

View File

@ -23,10 +23,13 @@ import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.FilterImpl; import org.hibernate.internal.FilterImpl;
import org.hibernate.internal.SessionCreationOptions; import org.hibernate.internal.SessionCreationOptions;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.loader.ast.spi.CascadingFetchProfile; import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.checkerframework.checker.nullness.qual.Nullable;
import static java.util.Collections.emptySet; import static java.util.Collections.emptySet;
import static org.hibernate.engine.FetchStyle.SUBSELECT; import static org.hibernate.engine.FetchStyle.SUBSELECT;
@ -51,7 +54,7 @@ public class LoadQueryInfluencers implements Serializable {
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
public static final LoadQueryInfluencers NONE = new LoadQueryInfluencers(); public static final LoadQueryInfluencers NONE = new LoadQueryInfluencers();
private final SessionFactoryImplementor sessionFactory; private final @Nullable SessionFactoryImplementor sessionFactory;
private CascadingFetchProfile enabledCascadingFetchProfile; private CascadingFetchProfile enabledCascadingFetchProfile;
@ -85,7 +88,7 @@ public class LoadQueryInfluencers implements Serializable {
subselectFetchEnabled = options.isSubselectFetchEnabled(); subselectFetchEnabled = options.isSubselectFetchEnabled();
} }
public EffectiveEntityGraph applyEntityGraph(RootGraphImplementor<?> rootGraph, GraphSemantic graphSemantic) { public EffectiveEntityGraph applyEntityGraph(@Nullable RootGraphImplementor<?> rootGraph, @Nullable GraphSemantic graphSemantic) {
final EffectiveEntityGraph effectiveEntityGraph = getEffectiveEntityGraph(); final EffectiveEntityGraph effectiveEntityGraph = getEffectiveEntityGraph();
if ( graphSemantic != null ) { if ( graphSemantic != null ) {
if ( rootGraph == null ) { if ( rootGraph == null ) {
@ -96,7 +99,7 @@ public class LoadQueryInfluencers implements Serializable {
return effectiveEntityGraph; return effectiveEntityGraph;
} }
public SessionFactoryImplementor getSessionFactory() { public @Nullable SessionFactoryImplementor getSessionFactory() {
return sessionFactory; return sessionFactory;
} }
@ -186,7 +189,7 @@ public class LoadQueryInfluencers implements Serializable {
} }
} }
public Filter getEnabledFilter(String filterName) { public @Nullable Filter getEnabledFilter(String filterName) {
if ( enabledFilters == null ) { if ( enabledFilters == null ) {
return null; return null;
} }
@ -197,7 +200,7 @@ public class LoadQueryInfluencers implements Serializable {
public Filter enableFilter(String filterName) { public Filter enableFilter(String filterName) {
checkMutability(); checkMutability();
FilterImpl filter = new FilterImpl( sessionFactory.getFilterDefinition( filterName ) ); FilterImpl filter = new FilterImpl( NullnessUtil.castNonNull( sessionFactory ).getFilterDefinition( filterName ) );
if ( enabledFilters == null ) { if ( enabledFilters == null ) {
this.enabledFilters = new HashMap<>(); this.enabledFilters = new HashMap<>();
} }
@ -223,7 +226,7 @@ public class LoadQueryInfluencers implements Serializable {
return filter.getParameter( parsed[1] ); return filter.getParameter( parsed[1] );
} }
public static String[] parseFilterParameterName(String filterParameterName) { public static String [] parseFilterParameterName(String filterParameterName) {
int dot = filterParameterName.lastIndexOf( '.' ); int dot = filterParameterName.lastIndexOf( '.' );
if ( dot <= 0 ) { if ( dot <= 0 ) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@ -274,7 +277,7 @@ public class LoadQueryInfluencers implements Serializable {
} }
@Internal @Internal
public HashSet<String> adjustFetchProfiles(Set<String> disabledFetchProfiles, Set<String> enabledFetchProfiles) { public @Nullable HashSet<String> adjustFetchProfiles(@Nullable Set<String> disabledFetchProfiles, @Nullable Set<String> enabledFetchProfiles) {
final HashSet<String> oldFetchProfiles = final HashSet<String> oldFetchProfiles =
hasEnabledFetchProfiles() ? new HashSet<>( enabledFetchProfileNames ) : null; hasEnabledFetchProfiles() ? new HashSet<>( enabledFetchProfileNames ) : null;
if ( disabledFetchProfiles != null && enabledFetchProfileNames != null ) { if ( disabledFetchProfiles != null && enabledFetchProfileNames != null ) {
@ -353,7 +356,7 @@ public class LoadQueryInfluencers implements Serializable {
private boolean isSubselectFetchEnabledInProfile(CollectionPersister persister) { private boolean isSubselectFetchEnabledInProfile(CollectionPersister persister) {
if ( hasEnabledFetchProfiles() ) { if ( hasEnabledFetchProfiles() ) {
for ( String profile : getEnabledFetchProfileNames() ) { for ( String profile : getEnabledFetchProfileNames() ) {
final FetchProfile fetchProfile = sessionFactory.getFetchProfile( profile ); final FetchProfile fetchProfile = persister.getFactory().getFetchProfile( profile ) ;
if ( fetchProfile != null ) { if ( fetchProfile != null ) {
final Fetch fetch = fetchProfile.getFetchByRole( persister.getRole() ); final Fetch fetch = fetchProfile.getFetchByRole( persister.getRole() );
if ( fetch != null && fetch.getMethod() == SUBSELECT) { if ( fetch != null && fetch.getMethod() == SUBSELECT) {
@ -382,7 +385,7 @@ public class LoadQueryInfluencers implements Serializable {
private boolean hasSubselectLoadableCollectionsEnabledInProfile(EntityPersister persister) { private boolean hasSubselectLoadableCollectionsEnabledInProfile(EntityPersister persister) {
if ( hasEnabledFetchProfiles() ) { if ( hasEnabledFetchProfiles() ) {
for ( String profile : getEnabledFetchProfileNames() ) { for ( String profile : getEnabledFetchProfileNames() ) {
if ( sessionFactory.getFetchProfile( profile ) if ( persister.getFactory().getFetchProfile( profile )
.hasSubselectLoadableCollectionsEnabled( persister ) ) { .hasSubselectLoadableCollectionsEnabled( persister ) ) {
return true; return true;
} }

View File

@ -11,6 +11,8 @@ import org.hibernate.engine.internal.ManagedTypeHelper;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyConfiguration; import org.hibernate.proxy.ProxyConfiguration;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* For a full explanation of the purpose of this interface see {@link ManagedTypeHelper}. * For a full explanation of the purpose of this interface see {@link ManagedTypeHelper}.
* *
@ -22,46 +24,46 @@ import org.hibernate.proxy.ProxyConfiguration;
@Internal @Internal
public interface PrimeAmongSecondarySupertypes { public interface PrimeAmongSecondarySupertypes {
default ManagedEntity asManagedEntity() { default @Nullable ManagedEntity asManagedEntity() {
return null; return null;
} }
default PersistentAttributeInterceptable asPersistentAttributeInterceptable() { default @Nullable PersistentAttributeInterceptable asPersistentAttributeInterceptable() {
return null; return null;
} }
default SelfDirtinessTracker asSelfDirtinessTracker() { default @Nullable SelfDirtinessTracker asSelfDirtinessTracker() {
return null; return null;
} }
//Included for consistency but doesn't seem to be used? //Included for consistency but doesn't seem to be used?
default Managed asManaged() { default @Nullable Managed asManaged() {
return null; return null;
} }
//Included for consistency but doesn't seem to be used? //Included for consistency but doesn't seem to be used?
default ManagedComposite asManagedComposite() { default @Nullable ManagedComposite asManagedComposite() {
return null; return null;
} }
//Included for consistency but doesn't seem to be used? //Included for consistency but doesn't seem to be used?
default ManagedMappedSuperclass asManagedMappedSuperclass() { default @Nullable ManagedMappedSuperclass asManagedMappedSuperclass() {
return null; return null;
} }
default CompositeOwner asCompositeOwner() { default @Nullable CompositeOwner asCompositeOwner() {
return null; return null;
} }
default CompositeTracker asCompositeTracker() { default @Nullable CompositeTracker asCompositeTracker() {
return null; return null;
} }
default HibernateProxy asHibernateProxy() { default @Nullable HibernateProxy asHibernateProxy() {
return null; return null;
} }
default ProxyConfiguration asProxyConfiguration() { default @Nullable ProxyConfiguration asProxyConfiguration() {
return null; return null;
} }

View File

@ -68,6 +68,7 @@ import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel; import jakarta.persistence.metamodel.Metamodel;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* A wrapper class that delegates all method invocations to a delegate instance of * A wrapper class that delegates all method invocations to a delegate instance of
@ -165,7 +166,7 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
} }
@Override @Override
public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException { public EntityPersister getEntityPersister(@Nullable String entityName, Object object) throws HibernateException {
return delegate.getEntityPersister( entityName, object ); return delegate.getEntityPersister( entityName, object );
} }
@ -853,22 +854,22 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey) {
return delegate.find( entityClass, primaryKey ); return delegate.find( entityClass, primaryKey );
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
return delegate.find( entityClass, primaryKey, properties ); return delegate.find( entityClass, primaryKey, properties );
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
return delegate.find( entityClass, primaryKey, lockMode ); return delegate.find( entityClass, primaryKey, lockMode );
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
return delegate.find( entityClass, primaryKey, lockMode, properties ); return delegate.find( entityClass, primaryKey, lockMode, properties );
} }

View File

@ -51,6 +51,7 @@ import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel; import jakarta.persistence.metamodel.Metamodel;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* This helper class allows decorating a Session instance, while the * This helper class allows decorating a Session instance, while the
@ -809,22 +810,22 @@ public class SessionLazyDelegator implements Session {
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey) {
return this.lazySession.get().find( entityClass, primaryKey ); return this.lazySession.get().find( entityClass, primaryKey );
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
return this.lazySession.get().find( entityClass, primaryKey, properties ); return this.lazySession.get().find( entityClass, primaryKey, properties );
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
return this.lazySession.get().find( entityClass, primaryKey, lockMode ); return this.lazySession.get().find( entityClass, primaryKey, lockMode );
} }
@Override @Override
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) { public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
return this.lazySession.get().find( entityClass, primaryKey, lockMode, properties ); return this.lazySession.get().find( entityClass, primaryKey, lockMode, properties );
} }

View File

@ -10,6 +10,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import jakarta.persistence.FlushModeType; import jakarta.persistence.FlushModeType;
import jakarta.persistence.TransactionRequiredException; import jakarta.persistence.TransactionRequiredException;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
@ -307,7 +308,7 @@ public interface SharedSessionContractImplementor
* @param entityName optional entity name * @param entityName optional entity name
* @param object the entity instance * @param object the entity instance
*/ */
EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException; EntityPersister getEntityPersister(@Nullable String entityName, Object object) throws HibernateException;
/** /**
* Get the entity instance associated with the given {@link EntityKey}, * Get the entity instance associated with the given {@link EntityKey},

View File

@ -11,6 +11,8 @@ import jakarta.persistence.FlushModeType;
import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.criteria.CriteriaUpdate;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -413,7 +415,7 @@ public class SharedSessionDelegatorBaseImpl implements SharedSessionContractImpl
} }
@Override @Override
public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException { public EntityPersister getEntityPersister(@Nullable String entityName, Object object) throws HibernateException {
return delegate.getEntityPersister( entityName, object ); return delegate.getEntityPersister( entityName, object );
} }

View File

@ -13,6 +13,8 @@ import java.io.Serializable;
import org.hibernate.internal.util.ValueHolder; import org.hibernate.internal.util.ValueHolder;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* An ordered pair of a value and its Hibernate type. * An ordered pair of a value and its Hibernate type.
* *
@ -28,7 +30,7 @@ public final class TypedValue implements Serializable {
public TypedValue(final Type type, final Object value) { public TypedValue(final Type type, final Object value) {
this.type = type; this.type = type;
this.value = value; this.value = value;
initTransients(); this.hashcode = hashCode(type, value);
} }
public Object getValue() { public Object getValue() {
@ -47,7 +49,7 @@ public final class TypedValue implements Serializable {
return hashcode.getValue(); return hashcode.getValue();
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(@Nullable Object other) {
if ( this == other ) { if ( this == other ) {
return true; return true;
} }
@ -62,10 +64,10 @@ public final class TypedValue implements Serializable {
private void readObject(ObjectInputStream ois) private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException { throws ClassNotFoundException, IOException {
ois.defaultReadObject(); ois.defaultReadObject();
initTransients(); this.hashcode = hashCode(type, value);
} }
private void initTransients() { private static ValueHolder hashCode(Type type, Object value) {
this.hashcode = new ValueHolder<>( () -> value == null ? 0 : type.getHashCode( value ) ); return new ValueHolder<>( () -> value == null ? 0 : type.getHashCode( value ) );
} }
} }

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.engine.spi; package org.hibernate.engine.spi;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* The base contract for determining transient status versus detached status. * The base contract for determining transient status versus detached status.
* *
@ -21,7 +23,7 @@ public interface UnsavedValueStrategy {
* indicates the value does not corresponds to unsaved data (aka, detached state); {@code null} indicates that * indicates the value does not corresponds to unsaved data (aka, detached state); {@code null} indicates that
* this strategy was not able to determine conclusively. * this strategy was not able to determine conclusively.
*/ */
Boolean isUnsaved(Object test); @Nullable Boolean isUnsaved(@Nullable Object test);
/** /**
* Get a default value meant to indicate transience. * Get a default value meant to indicate transience.
@ -30,5 +32,5 @@ public interface UnsavedValueStrategy {
* *
* @return The default transience value. * @return The default transience value.
*/ */
Object getDefaultValue(Object currentValue); @Nullable Object getDefaultValue(@Nullable Object currentValue);
} }

View File

@ -12,6 +12,8 @@ import org.hibernate.internal.CoreLogging;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* A strategy for determining if a version value is a version of * A strategy for determining if a version value is a version of
* a new transient instance or a previously persistent transient instance. * a new transient instance or a previously persistent transient instance.
@ -23,20 +25,20 @@ import org.jboss.logging.Logger;
public class VersionValue implements UnsavedValueStrategy { public class VersionValue implements UnsavedValueStrategy {
private static final Logger LOG = CoreLogging.logger( VersionValue.class ); private static final Logger LOG = CoreLogging.logger( VersionValue.class );
private final Object value; private final @Nullable Object value;
/** /**
* Assume the transient instance is newly instantiated if the version * Assume the transient instance is newly instantiated if the version
* is null, otherwise assume it is a detached instance. * is null, otherwise assume it is a detached instance.
*/ */
public static final VersionValue NULL = new VersionValue() { public static final VersionValue NULL = new VersionValue() {
@Override @Override
public Boolean isUnsaved(Object version) { public Boolean isUnsaved(@Nullable Object version) {
LOG.trace( "Version unsaved-value strategy NULL" ); LOG.trace( "Version unsaved-value strategy NULL" );
return version == null; return version == null;
} }
@Override @Override
public Object getDefaultValue(Object currentValue) { public @Nullable Object getDefaultValue(Object currentValue) {
return null; return null;
} }
@ -52,7 +54,7 @@ public class VersionValue implements UnsavedValueStrategy {
*/ */
public static final VersionValue UNDEFINED = new VersionValue() { public static final VersionValue UNDEFINED = new VersionValue() {
@Override @Override
public Boolean isUnsaved(Object version) { public @Nullable Boolean isUnsaved(@Nullable Object version) {
LOG.trace( "Version unsaved-value strategy UNDEFINED" ); LOG.trace( "Version unsaved-value strategy UNDEFINED" );
return version == null ? Boolean.TRUE : null; return version == null ? Boolean.TRUE : null;
} }
@ -75,7 +77,7 @@ public class VersionValue implements UnsavedValueStrategy {
public static final VersionValue NEGATIVE = new VersionValue() { public static final VersionValue NEGATIVE = new VersionValue() {
@Override @Override
public Boolean isUnsaved(Object version) throws MappingException { public Boolean isUnsaved(@Nullable Object version) throws MappingException {
LOG.trace( "Version unsaved-value strategy NEGATIVE" ); LOG.trace( "Version unsaved-value strategy NEGATIVE" );
if ( version == null ) { if ( version == null ) {
return Boolean.TRUE; return Boolean.TRUE;
@ -114,13 +116,13 @@ public class VersionValue implements UnsavedValueStrategy {
} }
@Override @Override
public Boolean isUnsaved(Object version) throws MappingException { public @Nullable Boolean isUnsaved(@Nullable Object version) throws MappingException {
LOG.tracev( "Version unsaved-value: {0}", value ); LOG.tracev( "Version unsaved-value: {0}", value );
return version == null || version.equals( value ); return version == null || version.equals( value );
} }
@Override @Override
public Object getDefaultValue(Object currentValue) { public @Nullable Object getDefaultValue(@Nullable Object currentValue) {
return value; return value;
} }

View File

@ -8,6 +8,8 @@ package org.hibernate.graph.spi;
import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.GraphSemantic;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Contract for anything a fetch/load graph can be applied * Contract for anything a fetch/load graph can be applied
* *
@ -17,10 +19,10 @@ public interface AppliedGraph {
/** /**
* The applied graph * The applied graph
*/ */
RootGraphImplementor<?> getGraph(); @Nullable RootGraphImplementor<?> getGraph();
/** /**
* The semantic (fetch/load) under which the graph should be applied * The semantic (fetch/load) under which the graph should be applied
*/ */
GraphSemantic getSemantic(); @Nullable GraphSemantic getSemantic();
} }

View File

@ -42,7 +42,7 @@ public final class StringHelper {
return string.length() - 1; return string.length() - 1;
} }
public static String join(String seperator, String[] strings) { public static String join(String separator, String[] strings) {
int length = strings.length; int length = strings.length;
if ( length == 0 ) { if ( length == 0 ) {
return ""; return "";
@ -54,7 +54,7 @@ public final class StringHelper {
StringBuilder buf = new StringBuilder( length * firstStringLength ) StringBuilder buf = new StringBuilder( length * firstStringLength )
.append( strings[0] ); .append( strings[0] );
for ( int i = 1; i < length; i++ ) { for ( int i = 1; i < length; i++ ) {
buf.append( seperator ).append( strings[i] ); buf.append( separator ).append( strings[i] );
} }
return buf.toString(); return buf.toString();
} }

View File

@ -19,6 +19,8 @@ import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* Base descriptor, within the mapping model, for any part of the * Base descriptor, within the mapping model, for any part of the
* application's domain model: an attribute, an entity identifier, * application's domain model: an attribute, an entity identifier,
@ -200,7 +202,7 @@ public interface ModelPart extends MappingModelExpressible {
EntityMappingType findContainingEntityMapping(); EntityMappingType findContainingEntityMapping();
default boolean areEqual(Object one, Object other, SharedSessionContractImplementor session) { default boolean areEqual(@Nullable Object one, @Nullable Object other, SharedSessionContractImplementor session) {
// NOTE : deepEquals to account for arrays (compound natural-id) // NOTE : deepEquals to account for arrays (compound natural-id)
return Objects.deepEquals( one, other ); return Objects.deepEquals( one, other );
} }

View File

@ -14,6 +14,7 @@ import java.util.Set;
import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode; import jakarta.persistence.CacheStoreMode;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
@ -248,12 +249,12 @@ public class QueryOptionsImpl implements MutableQueryOptions, AppliedGraph {
} }
@Override @Override
public RootGraphImplementor<?> getGraph() { public @Nullable RootGraphImplementor<?> getGraph() {
return rootGraph; return rootGraph;
} }
@Override @Override
public GraphSemantic getSemantic() { public @Nullable GraphSemantic getSemantic() {
return graphSemantic; return graphSemantic;
} }
} }