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);
}
public final
class Field extends AccessibleObject implements Member {
public final class Field extends AccessibleObject implements Member {
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 {
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 = [
'-AsuppressWarnings=initialization',
// 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.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Persistent collections are treated as value objects by Hibernate.
* 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 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

View File

@ -10,6 +10,8 @@ import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.AppliedGraph;
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
* 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
public GraphSemantic getSemantic() {
public @Nullable GraphSemantic getSemantic() {
return delegate.getSemantic();
}
@Override
public RootGraphImplementor<?> getGraph() {
public @Nullable RootGraphImplementor<?> 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.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.persister.entity.EntityPersister;
@ -57,6 +56,8 @@ import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
@ -511,7 +512,7 @@ public class ActionQueue {
prepareActions( collectionQueuedOps );
}
private void prepareActions(ExecutableList<?> queue) throws HibernateException {
private void prepareActions(@Nullable ExecutableList<?> queue) throws HibernateException {
if ( queue == null ) {
return;
}
@ -583,7 +584,7 @@ public class ActionQueue {
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() ) {
return false;
}
@ -617,7 +618,7 @@ public class ActionQueue {
* @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 {
if ( list == null || list.isEmpty() ) {
return;
@ -651,8 +652,10 @@ public class ActionQueue {
// 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
// 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();
@ -676,7 +679,7 @@ public class ActionQueue {
*
* @param spaces The spaces to invalidate
*/
private void invalidateSpaces(String[] spaces) {
private void invalidateSpaces(String @Nullable [] spaces) {
if ( spaces != null && spaces.length > 0 ) {
for ( String space : spaces ) {
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();
}
@ -858,7 +861,7 @@ public class ActionQueue {
|| nonempty( collectionCreations );
}
private boolean nonempty(ExecutableList<?> list) {
private boolean nonempty(@Nullable ExecutableList<?> list) {
return list != null && !list.isEmpty();
}
@ -984,7 +987,7 @@ public class ActionQueue {
this.session = session;
}
public void register(T process) {
public void register(@Nullable T process) {
if ( process != null ) {
processes.add( process );
}
@ -1051,7 +1054,7 @@ public class ActionQueue {
if ( session.getFactory().getSessionFactoryOptions().isQueryCacheEnabled() ) {
session.getFactory().getCache().getTimestampsCache().invalidate(
querySpacesToInvalidate.toArray(StringHelper.EMPTY_STRINGS),
querySpacesToInvalidate.toArray(new String[0]),
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 ) {
final EntityType entityType = (EntityType) type;
final InsertInfo insertInfo = insertInfosByEntity.get( value );
@ -1209,7 +1212,7 @@ public class ActionQueue {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if ( this == o ) {
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];
// The bitset is there to quickly query if an index is already scheduled
final BitSet bitSet = new BitSet(insertInfos.length);

View File

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

View File

@ -26,6 +26,9 @@ import org.hibernate.persister.entity.EntityPersister;
import org.jboss.logging.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Keeps track of:<ul>
* <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
* {@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
@ -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
* 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 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.
@ -92,7 +95,7 @@ public class BatchFetchQueue {
* @return The fetch descriptor; may return null if no subselect fetch queued for
* this entity key.
*/
public SubselectFetch getSubselect(EntityKey key) {
public @Nullable SubselectFetch getSubselect(EntityKey key) {
if ( subselectsByEntityKey == null ) {
return null;
}
@ -165,8 +168,8 @@ public class BatchFetchQueue {
* if necessary
*/
public void removeBatchLoadableEntityKey(EntityKey key) {
if ( batchLoadableEntityKeys != null
&& key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) {
if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() )
&& batchLoadableEntityKeys != null ) {
final LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
if ( set != null ) {
set.remove( key );
@ -178,8 +181,7 @@ public class BatchFetchQueue {
* Intended for test usage. Really has no use-case in Hibernate proper.
*/
public boolean containsEntityKey(EntityKey key) {
if ( batchLoadableEntityKeys != null
&& key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) ) {
if ( key.isBatchLoadable( context.getSession().getLoadQueryInfluencers() ) && batchLoadableEntityKeys != null ) {
LinkedHashSet<EntityKey> set = batchLoadableEntityKeys.get( key.getEntityName() );
if ( set != null ) {
return set.contains( key );
@ -197,7 +199,7 @@ public class BatchFetchQueue {
public <T> void collectBatchLoadableEntityIds(
final int domainBatchSize,
IndexedConsumer<T> collector,
final T loadingId,
final @NonNull T loadingId,
final EntityMappingType entityDescriptor) {
// make sure we load the id being loaded in the batch!
collector.accept( 0, loadingId );
@ -248,7 +250,7 @@ public class BatchFetchQueue {
* complex algorithm that tries to grab keys registered immediately after
* the given key.
*/
public Object[] getBatchLoadableEntityIds(
public Object [] getBatchLoadableEntityIds(
final EntityMappingType entityDescriptor,
final Object loadingId,
final int maxBatchSize) {
@ -328,6 +330,7 @@ public class BatchFetchQueue {
batchLoadableCollections = CollectionHelper.mapOfSize( 12 );
}
assert persister != null : "@AssumeAssertion(nullness)";
final LinkedHashMap<CollectionEntry, PersistentCollection<?>> map =
batchLoadableCollections.computeIfAbsent(
persister.getRole(),
@ -343,11 +346,13 @@ public class BatchFetchQueue {
* if necessary
*/
public void removeBatchLoadableCollection(CollectionEntry ce) {
final CollectionPersister persister = ce.getLoadedPersister();
if ( batchLoadableCollections == null ) {
return;
}
assert persister != null : "@AssumeAssertion(nullness)";
LinkedHashMap<CollectionEntry, PersistentCollection<?>> map =
batchLoadableCollections.get( ce.getLoadedPersister().getRole() );
batchLoadableCollections.get( persister.getRole() );
if ( map != null ) {
map.remove( ce );
}
@ -363,7 +368,7 @@ public class BatchFetchQueue {
public <T> void collectBatchLoadableCollectionKeys(
int batchSize,
IndexedConsumer<T> collector,
T keyBeingLoaded,
@NonNull T keyBeingLoaded,
PluralAttributeMapping pluralAttributeMapping) {
collector.accept( 0, keyBeingLoaded );
@ -383,9 +388,10 @@ public class BatchFetchQueue {
for ( Entry<CollectionEntry, PersistentCollection<?>> me : map.entrySet() ) {
final CollectionEntry ce = me.getKey();
final Object loadedKey = ce.getLoadedKey();
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
// (see for example Collections.processDereferencedCollection()
// and CollectionEntry.afterAction())
@ -407,21 +413,21 @@ public class BatchFetchQueue {
final boolean isEqual = pluralAttributeMapping.getKeyDescriptor().areEqual(
keyBeingLoaded,
ce.getLoadedKey(),
loadedKey,
context.getSession()
);
// final boolean isEqual = collectionPersister.getKeyType().isEqual(
// id,
// ce.getLoadedKey(),
// loadedKey,
// collectionPersister.getFactory()
// );
if ( isEqual ) {
end = i;
}
else if ( !isCached( ce.getLoadedKey(), pluralAttributeMapping.getCollectionDescriptor() ) ) {
else if ( !isCached( loadedKey, pluralAttributeMapping.getCollectionDescriptor() ) ) {
//noinspection unchecked
collector.accept( i++, (T) ce.getLoadedKey() );
collector.accept( i++, (T) loadedKey );
}
if ( i == batchSize ) {
@ -444,7 +450,7 @@ public class BatchFetchQueue {
* @param batchSize the maximum number of keys to return
* @return an array of collection keys, of length batchSize (padded with nulls)
*/
public Object[] getCollectionBatch(
public Object [] getCollectionBatch(
final CollectionPersister collectionPersister,
final Object id,
final int batchSize) {
@ -465,9 +471,10 @@ public class BatchFetchQueue {
if ( map != null ) {
for ( Entry<CollectionEntry, PersistentCollection<?>> me : map.entrySet() ) {
final CollectionEntry ce = me.getKey();
final Object loadedKey = ce.getLoadedKey();
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
// (see for example Collections.processDereferencedCollection()
// and CollectionEntry.afterAction())
@ -488,7 +495,7 @@ public class BatchFetchQueue {
final boolean isEqual = collectionPersister.getKeyType().isEqual(
id,
ce.getLoadedKey(),
loadedKey,
collectionPersister.getFactory()
);
@ -496,8 +503,8 @@ public class BatchFetchQueue {
end = i;
//checkForEnd = false;
}
else if ( !isCached( ce.getLoadedKey(), collectionPersister ) ) {
keys[i++] = ce.getLoadedKey();
else if ( !isCached( loadedKey, collectionPersister ) ) {
keys[i++] = loadedKey;
//count++;
}

View File

@ -12,6 +12,7 @@ import org.hibernate.collection.spi.AbstractPersistentCollection;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
@ -21,6 +22,9 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
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
* of a collection with respect to its persistent state
@ -33,14 +37,14 @@ public final class CollectionEntry implements Serializable {
//ATTRIBUTES MAINTAINED BETWEEN FLUSH CYCLES
// session-start/post-flush persistent state
private Serializable snapshot;
private @Nullable Serializable snapshot;
// allow the CollectionSnapshot to be serialized
private String role;
private @Nullable String role;
// "loaded" means the reference that is consistent
// with the current database state
private transient CollectionPersister loadedPersister;
private Object loadedKey;
private transient @Nullable CollectionPersister loadedPersister;
private @Nullable Object loadedKey;
// ATTRIBUTES USED ONLY DURING FLUSH CYCLE
@ -56,8 +60,8 @@ public final class CollectionEntry implements Serializable {
private transient boolean ignore;
// "current" means the reference that was found during flush()
private transient CollectionPersister currentPersister;
private transient Object currentKey;
private transient @Nullable CollectionPersister currentPersister;
private transient @Nullable Object currentKey;
/**
* For newly wrapped collections, or dereferenced collection wrappers
@ -88,7 +92,9 @@ public final class CollectionEntry implements Serializable {
//collection.clearDirty()
this.loadedKey = loadedKey;
setLoadedPersister( loadedPersister );
this.loadedPersister = loadedPersister;
this.role = ( loadedPersister == null ? null : loadedPersister.getRole() );
collection.setSnapshot( loadedKey, role, null );
@ -106,7 +112,8 @@ public final class CollectionEntry implements Serializable {
//collection.clearDirty()
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;
loadedKey = collection.getKey();
setLoadedPersister(
factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( collection.getRole() )
);
loadedPersister = factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( collection.getRole() );
this.role = ( loadedPersister == null ? null : loadedPersister.getRole() );
snapshot = collection.getStoredSnapshot();
}
@ -132,10 +138,10 @@ public final class CollectionEntry implements Serializable {
* @see #deserialize
*/
private CollectionEntry(
String role,
@Nullable String role,
Serializable snapshot,
Object loadedKey,
SessionFactoryImplementor factory) {
@Nullable SessionFactoryImplementor factory) {
this.role = role;
this.snapshot = snapshot;
this.loadedKey = loadedKey;
@ -176,7 +182,7 @@ public final class CollectionEntry implements Serializable {
if ( nonMutableChange ) {
throw new HibernateException(
"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 {
final CollectionPersister loadedPersister = getLoadedPersister();
snapshot = loadedPersister.isMutable()
snapshot = loadedPersister != null && loadedPersister.isMutable()
? collection.getSnapshot( loadedPersister )
: null;
collection.setSnapshot( loadedKey, role, snapshot );
final SharedSessionContractImplementor session = ((AbstractPersistentCollection<?>) collection).getSession();
if ( session.getLoadQueryInfluencers().effectivelyBatchLoadable( loadedPersister ) ) {
if ( loadedPersister != null && session.getLoadQueryInfluencers().effectivelyBatchLoadable( loadedPersister ) ) {
session.getPersistenceContextInternal()
.getBatchFetchQueue()
.removeBatchLoadableCollection( this );
@ -236,21 +242,21 @@ public final class CollectionEntry implements Serializable {
if ( resnapshot ) {
snapshot = loadedPersister == null || !loadedPersister.isMutable() ?
null :
collection.getSnapshot( loadedPersister ); //re-snapshot
collection.getSnapshot( NullnessUtil.castNonNull( loadedPersister ) ); //re-snapshot
}
collection.postAction();
}
public Object getKey() {
public @Nullable Object getKey() {
return getLoadedKey();
}
public String getRole() {
public @Nullable String getRole() {
return role;
}
public Serializable getSnapshot() {
public @Nullable Serializable getSnapshot() {
return snapshot;
}
@ -275,17 +281,17 @@ public final class CollectionEntry implements Serializable {
fromMerge = true;
}
private void setLoadedPersister(CollectionPersister persister) {
private void setLoadedPersister(@Nullable CollectionPersister persister) {
loadedPersister = persister;
setRole( persister == null ? null : persister.getRole() );
}
void afterDeserialize(SessionFactoryImplementor factory) {
void afterDeserialize(@Nullable SessionFactoryImplementor factory) {
if ( factory == null ) {
loadedPersister = null;
}
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;
}
public CollectionPersister getCurrentPersister() {
public @Nullable CollectionPersister getCurrentPersister() {
return currentPersister;
}
public void setCurrentPersister(CollectionPersister currentPersister) {
public void setCurrentPersister(@Nullable CollectionPersister currentPersister) {
this.currentPersister = currentPersister;
}
@ -349,26 +355,26 @@ public final class CollectionEntry implements Serializable {
* This is only available late during the flush
* cycle
*/
public Object getCurrentKey() {
public @Nullable Object getCurrentKey() {
return currentKey;
}
public void setCurrentKey(Object currentKey) {
public void setCurrentKey(@Nullable Object currentKey) {
this.currentKey = currentKey;
}
/**
* This is only available late during the flush cycle
*/
public CollectionPersister getLoadedPersister() {
public @Nullable CollectionPersister getLoadedPersister() {
return loadedPersister;
}
public Object getLoadedKey() {
public @Nullable Object getLoadedKey() {
return loadedKey;
}
public void setRole(String role) {
public void setRole(@Nullable String role) {
this.role = role;
}
@ -398,9 +404,10 @@ public final class CollectionEntry implements Serializable {
// does the collection already have
// it's own up-to-date snapshot?
final CollectionPersister loadedPersister = getLoadedPersister();
Serializable snapshot = getSnapshot();
return collection.wasInitialized() &&
( loadedPersister ==null || loadedPersister.isMutable() ) &&
collection.isSnapshotEmpty( getSnapshot() );
( loadedPersister == null || loadedPersister.isMutable() ) &&
(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.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Uniquely identifies a collection instance in a particular session.
*
@ -39,7 +41,7 @@ public final class CollectionKey implements Serializable {
private CollectionKey(
String role,
Object key,
@Nullable Object key,
Type keyType,
SessionFactoryImplementor factory) {
this.role = role;
@ -77,7 +79,7 @@ public final class CollectionKey implements Serializable {
}
@Override
public boolean equals(final Object other) {
public boolean equals(final @Nullable Object other) {
if ( this == other ) {
return true;
}
@ -127,7 +129,8 @@ public final class CollectionKey implements Serializable {
(String) ois.readObject(),
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.spi.AppliedGraph;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.util.NullnessUtil;
import org.jboss.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Think of this as the composite modeling of a graph
* and the semantic.
@ -33,8 +36,8 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
private final boolean allowOverwrite;
private GraphSemantic semantic;
private RootGraphImplementor<?> graph;
private @Nullable GraphSemantic semantic;
private @Nullable RootGraphImplementor<?> graph;
/**
* @implSpec I explicitly made this constructor package protected
@ -59,12 +62,12 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
}
@Override
public GraphSemantic getSemantic() {
public @Nullable GraphSemantic getSemantic() {
return semantic;
}
@Override
public RootGraphImplementor<?> getGraph() {
public @Nullable RootGraphImplementor<?> getGraph() {
return graph;
}
@ -75,7 +78,7 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
* @throws IllegalArgumentException Thrown if the semantic is null
* @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 ) {
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 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() ) {
return;
}
@ -138,6 +141,7 @@ public class EffectiveEntityGraph implements AppliedGraph, Serializable {
applyGraph( fetchHint, GraphSemantic.FETCH );
}
else {
assert loadHint != null : "@AssumeAssertion(nullness)";
applyGraph( loadHint, GraphSemantic.LOAD );
}
}

View File

@ -15,6 +15,8 @@ import org.hibernate.AssertionFailure;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* 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
@ -44,7 +46,7 @@ public final class EntityKey implements Serializable {
* @param id The entity id
* @param persister The entity persister
*/
public EntityKey(Object id, EntityPersister persister) {
public EntityKey(@Nullable Object id, EntityPersister persister) {
this.persister = persister;
if ( id == null ) {
throw new AssertionFailure( "null identifier (" + persister.getEntityName() + ")" );
@ -82,7 +84,7 @@ public final class EntityKey implements Serializable {
}
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if ( this == other ) {
return true;
}

View File

@ -14,6 +14,10 @@ import java.io.Serializable;
import org.hibernate.pretty.MessageHelper;
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
* by some unique property reference, as opposed to identifier.
@ -41,7 +45,7 @@ public class EntityUniqueKey implements Serializable {
this.entityName = entityName;
this.key = key;
this.keyType = keyType;
this.hashCode = generateHashCode( factory );
this.hashCode = generateHashCode( entityName, uniqueKeyName, keyType, key, factory );
}
public String getEntityName() {
@ -56,7 +60,7 @@ public class EntityUniqueKey implements Serializable {
return uniqueKeyName;
}
public int generateHashCode(SessionFactoryImplementor factory) {
public static int generateHashCode(String entityName, String uniqueKeyName, Type keyType, Object key, SessionFactoryImplementor factory) {
int result = 17;
result = 37 * result + entityName.hashCode();
result = 37 * result + uniqueKeyName.hashCode();
@ -70,7 +74,10 @@ public class EntityUniqueKey implements Serializable {
}
@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;
return that != null && that.entityName.equals( entityName )
&& 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.internal.util.collections.CollectionHelper;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A list of {@link Executable executeble actions}. Responsible for
* {@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 Sorter<E> sorter;
private final @Nullable Sorter<E> sorter;
private final boolean requiresSorting;
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
* 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.
@ -296,9 +298,10 @@ public class ExecutableList<E extends ComparableExecutable>
oos.writeInt( -1 );
}
else {
final Set<Serializable> qs = querySpaces;
oos.writeInt( querySpaces.size() );
// 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() );
}
}
@ -329,10 +332,12 @@ public class ExecutableList<E extends ComparableExecutable>
this.querySpaces = null;
}
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++ ) {
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.checkerframework.checker.nullness.qual.Nullable;
/**
* For persistence operations (INSERT, UPDATE, DELETE) what style of
* determining results (success/failure) is to be used.
@ -54,7 +56,7 @@ public enum ExecuteUpdateResultCheckStyle {
return name;
}
public static ExecuteUpdateResultCheckStyle fromResultCheckStyle(ResultCheckStyle style) {
public static @Nullable ExecuteUpdateResultCheckStyle fromResultCheckStyle(ResultCheckStyle style) {
switch (style) {
case 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 ) ) {
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;
}
}

View File

@ -13,6 +13,8 @@ import java.util.Set;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Represents the definition of a {@link org.hibernate.Filter filter}.
* 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.
*/
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.defaultFilterCondition = defaultCondition;
if ( explicitParamJaMappings != null ) {
@ -59,7 +61,9 @@ public class FilterDefinition implements Serializable {
* @return The parameters named by this configuration.
*/
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.
*/
public JdbcMapping getParameterJdbcMapping(String parameterName) {
public @Nullable JdbcMapping getParameterJdbcMapping(String parameterName) {
return explicitParamJaMappings.get( parameterName );
}

View File

@ -12,6 +12,8 @@ import org.hibernate.internal.CoreLogging;
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 new transient instance or a previously persistent transient instance.
@ -23,7 +25,7 @@ import org.jboss.logging.Logger;
public class IdentifierValue implements UnsavedValueStrategy {
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
@ -73,13 +75,13 @@ public class IdentifierValue implements UnsavedValueStrategy {
*/
public static final IdentifierValue NULL = new IdentifierValue() {
@Override
public Boolean isUnsaved(Object id) {
public Boolean isUnsaved(@Nullable Object id) {
LOG.trace( "ID unsaved-value strategy NULL" );
return id == null;
}
@Override
public Serializable getDefaultValue(Object currentValue) {
public @Nullable Serializable getDefaultValue(Object currentValue) {
return null;
}
@ -94,13 +96,13 @@ public class IdentifierValue implements UnsavedValueStrategy {
*/
public static final IdentifierValue UNDEFINED = new IdentifierValue() {
@Override
public Boolean isUnsaved(Object id) {
public @Nullable Boolean isUnsaved(Object id) {
LOG.trace( "ID unsaved-value strategy UNDEFINED" );
return null;
}
@Override
public Serializable getDefaultValue(Object currentValue) {
public @Nullable Serializable getDefaultValue(Object currentValue) {
return null;
}
@ -126,13 +128,13 @@ public class IdentifierValue implements UnsavedValueStrategy {
* Does the given identifier belong to a new instance?
*/
@Override
public Boolean isUnsaved(Object id) {
public @Nullable Boolean isUnsaved(@Nullable Object id) {
LOG.tracev( "ID unsaved-value: {0}", value );
return id == null || id.equals( value );
}
@Override
public Object getDefaultValue(Object currentValue) {
public @Nullable Object getDefaultValue(@Nullable Object currentValue) {
return value;
}

View File

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

View File

@ -11,6 +11,8 @@ import org.hibernate.engine.internal.ManagedTypeHelper;
import org.hibernate.proxy.HibernateProxy;
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}.
*
@ -22,46 +24,46 @@ import org.hibernate.proxy.ProxyConfiguration;
@Internal
public interface PrimeAmongSecondarySupertypes {
default ManagedEntity asManagedEntity() {
default @Nullable ManagedEntity asManagedEntity() {
return null;
}
default PersistentAttributeInterceptable asPersistentAttributeInterceptable() {
default @Nullable PersistentAttributeInterceptable asPersistentAttributeInterceptable() {
return null;
}
default SelfDirtinessTracker asSelfDirtinessTracker() {
default @Nullable SelfDirtinessTracker asSelfDirtinessTracker() {
return null;
}
//Included for consistency but doesn't seem to be used?
default Managed asManaged() {
default @Nullable Managed asManaged() {
return null;
}
//Included for consistency but doesn't seem to be used?
default ManagedComposite asManagedComposite() {
default @Nullable ManagedComposite asManagedComposite() {
return null;
}
//Included for consistency but doesn't seem to be used?
default ManagedMappedSuperclass asManagedMappedSuperclass() {
default @Nullable ManagedMappedSuperclass asManagedMappedSuperclass() {
return null;
}
default CompositeOwner asCompositeOwner() {
default @Nullable CompositeOwner asCompositeOwner() {
return null;
}
default CompositeTracker asCompositeTracker() {
default @Nullable CompositeTracker asCompositeTracker() {
return null;
}
default HibernateProxy asHibernateProxy() {
default @Nullable HibernateProxy asHibernateProxy() {
return null;
}
default ProxyConfiguration asProxyConfiguration() {
default @Nullable ProxyConfiguration asProxyConfiguration() {
return null;
}

View File

@ -68,6 +68,7 @@ import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
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
@ -165,7 +166,7 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
@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 );
}
@ -853,22 +854,22 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
@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 );
}
@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 );
}
@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 );
}
@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 );
}

View File

@ -51,6 +51,7 @@ import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* This helper class allows decorating a Session instance, while the
@ -809,22 +810,22 @@ public class SessionLazyDelegator implements Session {
}
@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 );
}
@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 );
}
@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 );
}
@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 );
}

View File

@ -10,6 +10,7 @@ import java.util.Set;
import java.util.UUID;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.TransactionRequiredException;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
@ -307,7 +308,7 @@ public interface SharedSessionContractImplementor
* @param entityName optional entity name
* @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},

View File

@ -11,6 +11,8 @@ import jakarta.persistence.FlushModeType;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
@ -413,7 +415,7 @@ public class SharedSessionDelegatorBaseImpl implements SharedSessionContractImpl
}
@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 );
}

View File

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

View File

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

View File

@ -8,6 +8,8 @@ package org.hibernate.graph.spi;
import org.hibernate.graph.GraphSemantic;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Contract for anything a fetch/load graph can be applied
*
@ -17,10 +19,10 @@ public interface AppliedGraph {
/**
* The applied graph
*/
RootGraphImplementor<?> getGraph();
@Nullable RootGraphImplementor<?> getGraph();
/**
* 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;
}
public static String join(String seperator, String[] strings) {
public static String join(String separator, String[] strings) {
int length = strings.length;
if ( length == 0 ) {
return "";
@ -54,7 +54,7 @@ public final class StringHelper {
StringBuilder buf = new StringBuilder( length * firstStringLength )
.append( strings[0] );
for ( int i = 1; i < length; i++ ) {
buf.append( seperator ).append( strings[i] );
buf.append( separator ).append( strings[i] );
}
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.type.descriptor.java.JavaType;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Base descriptor, within the mapping model, for any part of the
* application's domain model: an attribute, an entity identifier,
@ -200,7 +202,7 @@ public interface ModelPart extends MappingModelExpressible {
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)
return Objects.deepEquals( one, other );
}

View File

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