Migrate to JSpecify annotations for nullability constraints.

Closes: #4874
This commit is contained in:
Christoph Strobl
2025-03-12 11:06:41 +01:00
committed by Mark Paluch
parent 6531bc792b
commit 13ff2d602c
422 changed files with 3143 additions and 1761 deletions

View File

@@ -353,8 +353,76 @@
</dependencies>
<build>
<profiles>
<profile>
<id>nullaway</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
</path>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh}</version>
</path>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${errorprone}</version>
</path>
<path>
<groupId>com.uber.nullaway</groupId>
<artifactId>nullaway</artifactId>
<version>${nullaway}</version>
</path>
</annotationProcessorPaths>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<compilerArgs>
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
<arg>-Xplugin:ErrorProne -XepDisableAllChecks -Xep:NullAway:ERROR -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:TreatGeneratedAsUnannotated=true -XepOpt:NullAway:CustomContractAnnotations=org.springframework.lang.Contract</arg>
</compilerArgs>
</configuration>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>

View File

@@ -20,9 +20,10 @@ import java.util.Arrays;
import org.bson.Document;
import org.bson.codecs.DocumentCodec;
import org.bson.codecs.configuration.CodecRegistry;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -31,8 +32,7 @@ import org.springframework.util.StringUtils;
* A {@link MongoExpression} using the {@link ParameterBindingDocumentCodec} for parsing a raw ({@literal json})
* expression. The expression will be wrapped within <code>{ ... }</code> if necessary. The actual parsing and parameter
* binding of placeholders like {@code ?0} is delayed upon first call on the target {@link Document} via
* {@link #toDocument()}.
* <br />
* {@link #toDocument()}. <br />
*
* <pre class="code">
* $toUpper : $name -> { '$toUpper' : '$name' }
@@ -55,7 +55,7 @@ public class BindableMongoExpression implements MongoExpression {
private final @Nullable CodecRegistryProvider codecRegistryProvider;
private final @Nullable Object[] args;
private final Object @Nullable [] args;
private final Lazy<Document> target;
@@ -63,9 +63,9 @@ public class BindableMongoExpression implements MongoExpression {
* Create a new instance of {@link BindableMongoExpression}.
*
* @param expression must not be {@literal null}.
* @param args can be {@literal null}.
* @param args must not be {@literal null} but may contain {@literal null} elements.
*/
public BindableMongoExpression(String expression, @Nullable Object[] args) {
public BindableMongoExpression(String expression, Object @Nullable [] args) {
this(expression, null, args);
}
@@ -74,10 +74,10 @@ public class BindableMongoExpression implements MongoExpression {
*
* @param expression must not be {@literal null}.
* @param codecRegistryProvider can be {@literal null}.
* @param args can be {@literal null}.
* @param args must not be {@literal null} but may contain {@literal null} elements.
*/
public BindableMongoExpression(String expression, @Nullable CodecRegistryProvider codecRegistryProvider,
@Nullable Object[] args) {
Object @Nullable [] args) {
Assert.notNull(expression, "Expression must not be null");
@@ -93,6 +93,7 @@ public class BindableMongoExpression implements MongoExpression {
* @param codecRegistry must not be {@literal null}.
* @return new instance of {@link BindableMongoExpression}.
*/
@Contract("_ -> new")
public BindableMongoExpression withCodecRegistry(CodecRegistry codecRegistry) {
return new BindableMongoExpression(expressionString, () -> codecRegistry, args);
}
@@ -103,6 +104,7 @@ public class BindableMongoExpression implements MongoExpression {
* @param args must not be {@literal null}.
* @return new instance of {@link BindableMongoExpression}.
*/
@Contract("_ -> new")
public BindableMongoExpression bind(Object... args) {
return new BindableMongoExpression(expressionString, codecRegistryProvider, args);
}
@@ -139,7 +141,7 @@ public class BindableMongoExpression implements MongoExpression {
private static String wrapJsonIfNecessary(String json) {
if(!StringUtils.hasText(json)) {
if (!StringUtils.hasText(json)) {
return json;
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import com.mongodb.MongoBulkWriteException;
@@ -40,10 +41,10 @@ public class BulkOperationException extends DataAccessException {
/**
* Creates a new {@link BulkOperationException} with the given message and source {@link MongoBulkWriteException}.
*
* @param message must not be {@literal null}.
* @param message can be {@literal null}.
* @param source must not be {@literal null}.
*/
public BulkOperationException(String message, MongoBulkWriteException source) {
public BulkOperationException(@Nullable String message, MongoBulkWriteException source) {
super(message, source);

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.lang.Nullable;
/**
* {@link NonTransientDataAccessException} specific to MongoDB {@link com.mongodb.session.ClientSession} related data

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Default implementation of {@link MongoTransactionOptions} using {@literal mongo:} as {@link #getLabelPrefix() label
@@ -42,9 +42,8 @@ enum DefaultMongoTransactionOptionsResolver implements MongoTransactionOptionsRe
return SimpleMongoTransactionOptions.of(options);
}
@Nullable
@Override
public String getLabelPrefix() {
public @Nullable String getLabelPrefix() {
return PREFIX;
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -29,8 +29,7 @@ import com.mongodb.client.MongoDatabase;
/**
* Helper class for managing a {@link MongoDatabase} instances via {@link MongoDatabaseFactory}. Used for obtaining
* {@link ClientSession session bound} resources, such as {@link MongoDatabase} and
* {@link com.mongodb.client.MongoCollection} suitable for transactional usage.
* <br />
* {@link com.mongodb.client.MongoCollection} suitable for transactional usage. <br />
* <strong>Note:</strong> Intended for internal usage only.
*
* @author Christoph Strobl
@@ -42,8 +41,7 @@ public class MongoDatabaseUtils {
/**
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory} using
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
* <br />
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}. <br />
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -55,8 +53,7 @@ public class MongoDatabaseUtils {
}
/**
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory}.
* <br />
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory}. <br />
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -70,8 +67,7 @@ public class MongoDatabaseUtils {
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDatabaseFactory factory} using
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
* <br />
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}. <br />
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -139,8 +135,7 @@ public class MongoDatabaseUtils {
return resourceHolder != null && resourceHolder.hasActiveTransaction();
}
@Nullable
private static ClientSession doGetSession(MongoDatabaseFactory dbFactory,
private static @Nullable ClientSession doGetSession(MongoDatabaseFactory dbFactory,
SessionSynchronization sessionSynchronization) {
MongoResourceHolder resourceHolder = (MongoResourceHolder) TransactionSynchronizationManager.getResource(dbFactory);

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.ResourceHolderSupport;
@@ -23,8 +23,7 @@ import com.mongodb.client.ClientSession;
/**
* MongoDB specific {@link ResourceHolderSupport resource holder}, wrapping a {@link ClientSession}.
* {@link MongoTransactionManager} binds instances of this class to the thread.
* <br />
* {@link MongoTransactionManager} binds instances of this class to the thread. <br />
* <strong>Note:</strong> Intended for internal usage only.
*
* @author Christoph Strobl

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* A specific {@link ClientSessionException} related to issues with a transaction such as aborted or non existing

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSystemException;
@@ -36,19 +36,15 @@ import com.mongodb.client.ClientSession;
/**
* A {@link org.springframework.transaction.PlatformTransactionManager} implementation that manages
* {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}.
* <br />
* Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread.
* <br />
* {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}. <br />
* Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread. <br />
* {@link TransactionDefinition#isReadOnly() Readonly} transactions operate on a {@link ClientSession} and enable causal
* consistency, and also {@link ClientSession#startTransaction() start}, {@link ClientSession#commitTransaction()
* commit} or {@link ClientSession#abortTransaction() abort} a transaction.
* <br />
* commit} or {@link ClientSession#abortTransaction() abort} a transaction. <br />
* Application code is required to retrieve the {@link com.mongodb.client.MongoDatabase} via
* {@link MongoDatabaseUtils#getDatabase(MongoDatabaseFactory)} instead of a standard
* {@link MongoDatabaseFactory#getMongoDatabase()} call. Spring classes such as
* {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly.
* <br />
* {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly. <br />
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. One may override
* {@link #doCommit(MongoTransactionObject)} to implement the
* <a href="https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation">Retry Commit Operation</a>
@@ -80,7 +76,9 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
* @see #setTransactionSynchronization(int)
*/
public MongoTransactionManager() {
this.transactionOptionsResolver = MongoTransactionOptionsResolver.defaultResolver();
this.options = MongoTransactionOptions.NONE;
}
/**
@@ -151,7 +149,8 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
}
try {
MongoTransactionOptions mongoTransactionOptions = transactionOptionsResolver.resolve(definition).mergeWith(options);
MongoTransactionOptions mongoTransactionOptions = transactionOptionsResolver.resolve(definition)
.mergeWith(options);
mongoTransactionObject.startTransaction(mongoTransactionOptions.toDriverOptions());
} catch (MongoException ex) {
throw new TransactionSystemException(String.format("Could not start Mongo transaction for session %s.",
@@ -206,6 +205,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
* By default those labels are ignored, nevertheless one might check for
* {@link MongoException#UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL transient commit errors labels} and retry the the
* commit. <br />
*
* <pre>
* <code>
* int retries = 3;
@@ -302,8 +302,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
*
* @return can be {@literal null}.
*/
@Nullable
public MongoDatabaseFactory getDatabaseFactory() {
public @Nullable MongoDatabaseFactory getDatabaseFactory() {
return databaseFactory;
}
@@ -461,8 +460,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
}
}
@Nullable
public ClientSession getSession() {
public @Nullable ClientSession getSession() {
return resourceHolder != null ? resourceHolder.getSession() : null;
}

View File

@@ -19,15 +19,16 @@ import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.ReadConcernAware;
import org.springframework.data.mongodb.core.ReadPreferenceAware;
import org.springframework.data.mongodb.core.WriteConcernAware;
import org.springframework.lang.Nullable;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import org.springframework.lang.Contract;
/**
* Options to be applied within a specific transaction scope.
@@ -43,27 +44,23 @@ public interface MongoTransactionOptions
*/
MongoTransactionOptions NONE = new MongoTransactionOptions() {
@Nullable
@Override
public Duration getMaxCommitTime() {
public @Nullable Duration getMaxCommitTime() {
return null;
}
@Nullable
@Override
public ReadConcern getReadConcern() {
public @Nullable ReadConcern getReadConcern() {
return null;
}
@Nullable
@Override
public ReadPreference getReadPreference() {
public @Nullable ReadPreference getReadPreference() {
return null;
}
@Nullable
@Override
public WriteConcern getWriteConcern() {
public @Nullable WriteConcern getWriteConcern() {
return null;
}
};
@@ -76,6 +73,7 @@ public interface MongoTransactionOptions
* @return new instance of {@link MongoTransactionOptions} or this if {@literal fallbackOptions} is {@literal null} or
* {@link #NONE}.
*/
@Contract("null -> this")
default MongoTransactionOptions mergeWith(@Nullable MongoTransactionOptions fallbackOptions) {
if (fallbackOptions == null || MongoTransactionOptions.NONE.equals(fallbackOptions)) {
@@ -84,30 +82,26 @@ public interface MongoTransactionOptions
return new MongoTransactionOptions() {
@Nullable
@Override
public Duration getMaxCommitTime() {
public @Nullable Duration getMaxCommitTime() {
return MongoTransactionOptions.this.hasMaxCommitTime() ? MongoTransactionOptions.this.getMaxCommitTime()
: fallbackOptions.getMaxCommitTime();
}
@Nullable
@Override
public ReadConcern getReadConcern() {
public @Nullable ReadConcern getReadConcern() {
return MongoTransactionOptions.this.hasReadConcern() ? MongoTransactionOptions.this.getReadConcern()
: fallbackOptions.getReadConcern();
}
@Nullable
@Override
public ReadPreference getReadPreference() {
public @Nullable ReadPreference getReadPreference() {
return MongoTransactionOptions.this.hasReadPreference() ? MongoTransactionOptions.this.getReadPreference()
: fallbackOptions.getReadPreference();
}
@Nullable
@Override
public WriteConcern getWriteConcern() {
public @Nullable WriteConcern getWriteConcern() {
return MongoTransactionOptions.this.hasWriteConcern() ? MongoTransactionOptions.this.getWriteConcern()
: fallbackOptions.getWriteConcern();
}
@@ -128,8 +122,8 @@ public interface MongoTransactionOptions
* @return MongoDB driver native {@link TransactionOptions}.
* @see MongoTransactionOptions#map(Function)
*/
@Nullable
default TransactionOptions toDriverOptions() {
@SuppressWarnings("NullAway")
default @Nullable TransactionOptions toDriverOptions() {
return map(it -> {
@@ -157,7 +151,7 @@ public interface MongoTransactionOptions
/**
* Factory method to wrap given MongoDB driver native {@link TransactionOptions} into {@link MongoTransactionOptions}.
*
* @param options
* @param options can be {@literal null}.
* @return {@link MongoTransactionOptions#NONE} if given object is {@literal null}.
*/
static MongoTransactionOptions of(@Nullable TransactionOptions options) {
@@ -168,35 +162,30 @@ public interface MongoTransactionOptions
return new MongoTransactionOptions() {
@Nullable
@Override
public Duration getMaxCommitTime() {
public @Nullable Duration getMaxCommitTime() {
Long millis = options.getMaxCommitTime(TimeUnit.MILLISECONDS);
return millis != null ? Duration.ofMillis(millis) : null;
}
@Nullable
@Override
public ReadConcern getReadConcern() {
public @Nullable ReadConcern getReadConcern() {
return options.getReadConcern();
}
@Nullable
@Override
public ReadPreference getReadPreference() {
public @Nullable ReadPreference getReadPreference() {
return options.getReadPreference();
}
@Nullable
@Override
public WriteConcern getWriteConcern() {
public @Nullable WriteConcern getWriteConcern() {
return options.getWriteConcern();
}
@Nullable
@Override
public TransactionOptions toDriverOptions() {
public @Nullable TransactionOptions toDriverOptions() {
return options;
}
};

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.reactive.ReactiveResourceSynchronization;
import org.springframework.transaction.reactive.TransactionSynchronization;
@@ -35,8 +35,7 @@ import com.mongodb.reactivestreams.client.MongoDatabase;
/**
* Helper class for managing reactive {@link MongoDatabase} instances via {@link ReactiveMongoDatabaseFactory}. Used for
* obtaining {@link ClientSession session bound} resources, such as {@link MongoDatabase} and {@link MongoCollection}
* suitable for transactional usage.
* <br />
* suitable for transactional usage. <br />
* <strong>Note:</strong> Intended for internal usage only.
*
* @author Mark Paluch
@@ -74,8 +73,7 @@ public class ReactiveMongoDatabaseUtils {
/**
* Obtain the default {@link MongoDatabase database} form the given {@link ReactiveMongoDatabaseFactory factory} using
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
* <br />
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}. <br />
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -103,32 +101,32 @@ public class ReactiveMongoDatabaseUtils {
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link ReactiveMongoDatabaseFactory
* factory} using {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
* <br />
* factory} using {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}. <br />
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
* @param dbName the name of the {@link MongoDatabase} to get.
* @param dbName the name of the {@link MongoDatabase} to get. If {@literal null} the default database of the
* {@link ReactiveMongoDatabaseFactory}.
* @param factory the {@link ReactiveMongoDatabaseFactory} to get the {@link MongoDatabase} from.
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
*/
public static Mono<MongoDatabase> getDatabase(String dbName, ReactiveMongoDatabaseFactory factory) {
public static Mono<MongoDatabase> getDatabase(@Nullable String dbName, ReactiveMongoDatabaseFactory factory) {
return doGetMongoDatabase(dbName, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
}
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link ReactiveMongoDatabaseFactory
* factory}.
* <br />
* factory}. <br />
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
* @param dbName the name of the {@link MongoDatabase} to get.
* @param dbName the name of the {@link MongoDatabase} to get. If {@literal null} the default database of the *
* {@link ReactiveMongoDatabaseFactory}.
* @param factory the {@link ReactiveMongoDatabaseFactory} to get the {@link MongoDatabase} from.
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
*/
public static Mono<MongoDatabase> getDatabase(String dbName, ReactiveMongoDatabaseFactory factory,
public static Mono<MongoDatabase> getDatabase(@Nullable String dbName, ReactiveMongoDatabaseFactory factory,
SessionSynchronization sessionSynchronization) {
return doGetMongoDatabase(dbName, factory, sessionSynchronization);
}

View File

@@ -15,16 +15,15 @@
*/
package org.springframework.data.mongodb;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.ResourceHolderSupport;
import com.mongodb.reactivestreams.client.ClientSession;
/**
* MongoDB specific resource holder, wrapping a {@link ClientSession}. {@link ReactiveMongoTransactionManager} binds
* instances of this class to the subscriber context.
* <br />
* instances of this class to the subscriber context. <br />
* <strong>Note:</strong> Intended for internal usage only.
*
* @author Mark Paluch
@@ -103,8 +102,7 @@ class ReactiveMongoResourceHolder extends ResourceHolderSupport {
* @param session
* @return
*/
@Nullable
public ClientSession setSessionIfAbsent(@Nullable ClientSession session) {
public @Nullable ClientSession setSessionIfAbsent(@Nullable ClientSession session) {
if (!hasSession()) {
setSession(session);

View File

@@ -17,8 +17,8 @@ package org.springframework.data.mongodb;
import reactor.core.publisher.Mono;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSystemException;
@@ -64,7 +64,7 @@ import com.mongodb.reactivestreams.client.ClientSession;
public class ReactiveMongoTransactionManager extends AbstractReactiveTransactionManager implements InitializingBean {
private @Nullable ReactiveMongoDatabaseFactory databaseFactory;
private @Nullable MongoTransactionOptions options;
private MongoTransactionOptions options;
private final MongoTransactionOptionsResolver transactionOptionsResolver;
/**
@@ -79,7 +79,9 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
* @see #setDatabaseFactory(ReactiveMongoDatabaseFactory)
*/
public ReactiveMongoTransactionManager() {
this.transactionOptionsResolver = MongoTransactionOptionsResolver.defaultResolver();
this.options = MongoTransactionOptions.NONE;
}
/**
@@ -98,7 +100,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
* starting a new transaction.
*
* @param databaseFactory must not be {@literal null}.
* @param options can be {@literal null}.
* @param options can be {@literal null}. Will default {@link MongoTransactionOptions#NONE} if {@literal null}.
*/
public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory,
@Nullable TransactionOptions options) {
@@ -112,7 +114,8 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
*
* @param databaseFactory must not be {@literal null}.
* @param transactionOptionsResolver must not be {@literal null}.
* @param defaultTransactionOptions can be {@literal null}.
* @param defaultTransactionOptions can be {@literal null}. Will default {@link MongoTransactionOptions#NONE} if
* {@literal null}.
* @since 4.3
*/
public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory,
@@ -124,7 +127,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
this.databaseFactory = databaseFactory;
this.transactionOptionsResolver = transactionOptionsResolver;
this.options = defaultTransactionOptions;
this.options = defaultTransactionOptions != null ? defaultTransactionOptions : MongoTransactionOptions.NONE;
}
@Override
@@ -318,8 +321,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
*
* @return can be {@literal null}.
*/
@Nullable
public ReactiveMongoDatabaseFactory getDatabaseFactory() {
public @Nullable ReactiveMongoDatabaseFactory getDatabaseFactory() {
return databaseFactory;
}
@@ -470,8 +472,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
}
}
@Nullable
public ClientSession getSession() {
public @Nullable ClientSession getSession() {
return resourceHolder != null ? resourceHolder.getSession() : null;
}

View File

@@ -22,8 +22,8 @@ import java.util.function.BiFunction;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jspecify.annotations.Nullable;
import org.springframework.core.MethodClassKey;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
@@ -34,8 +34,7 @@ import com.mongodb.session.ClientSession;
/**
* {@link MethodInterceptor} implementation looking up and invoking an alternative target method having
* {@link ClientSession} as its first argument. This allows seamless integration with the existing code base.
* <br />
* {@link ClientSession} as its first argument. This allows seamless integration with the existing code base. <br />
* The {@link MethodInterceptor} is aware of methods on {@code MongoCollection} that my return new instances of itself
* like (eg. {@link com.mongodb.reactivestreams.client.MongoCollection#withWriteConcern(WriteConcern)} and decorate them
* if not already proxied.
@@ -95,13 +94,13 @@ public class SessionAwareMethodInterceptor<D, C> implements MethodInterceptor {
this.sessionType = sessionType;
}
@Nullable
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
public @Nullable Object invoke(MethodInvocation methodInvocation) throws Throwable {
if (requiresDecoration(methodInvocation.getMethod())) {
Object target = methodInvocation.proceed();
Assert.notNull(target, "invocation target was null");
if (target instanceof Proxy) {
return target;
}

View File

@@ -21,7 +21,7 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.mongodb.Function;
@@ -41,10 +41,10 @@ class SimpleMongoTransactionOptions implements MongoTransactionOptions {
static final Set<String> KNOWN_KEYS = Arrays.stream(OptionKey.values()).map(OptionKey::getKey)
.collect(Collectors.toSet());
private final Duration maxCommitTime;
private final ReadConcern readConcern;
private final ReadPreference readPreference;
private final WriteConcern writeConcern;
private final @Nullable Duration maxCommitTime;
private final @Nullable ReadConcern readConcern;
private final @Nullable ReadPreference readPreference;
private final @Nullable WriteConcern writeConcern;
static SimpleMongoTransactionOptions of(Map<String, String> options) {
return new SimpleMongoTransactionOptions(options);
@@ -58,27 +58,23 @@ class SimpleMongoTransactionOptions implements MongoTransactionOptions {
this.writeConcern = doGetWriteConcern(options);
}
@Nullable
@Override
public Duration getMaxCommitTime() {
public @Nullable Duration getMaxCommitTime() {
return maxCommitTime;
}
@Nullable
@Override
public ReadConcern getReadConcern() {
public @Nullable ReadConcern getReadConcern() {
return readConcern;
}
@Nullable
@Override
public ReadPreference getReadPreference() {
public @Nullable ReadPreference getReadPreference() {
return readPreference;
}
@Nullable
@Override
public WriteConcern getWriteConcern() {
public @Nullable WriteConcern getWriteConcern() {
return writeConcern;
}
@@ -89,8 +85,7 @@ class SimpleMongoTransactionOptions implements MongoTransactionOptions {
+ ", readPreference=" + readPreference + ", writeConcern=" + writeConcern + '}';
}
@Nullable
private static Duration doGetMaxCommitTime(Map<String, String> options) {
private static @Nullable Duration doGetMaxCommitTime(Map<String, String> options) {
return getValue(options, OptionKey.MAX_COMMIT_TIME, value -> {
@@ -100,18 +95,15 @@ class SimpleMongoTransactionOptions implements MongoTransactionOptions {
});
}
@Nullable
private static ReadConcern doGetReadConcern(Map<String, String> options) {
private static @Nullable ReadConcern doGetReadConcern(Map<String, String> options) {
return getValue(options, OptionKey.READ_CONCERN, value -> new ReadConcern(ReadConcernLevel.fromString(value)));
}
@Nullable
private static ReadPreference doGetReadPreference(Map<String, String> options) {
private static @Nullable ReadPreference doGetReadPreference(Map<String, String> options) {
return getValue(options, OptionKey.READ_PREFERENCE, ReadPreference::valueOf);
}
@Nullable
private static WriteConcern doGetWriteConcern(Map<String, String> options) {
private static @Nullable WriteConcern doGetWriteConcern(Map<String, String> options) {
return getValue(options, OptionKey.WRITE_CONCERN, value -> {
@@ -123,8 +115,8 @@ class SimpleMongoTransactionOptions implements MongoTransactionOptions {
});
}
@Nullable
private static <T> T getValue(Map<String, String> options, OptionKey key, Function<String, T> convertFunction) {
private static <T> @Nullable T getValue(Map<String, String> options, OptionKey key,
Function<String, T> convertFunction) {
String value = options.get(key.getKey());
return value != null ? convertFunction.apply(value) : null;

View File

@@ -17,7 +17,7 @@ package org.springframework.data.mongodb;
import java.time.Duration;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* MongoDB-specific transaction metadata.

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.transaction.TransactionDefinition;
/**

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;
public class UncategorizedMongoDbException extends UncategorizedDataAccessException {

View File

@@ -17,11 +17,11 @@ package org.springframework.data.mongodb.aot;
import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
import org.springframework.data.util.ReactiveWrappers;
import org.springframework.data.util.ReactiveWrappers.ReactiveLibrary;
import org.springframework.data.util.TypeUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**

View File

@@ -15,11 +15,11 @@
*/
package org.springframework.data.mongodb.aot;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.core.ResolvableType;
import org.springframework.data.aot.ManagedTypesBeanRegistrationAotProcessor;
import org.springframework.data.mongodb.MongoManagedTypes;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**

View File

@@ -15,10 +15,11 @@
*/
package org.springframework.data.mongodb.aot;
import static org.springframework.data.mongodb.aot.MongoAotPredicates.*;
import static org.springframework.data.mongodb.aot.MongoAotPredicates.isReactorPresent;
import java.util.Arrays;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -31,7 +32,6 @@ import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterConvertC
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeSaveCallback;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import com.mongodb.MongoClientSettings;

View File

@@ -17,7 +17,7 @@ package org.springframework.data.mongodb.config;
import java.beans.PropertyEditorSupport;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.ConnectionString;

View File

@@ -21,6 +21,8 @@ import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -56,7 +58,6 @@ import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCre
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -76,6 +77,7 @@ import org.w3c.dom.Element;
* @author Zied Yaich
* @author Tomasz Forys
*/
@NullUnmarked
public class MappingMongoConverterParser implements BeanDefinitionParser {
private static final String BASE_PACKAGE = "base-package";
@@ -157,8 +159,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
return null;
}
@Nullable
private BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) {
private @Nullable BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) {
String disableValidation = element.getAttribute("disable-validation");
boolean validationDisabled = StringUtils.hasText(disableValidation) && Boolean.parseBoolean(disableValidation);
@@ -291,8 +292,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
}
}
@Nullable
private BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
private @Nullable BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
List<Element> customConvertersElements = DomUtils.getChildElementsByTagName(element, "custom-converters");
@@ -354,8 +354,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
return classes;
}
@Nullable
public BeanMetadataElement parseConverter(Element element, ParserContext parserContext) {
public @Nullable BeanMetadataElement parseConverter(Element element, ParserContext parserContext) {
String converterRef = element.getAttribute("ref");
if (StringUtils.hasText(converterRef)) {

View File

@@ -18,6 +18,8 @@ package org.springframework.data.mongodb.config;
import static org.springframework.data.config.ParsingUtils.*;
import static org.springframework.data.mongodb.config.BeanNames.*;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -29,7 +31,6 @@ import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDef
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAuditingEntityCallback;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -42,6 +43,7 @@ import org.w3c.dom.Element;
* @author Oliver Gierke
* @author Mark Paluch
*/
@NullUnmarked
public class MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
private static boolean PROJECT_REACTOR_AVAILABLE = ClassUtils.isPresent("reactor.core.publisher.Mono",

View File

@@ -35,6 +35,7 @@ import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -52,7 +53,7 @@ public abstract class MongoConfigurationSupport {
/**
* Return the name of the database to connect to.
*
* @return must not be {@literal null}.
* @return never {@literal null}.
*/
protected abstract String getDatabaseName();
@@ -76,7 +77,7 @@ public abstract class MongoConfigurationSupport {
* Creates a {@link MongoMappingContext} equipped with entity classes scanned from the mapping base package.
*
* @see #getMappingBasePackages()
* @return
* @return never {@literal null}.
*/
@Bean
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions,
@@ -172,8 +173,10 @@ public abstract class MongoConfigurationSupport {
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
initialEntitySet
.add(ClassUtils.forName(candidate.getBeanClassName(), MongoConfigurationSupport.class.getClassLoader()));
String beanClassName = candidate.getBeanClassName();
Assert.notNull(beanClassName, "BeanClassName cannot be null");
initialEntitySet.add(ClassUtils.forName(beanClassName, MongoConfigurationSupport.class.getClassLoader()));
}
}

View File

@@ -26,7 +26,7 @@ import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

View File

@@ -20,6 +20,8 @@ import static org.springframework.data.mongodb.config.MongoParsingUtils.*;
import java.util.Set;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
@@ -31,7 +33,6 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -47,6 +48,7 @@ import com.mongodb.ConnectionString;
* @author Viktor Khoroshko
* @author Mark Paluch
*/
@NullUnmarked
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
private static final Set<String> MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES = Set.of("id", "write-concern");
@@ -125,8 +127,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
* @param parserContext
* @return {@literal null} in case no client-/uri defined.
*/
@Nullable
private BeanDefinition getConnectionString(Element element, ParserContext parserContext) {
private @Nullable BeanDefinition getConnectionString(Element element, ParserContext parserContext) {
String type = null;

View File

@@ -19,6 +19,7 @@ import static org.springframework.data.config.ParsingUtils.*;
import java.util.Map;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -40,6 +41,7 @@ import org.w3c.dom.Element;
* @author Christoph Strobl
* @author Mark Paluch
*/
@NullUnmarked
abstract class MongoParsingUtils {
private MongoParsingUtils() {}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.config;
import static org.springframework.data.config.ParsingUtils.*;
import static org.springframework.data.mongodb.config.MongoParsingUtils.*;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
@@ -37,6 +38,7 @@ import org.w3c.dom.Element;
* @author Martin Baumgartner
* @author Oliver Gierke
*/
@NullUnmarked
class MongoTemplateParser extends AbstractBeanDefinitionParser {
@Override

View File

@@ -17,7 +17,7 @@ package org.springframework.data.mongodb.config;
import java.beans.PropertyEditorSupport;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.ReadConcern;

View File

@@ -17,10 +17,10 @@ package org.springframework.data.mongodb.config;
import java.beans.PropertyEditorSupport;
import org.springframework.lang.Nullable;
import com.mongodb.ReadPreference;
import org.jspecify.annotations.Nullable;
/**
* Parse a {@link String} to a {@link ReadPreference}.
*

View File

@@ -23,7 +23,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -80,11 +80,10 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
* @param source
* @return the
*/
@Nullable
private ServerAddress parseServerAddress(String source) {
private @Nullable ServerAddress parseServerAddress(String source) {
if (!StringUtils.hasText(source)) {
if(LOG.isWarnEnabled()) {
if (LOG.isWarnEnabled()) {
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source));
}
return null;
@@ -93,7 +92,7 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
String[] hostAndPort = extractHostAddressAndPort(source.trim());
if (hostAndPort.length > 2) {
if(LOG.isWarnEnabled()) {
if (LOG.isWarnEnabled()) {
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source));
}
return null;
@@ -105,11 +104,11 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
return port == null ? new ServerAddress(hostAddress) : new ServerAddress(hostAddress, port);
} catch (UnknownHostException e) {
if(LOG.isWarnEnabled()) {
if (LOG.isWarnEnabled()) {
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "host", hostAndPort[0]));
}
} catch (NumberFormatException e) {
if(LOG.isWarnEnabled()) {
if (LOG.isWarnEnabled()) {
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "port", hostAndPort[1]));
}
}

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb.config;
import java.beans.PropertyEditorSupport;
import org.bson.UuidRepresentation;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
/**

View File

@@ -17,7 +17,7 @@ package org.springframework.data.mongodb.config;
import java.beans.PropertyEditorSupport;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.WriteConcern;

View File

@@ -1,6 +1,6 @@
/**
* Spring XML namespace configuration for MongoDB specific repositories.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.mongodb.config;

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb.core;
import java.util.List;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
@@ -30,7 +30,6 @@ import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
/**
* Utility methods to map {@link org.springframework.data.mongodb.core.aggregation.Aggregation} pipeline definitions and

View File

@@ -21,9 +21,9 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.bson.BsonTimestamp;
import org.bson.BsonValue;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.messaging.Message;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -78,8 +78,7 @@ public class ChangeStreamEvent<T> {
*
* @return can be {@literal null}.
*/
@Nullable
public ChangeStreamDocument<Document> getRaw() {
public @Nullable ChangeStreamDocument<Document> getRaw() {
return raw;
}
@@ -88,10 +87,10 @@ public class ChangeStreamEvent<T> {
*
* @return can be {@literal null}.
*/
@Nullable
public Instant getTimestamp() {
public @Nullable Instant getTimestamp() {
return getBsonTimestamp() != null ? converter.getConversionService().convert(raw.getClusterTime(), Instant.class)
return getBsonTimestamp() != null && raw != null
? converter.getConversionService().convert(raw.getClusterTime(), Instant.class)
: null;
}
@@ -111,8 +110,7 @@ public class ChangeStreamEvent<T> {
*
* @return can be {@literal null}.
*/
@Nullable
public BsonValue getResumeToken() {
public @Nullable BsonValue getResumeToken() {
return raw != null ? raw.getResumeToken() : null;
}
@@ -121,8 +119,7 @@ public class ChangeStreamEvent<T> {
*
* @return can be {@literal null}.
*/
@Nullable
public OperationType getOperationType() {
public @Nullable OperationType getOperationType() {
return raw != null ? raw.getOperationType() : null;
}
@@ -131,8 +128,7 @@ public class ChangeStreamEvent<T> {
*
* @return can be {@literal null}.
*/
@Nullable
public String getDatabaseName() {
public @Nullable String getDatabaseName() {
return raw != null ? raw.getNamespace().getDatabaseName() : null;
}
@@ -141,8 +137,7 @@ public class ChangeStreamEvent<T> {
*
* @return can be {@literal null}.
*/
@Nullable
public String getCollectionName() {
public @Nullable String getCollectionName() {
return raw != null ? raw.getNamespace().getCollectionName() : null;
}
@@ -152,8 +147,7 @@ public class ChangeStreamEvent<T> {
* @return {@literal null} when {@link #getRaw()} or {@link ChangeStreamDocument#getFullDocument()} is
* {@literal null}.
*/
@Nullable
public T getBody() {
public @Nullable T getBody() {
if (raw == null || raw.getFullDocument() == null) {
return null;
@@ -163,14 +157,14 @@ public class ChangeStreamEvent<T> {
}
/**
* Get the potentially converted {@link ChangeStreamDocument#getFullDocumentBeforeChange() document} before being changed.
* Get the potentially converted {@link ChangeStreamDocument#getFullDocumentBeforeChange() document} before being
* changed.
*
* @return {@literal null} when {@link #getRaw()} or {@link ChangeStreamDocument#getFullDocumentBeforeChange()} is
* {@literal null}.
* @since 4.0
*/
@Nullable
public T getBodyBeforeChange() {
public @Nullable T getBodyBeforeChange() {
if (raw == null || raw.getFullDocumentBeforeChange() == null) {
return null;
@@ -189,6 +183,7 @@ public class ChangeStreamEvent<T> {
return (T) doGetConverted(fullDocument, CONVERTED_FULL_DOCUMENT_UPDATER);
}
@SuppressWarnings("NullAway")
private Object doGetConverted(Document fullDocument, AtomicReferenceFieldUpdater<ChangeStreamEvent, Object> updater) {
Object result = updater.get(this);

View File

@@ -23,9 +23,10 @@ import org.bson.BsonDocument;
import org.bson.BsonTimestamp;
import org.bson.BsonValue;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -248,6 +249,7 @@ public class ChangeStreamOptions {
* @param collation must not be {@literal null} nor {@literal empty}.
* @return this.
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder collation(Collation collation) {
Assert.notNull(collation, "Collation must not be null nor empty");
@@ -257,14 +259,12 @@ public class ChangeStreamOptions {
}
/**
* Set the filter to apply.
* <br />
* Set the filter to apply. <br />
* Fields on aggregation expression root level are prefixed to map to fields contained in
* {@link ChangeStreamDocument#getFullDocument() fullDocument}. However {@literal operationType}, {@literal ns},
* {@literal documentKey} and {@literal fullDocument} are reserved words that will be omitted, and therefore taken
* as given, during the mapping procedure. You may want to have a look at the
* <a href="https://docs.mongodb.com/manual/reference/change-events/">structure of Change Events</a>.
* <br />
* <a href="https://docs.mongodb.com/manual/reference/change-events/">structure of Change Events</a>. <br />
* Use {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation} to ensure filter expressions are
* mapped to domain type fields.
*
@@ -272,6 +272,7 @@ public class ChangeStreamOptions {
* {@literal null}.
* @return this.
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder filter(Aggregation filter) {
Assert.notNull(filter, "Filter must not be null");
@@ -286,6 +287,7 @@ public class ChangeStreamOptions {
* @param filter must not be {@literal null} nor contain {@literal null} values.
* @return this.
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder filter(Document... filter) {
Assert.noNullElements(filter, "Filter must not contain null values");
@@ -301,6 +303,7 @@ public class ChangeStreamOptions {
* @param resumeToken must not be {@literal null}.
* @return this.
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder resumeToken(BsonValue resumeToken) {
Assert.notNull(resumeToken, "ResumeToken must not be null");
@@ -330,6 +333,7 @@ public class ChangeStreamOptions {
* @param lookup must not be {@literal null}.
* @return this.
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder fullDocumentLookup(FullDocument lookup) {
Assert.notNull(lookup, "Lookup must not be null");
@@ -345,6 +349,7 @@ public class ChangeStreamOptions {
* @return this.
* @since 4.0
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder fullDocumentBeforeChangeLookup(FullDocumentBeforeChange lookup) {
Assert.notNull(lookup, "Lookup must not be null");
@@ -358,7 +363,7 @@ public class ChangeStreamOptions {
*
* @return this.
* @since 4.0
* @see #fullDocumentBeforeChangeLookup(FullDocumentBeforeChange)
* @see #fullDocumentBeforeChangeLookup(FullDocumentBeforeChange)
*/
public ChangeStreamOptionsBuilder returnFullDocumentBeforeChange() {
return fullDocumentBeforeChangeLookup(FullDocumentBeforeChange.WHEN_AVAILABLE);
@@ -370,6 +375,7 @@ public class ChangeStreamOptions {
* @param resumeTimestamp must not be {@literal null}.
* @return this.
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder resumeAt(Instant resumeTimestamp) {
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null");
@@ -385,6 +391,7 @@ public class ChangeStreamOptions {
* @return this.
* @since 2.2
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder resumeAt(BsonTimestamp resumeTimestamp) {
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null");
@@ -400,6 +407,7 @@ public class ChangeStreamOptions {
* @return this.
* @since 2.2
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder resumeAfter(BsonValue resumeToken) {
resumeToken(resumeToken);
@@ -415,6 +423,7 @@ public class ChangeStreamOptions {
* @return this.
* @since 2.2
*/
@Contract("_ -> this")
public ChangeStreamOptionsBuilder startAfter(BsonValue resumeToken) {
resumeToken(resumeToken);
@@ -426,6 +435,7 @@ public class ChangeStreamOptions {
/**
* @return the built {@link ChangeStreamOptions}
*/
@Contract("-> new")
public ChangeStreamOptions build() {
ChangeStreamOptions options = new ChangeStreamOptions();

View File

@@ -16,8 +16,8 @@
package org.springframework.data.mongodb.core;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;

View File

@@ -245,7 +245,7 @@ public class CollectionOptions {
* @since 2.1
*/
public CollectionOptions schema(MongoJsonSchema schema) {
return validator(Validator.schema(schema));
return validator(schema != null ? Validator.schema(schema) : null);
}
/**
@@ -574,6 +574,7 @@ public class CollectionOptions {
* @param validator can be {@literal null}.
* @return new instance of {@link ValidationOptions}.
*/
@Contract("_ -> new")
public ValidationOptions validator(@Nullable Validator validator) {
return new ValidationOptions(validator, validationLevel, validationAction);
}
@@ -584,6 +585,7 @@ public class CollectionOptions {
* @param validationLevel can be {@literal null}.
* @return new instance of {@link ValidationOptions}.
*/
@Contract("_ -> new")
public ValidationOptions validationLevel(ValidationLevel validationLevel) {
return new ValidationOptions(validator, validationLevel, validationAction);
}
@@ -594,6 +596,7 @@ public class CollectionOptions {
* @param validationAction can be {@literal null}.
* @return new instance of {@link ValidationOptions}.
*/
@Contract("_ -> new")
public ValidationOptions validationAction(ValidationAction validationAction) {
return new ValidationOptions(validator, validationLevel, validationAction);
}
@@ -950,6 +953,7 @@ public class CollectionOptions {
* @param metaField must not be {@literal null}.
* @return new instance of {@link TimeSeriesOptions}.
*/
@Contract("_ -> new")
public TimeSeriesOptions metaField(String metaField) {
return new TimeSeriesOptions(timeField, metaField, granularity, expireAfter);
}
@@ -961,6 +965,7 @@ public class CollectionOptions {
* @return new instance of {@link TimeSeriesOptions}.
* @see Granularity
*/
@Contract("_ -> new")
public TimeSeriesOptions granularity(GranularityDefinition granularity) {
return new TimeSeriesOptions(timeField, metaField, granularity, expireAfter);
}
@@ -973,6 +978,7 @@ public class CollectionOptions {
* @see com.mongodb.client.model.CreateCollectionOptions#expireAfter(long, java.util.concurrent.TimeUnit)
* @since 4.4
*/
@Contract("_ -> new")
public TimeSeriesOptions expireAfter(Duration ttl) {
return new TimeSeriesOptions(timeField, metaField, granularity, ttl);
}

View File

@@ -21,6 +21,7 @@ import java.util.function.BiFunction;
import java.util.function.Function;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
@@ -84,7 +85,7 @@ class CollectionPreparerSupport implements ReadConcernAware, ReadPreferenceAware
}
@Override
public ReadConcern getReadConcern() {
public @Nullable ReadConcern getReadConcern() {
for (Object aware : sources) {
if (aware instanceof ReadConcernAware rca && rca.hasReadConcern()) {
@@ -108,7 +109,7 @@ class CollectionPreparerSupport implements ReadConcernAware, ReadPreferenceAware
}
@Override
public ReadPreference getReadPreference() {
public @Nullable ReadPreference getReadPreference() {
for (Object aware : sources) {
if (aware instanceof ReadPreferenceAware rpa && rpa.hasReadPreference()) {

View File

@@ -23,9 +23,9 @@ import java.util.List;
import java.util.Map;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.query.MetricConversion;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -154,7 +154,7 @@ class CountQuery {
* @param $and potentially existing {@code $and} condition.
* @return the rewritten query {@link Document}.
*/
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "NullAway" })
private static Document createGeoWithin(String key, Document source, @Nullable Object $and) {
boolean spheric = source.containsKey("$nearSphere");
@@ -233,6 +233,7 @@ class CountQuery {
return source.containsKey("$minDistance");
}
@SuppressWarnings("NullAway")
private static Object toCenterCoordinates(Object value) {
if (ObjectUtils.isArray(value)) {

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb.core;
import java.util.function.Function;
import org.bson.Document;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.mongodb.ReadPreference;
@@ -76,8 +76,7 @@ public interface CursorPreparer extends ReadPreferenceAware {
* @since 2.2
*/
@Override
@Nullable
default ReadPreference getReadPreference() {
default @Nullable ReadPreference getReadPreference() {
return null;
}
}

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import com.mongodb.MongoException;
import com.mongodb.client.MongoDatabase;

View File

@@ -21,6 +21,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.DataIntegrityViolationException;
@@ -40,7 +41,7 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.util.Pair;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import com.mongodb.MongoBulkWriteException;
@@ -115,6 +116,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_ -> this")
public BulkOperations insert(Object document) {
Assert.notNull(document, "Document must not be null");
@@ -127,6 +129,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_ -> this")
public BulkOperations insert(List<? extends Object> documents) {
Assert.notNull(documents, "Documents must not be null");
@@ -137,6 +140,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_, _ -> this")
public BulkOperations updateOne(Query query, UpdateDefinition update) {
Assert.notNull(query, "Query must not be null");
@@ -146,6 +150,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_ -> this")
public BulkOperations updateOne(List<Pair<Query, UpdateDefinition>> updates) {
Assert.notNull(updates, "Updates must not be null");
@@ -158,6 +163,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_, _ -> this")
public BulkOperations updateMulti(Query query, UpdateDefinition update) {
Assert.notNull(query, "Query must not be null");
@@ -169,6 +175,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_ -> this")
public BulkOperations updateMulti(List<Pair<Query, UpdateDefinition>> updates) {
Assert.notNull(updates, "Updates must not be null");
@@ -181,11 +188,13 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_, _ -> this")
public BulkOperations upsert(Query query, UpdateDefinition update) {
return update(query, update, true, true);
}
@Override
@Contract("_ -> this")
public BulkOperations upsert(List<Pair<Query, Update>> updates) {
for (Pair<Query, Update> update : updates) {
@@ -196,6 +205,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_ -> this")
public BulkOperations remove(Query query) {
Assert.notNull(query, "Query must not be null");
@@ -209,6 +219,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_ -> this")
public BulkOperations remove(List<Query> removes) {
Assert.notNull(removes, "Removals must not be null");
@@ -221,6 +232,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
}
@Override
@Contract("_, _, _ -> this")
public BulkOperations replaceOne(Query query, Object replacement, FindAndReplaceOptions options) {
Assert.notNull(query, "Query must not be null");
@@ -412,7 +424,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
return eventPublisher == null;
}
@SuppressWarnings("rawtypes")
@SuppressWarnings({ "rawtypes", "NullAway" })
public <T> T callback(Class<? extends EntityCallback> callbackType, T entity, String collectionName) {
if (skipEntityCallbacks()) {
@@ -422,7 +434,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
return entityCallbacks.callback(callbackType, entity, collectionName);
}
@SuppressWarnings("rawtypes")
@SuppressWarnings({ "rawtypes", "NullAway" })
public <T> T callback(Class<? extends EntityCallback> callbackType, T entity, Document document,
String collectionName) {
@@ -433,6 +445,7 @@ class DefaultBulkOperations extends BulkOperationsSupport implements BulkOperati
return entityCallbacks.callback(callbackType, entity, document, collectionName);
}
@SuppressWarnings("NullAway")
public void publishEvent(ApplicationEvent event) {
if (skipEventPublishing()) {

View File

@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.List;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
@@ -28,7 +29,6 @@ import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
@@ -115,6 +115,7 @@ public class DefaultIndexOperations implements IndexOperations {
}
@Override
@SuppressWarnings("NullAway")
public String ensureIndex(IndexDefinition indexDefinition) {
return execute(collection -> {
@@ -131,8 +132,7 @@ public class DefaultIndexOperations implements IndexOperations {
});
}
@Nullable
private MongoPersistentEntity<?> lookupPersistentEntity(@Nullable Class<?> entityType, String collection) {
private @Nullable MongoPersistentEntity<?> lookupPersistentEntity(@Nullable Class<?> entityType, String collection) {
if (entityType != null) {
return mapper.getMappingContext().getRequiredPersistentEntity(entityType);
@@ -160,6 +160,7 @@ public class DefaultIndexOperations implements IndexOperations {
}
@Override
@SuppressWarnings("NullAway")
public void alterIndex(String name, org.springframework.data.mongodb.core.index.IndexOptions options) {
Document indexOptions = new Document("name", name);
@@ -180,6 +181,7 @@ public class DefaultIndexOperations implements IndexOperations {
}
@Override
@SuppressWarnings("NullAway")
public List<IndexInfo> getIndexInfo() {
return execute(new CollectionCallback<List<IndexInfo>>() {
@@ -208,8 +210,7 @@ public class DefaultIndexOperations implements IndexOperations {
});
}
@Nullable
public <T> T execute(CollectionCallback<T> callback) {
public <T> @Nullable T execute(CollectionCallback<T> callback) {
Assert.notNull(callback, "CollectionCallback must not be null");
@@ -228,6 +229,7 @@ public class DefaultIndexOperations implements IndexOperations {
mapper.getMappedSort((Document) sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY), entity));
}
@SuppressWarnings("NullAway")
private static IndexOptions addDefaultCollationIfRequired(IndexOptions ops,
@Nullable MongoPersistentEntity<?> entity) {

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.IndexOperations;
@@ -43,7 +44,7 @@ class DefaultIndexOperationsProvider implements IndexOperationsProvider {
}
@Override
public IndexOperations indexOps(String collectionName, Class<?> type) {
public IndexOperations indexOps(String collectionName, @Nullable Class<?> type) {
return new DefaultIndexOperations(mongoDbFactory, collectionName, mapper, type);
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.lang.Contract;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -24,6 +25,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.mapping.callback.EntityCallback;
@@ -40,7 +42,6 @@ import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.mongodb.WriteConcern;
@@ -107,6 +108,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_ -> this")
public ReactiveBulkOperations insert(Object document) {
Assert.notNull(document, "Document must not be null");
@@ -120,6 +122,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_ -> this")
public ReactiveBulkOperations insert(List<? extends Object> documents) {
Assert.notNull(documents, "Documents must not be null");
@@ -130,6 +133,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_, _, _ -> this")
public ReactiveBulkOperations updateOne(Query query, UpdateDefinition update) {
Assert.notNull(query, "Query must not be null");
@@ -140,6 +144,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_, _ -> this")
public ReactiveBulkOperations updateMulti(Query query, UpdateDefinition update) {
Assert.notNull(query, "Query must not be null");
@@ -150,11 +155,13 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_, _ -> this")
public ReactiveBulkOperations upsert(Query query, UpdateDefinition update) {
return update(query, update, true, true);
}
@Override
@Contract("_ -> this")
public ReactiveBulkOperations remove(Query query) {
Assert.notNull(query, "Query must not be null");
@@ -169,6 +176,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_ -> this")
public ReactiveBulkOperations remove(List<Query> removes) {
Assert.notNull(removes, "Removals must not be null");
@@ -181,6 +189,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
}
@Override
@Contract("_, _, _ -> this")
public ReactiveBulkOperations replaceOne(Query query, Object replacement, FindAndReplaceOptions options) {
Assert.notNull(query, "Query must not be null");
@@ -359,7 +368,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
return eventPublisher == null;
}
@SuppressWarnings("rawtypes")
@SuppressWarnings({ "rawtypes", "NullAway" })
public <T> Mono<T> callback(Class<? extends EntityCallback> callbackType, T entity, String collectionName) {
if (skipEntityCallbacks()) {
@@ -369,7 +378,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
return entityCallbacks.callback(callbackType, entity, collectionName);
}
@SuppressWarnings("rawtypes")
@SuppressWarnings({ "rawtypes", "NullAway" })
public <T> Mono<T> callback(Class<? extends EntityCallback> callbackType, T entity, Document document,
String collectionName) {
@@ -380,6 +389,7 @@ class DefaultReactiveBulkOperations extends BulkOperationsSupport implements Rea
return entityCallbacks.callback(callbackType, entity, document, collectionName);
}
@SuppressWarnings("NullAway")
public void publishEvent(ApplicationEvent event) {
if (skipEventPublishing()) {

View File

@@ -19,16 +19,15 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Collection;
import java.util.Optional;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.ReactiveIndexOperations;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
@@ -48,7 +47,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
private final ReactiveMongoOperations mongoOperations;
private final String collectionName;
private final QueryMapper queryMapper;
private final Optional<Class<?>> type;
private final @Nullable Class<?> type;
/**
* Creates a new {@link DefaultReactiveIndexOperations}.
@@ -59,7 +58,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
*/
public DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName,
QueryMapper queryMapper) {
this(mongoOperations, collectionName, queryMapper, Optional.empty());
this(mongoOperations, collectionName, queryMapper, null);
}
/**
@@ -71,12 +70,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
* @param type used for mapping potential partial index filter expression, must not be {@literal null}.
*/
public DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName,
QueryMapper queryMapper, Class<?> type) {
this(mongoOperations, collectionName, queryMapper, Optional.of(type));
}
private DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName,
QueryMapper queryMapper, Optional<Class<?>> type) {
QueryMapper queryMapper, @Nullable Class<?> type) {
Assert.notNull(mongoOperations, "ReactiveMongoOperations must not be null");
Assert.notNull(collectionName, "Collection must not be null");
@@ -89,13 +83,12 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
}
@Override
@SuppressWarnings("NullAway")
public Mono<String> ensureIndex(IndexDefinition indexDefinition) {
return mongoOperations.execute(collectionName, collection -> {
MongoPersistentEntity<?> entity = type
.map(val -> (MongoPersistentEntity) queryMapper.getMappingContext().getRequiredPersistentEntity(val))
.orElseGet(() -> lookupPersistentEntity(collectionName));
MongoPersistentEntity<?> entity = getConfiguredEntity();
IndexOptions indexOptions = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
@@ -124,8 +117,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
}).then();
}
@Nullable
private MongoPersistentEntity<?> lookupPersistentEntity(String collection) {
private @Nullable MongoPersistentEntity<?> lookupPersistentEntity(String collection) {
Collection<? extends MongoPersistentEntity<?>> entities = queryMapper.getMappingContext().getPersistentEntities();
@@ -152,6 +144,14 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
.map(IndexConverters.documentToIndexInfoConverter()::convert);
}
private @Nullable MongoPersistentEntity<?> getConfiguredEntity() {
if (type != null) {
return queryMapper.getMappingContext().getRequiredPersistentEntity(type);
}
return lookupPersistentEntity(collectionName);
}
private IndexOptions addPartialFilterIfPresent(IndexOptions ops, Document sourceOptions,
@Nullable MongoPersistentEntity<?> entity) {
@@ -164,6 +164,7 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
queryMapper.getMappedObject((Document) sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY), entity));
}
@SuppressWarnings("NullAway")
private static IndexOptions addDefaultCollationIfRequired(IndexOptions ops,
@Nullable MongoPersistentEntity<?> entity) {

View File

@@ -15,9 +15,9 @@
*/
package org.springframework.data.mongodb.core;
import static java.util.UUID.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import static java.util.UUID.randomUUID;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
import java.util.ArrayList;
import java.util.Arrays;
@@ -28,7 +28,8 @@ import java.util.Set;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.dao.DataAccessException;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
@@ -38,8 +39,6 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBList;
import com.mongodb.MongoException;
import com.mongodb.client.MongoDatabase;
/**
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ExecutableMongoScript}.
@@ -51,6 +50,7 @@ import com.mongodb.client.MongoDatabase;
* @deprecated since 2.2. The {@code eval} command has been removed in MongoDB Server 4.2.0.
*/
@Deprecated
@NullUnmarked
class DefaultScriptOperations implements ScriptOperations {
private static final String SCRIPT_COLLECTION_NAME = "system.js";
@@ -85,38 +85,28 @@ class DefaultScriptOperations implements ScriptOperations {
}
@Override
public Object execute(ExecutableMongoScript script, Object... args) {
public @Nullable Object execute(ExecutableMongoScript script, Object... args) {
Assert.notNull(script, "Script must not be null");
return mongoOperations.execute(new DbCallback<Object>() {
return mongoOperations.execute(db -> {
@Override
public Object doInDB(MongoDatabase db) throws MongoException, DataAccessException {
Document command = new Document("$eval", script.getCode());
BasicDBList commandArgs = new BasicDBList();
commandArgs.addAll(Arrays.asList(convertScriptArgs(false, args)));
command.append("args", commandArgs);
return db.runCommand(command).get("retval");
}
Document command = new Document("$eval", script.getCode());
BasicDBList commandArgs = new BasicDBList();
commandArgs.addAll(Arrays.asList(convertScriptArgs(false, args)));
command.append("args", commandArgs);
return db.runCommand(command).get("retval");
});
}
@Override
public Object call(String scriptName, Object... args) {
public @Nullable Object call(String scriptName, Object... args) {
Assert.hasText(scriptName, "ScriptName must not be null or empty");
return mongoOperations.execute(new DbCallback<Object>() {
@Override
public Object doInDB(MongoDatabase db) throws MongoException, DataAccessException {
return db.runCommand(new Document("eval", String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args))))
.get("retval");
}
});
return mongoOperations.execute(
db -> db.runCommand(new Document("eval", String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args))))
.get("retval"));
}
@Override

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import com.mongodb.WriteConcern;
/**
@@ -26,7 +28,7 @@ enum DefaultWriteConcernResolver implements WriteConcernResolver {
INSTANCE;
public WriteConcern resolve(MongoAction action) {
public @Nullable WriteConcern resolve(MongoAction action) {
return action.getDefaultWriteConcern();
}
}

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.lang.Nullable;
/**
* Delegate class to encapsulate lifecycle event configuration and publishing.
@@ -47,6 +47,7 @@ class EntityLifecycleEventDelegate {
*
* @param event the application event.
*/
@SuppressWarnings("NullAway")
public void publishEvent(Object event) {
if (canPublishEvent()) {

View File

@@ -26,9 +26,11 @@ import java.util.function.Predicate;
import org.bson.BsonNull;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.expression.ValueEvaluationContext;
@@ -65,7 +67,6 @@ import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.TargetAware;
import org.springframework.data.util.Optionals;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
@@ -423,6 +424,7 @@ class EntityOperations {
*
* @return
*/
@Nullable
Object getId();
/**
@@ -528,10 +530,9 @@ class EntityOperations {
* Populates the identifier of the backing entity if it has an identifier property and there's no identifier
* currently present.
*
* @param id must not be {@literal null}.
* @param id can be {@literal null}.
* @return
*/
@Nullable
T populateIdIfNecessary(@Nullable Object id);
/**
@@ -574,12 +575,12 @@ class EntityOperations {
}
@Override
public Object getId() {
public @Nullable Object getId() {
return getPropertyValue(ID_FIELD);
}
@Override
public Object getPropertyValue(String key) {
public @Nullable Object getPropertyValue(String key) {
return map.get(key);
}
@@ -588,7 +589,6 @@ class EntityOperations {
return Query.query(Criteria.where(ID_FIELD).is(map.get(ID_FIELD)));
}
@Nullable
@Override
public T populateIdIfNecessary(@Nullable Object id) {
@@ -615,8 +615,7 @@ class EntityOperations {
}
@Override
@Nullable
public Number getVersion() {
public @Nullable Number getVersion() {
return null;
}
@@ -733,7 +732,7 @@ class EntityOperations {
}
@Override
public Object getPropertyValue(String key) {
public @Nullable Object getPropertyValue(String key) {
return propertyAccessor.getProperty(entity.getRequiredPersistentProperty(key));
}
@@ -800,8 +799,7 @@ class EntityOperations {
}
@Override
@Nullable
public Object getVersion() {
public @Nullable Object getVersion() {
return propertyAccessor.getProperty(entity.getRequiredVersionProperty());
}
@@ -849,7 +847,6 @@ class EntityOperations {
return keyset;
}
@Nullable
private Object getNestedPropertyValue(String key) {
String[] segments = key.split("\\.");
@@ -862,6 +859,10 @@ class EntityOperations {
currentValue = currentEntity.getPropertyValue(segment);
if (i < segments.length - 1) {
if (currentValue == null) {
return BsonNull.VALUE;
}
currentEntity = entityOperations.forEntity(currentValue);
}
}
@@ -898,7 +899,6 @@ class EntityOperations {
new ConvertingPropertyAccessor<>(propertyAccessor, conversionService), entityOperations);
}
@Nullable
@Override
public T populateIdIfNecessary(@Nullable Object id) {
@@ -920,8 +920,7 @@ class EntityOperations {
}
@Override
@Nullable
public Number getVersion() {
public @Nullable Number getVersion() {
MongoPersistentProperty versionProperty = entity.getRequiredVersionProperty();
@@ -1137,7 +1136,7 @@ class EntityOperations {
@Override
public String getIdKeyName() {
return entity.getIdProperty().getName();
return entity.getIdProperty() != null ? entity.getIdProperty().getName() : ID_FIELD;
}
private String mappedNameOrDefault(String name) {
@@ -1157,7 +1156,8 @@ class EntityOperations {
return mongoEntity.getValueEvaluationContext(null);
}
return ValueEvaluationContext.of(this.environment, SimpleEvaluationContext.forReadOnlyDataBinding().build());
return ValueEvaluationContext.of(this.environment != null ? this.environment : new StandardEnvironment(),
SimpleEvaluationContext.forReadOnlyDataBinding().build());
}
/**

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
@@ -55,11 +56,11 @@ class ExecutableAggregationOperationSupport implements ExecutableAggregationOper
private final MongoTemplate template;
private final Class<T> domainType;
private final Aggregation aggregation;
private final String collection;
private final @Nullable Aggregation aggregation;
private final @Nullable String collection;
public ExecutableAggregationSupport(MongoTemplate template, Class<T> domainType, Aggregation aggregation,
String collection) {
public ExecutableAggregationSupport(MongoTemplate template, Class<T> domainType, @Nullable Aggregation aggregation,
@Nullable String collection) {
this.template = template;
this.domainType = domainType;
this.aggregation = aggregation;
@@ -84,21 +85,25 @@ class ExecutableAggregationOperationSupport implements ExecutableAggregationOper
@Override
public AggregationResults<T> all() {
Assert.notNull(aggregation, "Aggregation must be set first");
return template.aggregate(aggregation, getCollectionName(aggregation), domainType);
}
@Override
public Stream<T> stream() {
Assert.notNull(aggregation, "Aggregation must be set first");
return template.aggregateStream(aggregation, getCollectionName(aggregation), domainType);
}
private String getCollectionName(Aggregation aggregation) {
private String getCollectionName(@Nullable Aggregation aggregation) {
if (StringUtils.hasText(collection)) {
return collection;
}
if (aggregation instanceof TypedAggregation typedAggregation) {
if (aggregation instanceof TypedAggregation<?> typedAggregation) {
if (typedAggregation.getInputType() != null) {
return template.getCollectionName(typedAggregation.getInputType());

View File

@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.ScrollPosition;
@@ -27,7 +28,6 @@ import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
import com.mongodb.client.MongoCollection;

View File

@@ -16,18 +16,17 @@
package org.springframework.data.mongodb.core;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Window;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.SerializationUtils;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -53,6 +52,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
@Contract("_ -> new")
public <T> ExecutableFind<T> query(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null");
@@ -84,6 +84,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
@Contract("_ -> new")
public FindWithProjection<T> inCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty");
@@ -92,6 +93,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
@Contract("_ -> new")
public <T1> FindWithQuery<T1> as(Class<T1> returnType) {
Assert.notNull(returnType, "ReturnType must not be null");
@@ -100,6 +102,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
@Contract("_ -> new")
public TerminatingFind<T> matching(Query query) {
Assert.notNull(query, "Query must not be null");
@@ -108,7 +111,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
public T oneValue() {
public @Nullable T oneValue() {
List<T> result = doFind(new DelegatingQueryCursorPreparer(getCursorPreparer(query, null)).limit(2));
@@ -124,7 +127,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
public T firstValue() {
public @Nullable T firstValue() {
List<T> result = doFind(new DelegatingQueryCursorPreparer(getCursorPreparer(query, null)).limit(1));
@@ -206,10 +209,10 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
* @author Christoph Strobl
* @since 2.0
*/
static class DelegatingQueryCursorPreparer implements SortingQueryCursorPreparer {
static class DelegatingQueryCursorPreparer implements CursorPreparer {
private final @Nullable CursorPreparer delegate;
private Optional<Integer> limit = Optional.empty();
private int limit = -1;
DelegatingQueryCursorPreparer(@Nullable CursorPreparer delegate) {
this.delegate = delegate;
@@ -219,25 +222,22 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
public FindIterable<Document> prepare(FindIterable<Document> iterable) {
FindIterable<Document> target = delegate != null ? delegate.prepare(iterable) : iterable;
return limit.map(target::limit).orElse(target);
if (limit >= 0) {
target.limit(limit);
}
return target;
}
@Contract("_ -> this")
CursorPreparer limit(int limit) {
this.limit = Optional.of(limit);
this.limit = limit;
return this;
}
@Override
@Nullable
public ReadPreference getReadPreference() {
return delegate.getReadPreference();
}
@Override
@Nullable
public Document getSortObject() {
return delegate instanceof SortingQueryCursorPreparer sqcp ? sqcp.getSortObject() : null;
public @Nullable ReadPreference getReadPreference() {
return delegate != null ? delegate.getReadPreference() : null;
}
}
@@ -258,6 +258,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
@SuppressWarnings("unchecked")
@Contract("_ -> new")
public <R> TerminatingDistinct<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null");
@@ -266,6 +267,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
@Contract("_ -> new")
public TerminatingDistinct<T> matching(Query query) {
Assert.notNull(query, "Query must not be null");

View File

@@ -18,8 +18,9 @@ package org.springframework.data.mongodb.core;
import java.util.ArrayList;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -41,6 +42,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
}
@Override
@Contract("_ -> new")
public <T> ExecutableInsert<T> insert(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null");
@@ -56,10 +58,11 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
private final MongoTemplate template;
private final Class<T> domainType;
@Nullable private final String collection;
@Nullable private final BulkMode bulkMode;
private final @Nullable String collection;
private final @Nullable BulkMode bulkMode;
ExecutableInsertSupport(MongoTemplate template, Class<T> domainType, String collection, BulkMode bulkMode) {
ExecutableInsertSupport(MongoTemplate template, Class<T> domainType, @Nullable String collection,
@Nullable BulkMode bulkMode) {
this.template = template;
this.domainType = domainType;
@@ -93,6 +96,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
}
@Override
@Contract("_ -> new")
public InsertWithBulkMode<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty");
@@ -101,6 +105,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
}
@Override
@Contract("_ -> new")
public TerminatingBulkInsert<T> withBulkMode(BulkMode bulkMode) {
Assert.notNull(bulkMode, "BulkMode must not be null");

View File

@@ -17,9 +17,10 @@ package org.springframework.data.mongodb.core;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -46,6 +47,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation#mapReduce(java.lang.Class)
*/
@Override
@Contract("_ -> new")
public <T> ExecutableMapReduceSupport<T> mapReduce(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null");
@@ -89,6 +91,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.TerminatingMapReduce#all()
*/
@Override
@SuppressWarnings("NullAway")
public List<T> all() {
return template.mapReduce(query, domainType, getCollectionName(), mapFunction, reduceFunction, options,
returnType);

View File

@@ -17,8 +17,9 @@ package org.springframework.data.mongodb.core;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -42,6 +43,7 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
}
@Override
@Contract("_ -> new")
public <T> ExecutableRemove<T> remove(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null");
@@ -60,7 +62,8 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
private final Query query;
@Nullable private final String collection;
public ExecutableRemoveSupport(MongoTemplate template, Class<T> domainType, Query query, String collection) {
public ExecutableRemoveSupport(MongoTemplate template, Class<T> domainType, Query query,
@Nullable String collection) {
this.template = template;
this.domainType = domainType;
this.query = query;
@@ -68,6 +71,7 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
}
@Override
@Contract("_ -> new")
public RemoveWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty");
@@ -76,6 +80,7 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
}
@Override
@Contract("_ -> new")
public TerminatingRemove<T> matching(Query query) {
Assert.notNull(query, "Query must not be null");

View File

@@ -17,12 +17,12 @@ package org.springframework.data.mongodb.core;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.aggregation.AggregationUpdate;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.lang.Nullable;
import com.mongodb.client.result.UpdateResult;

View File

@@ -15,9 +15,10 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -41,6 +42,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public <T> ExecutableUpdate<T> update(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null");
@@ -52,6 +54,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
* @author Christoph Strobl
* @since 2.0
*/
@SuppressWarnings("rawtypes")
static class ExecutableUpdateSupport<T>
implements ExecutableUpdate<T>, UpdateWithCollection<T>, UpdateWithQuery<T>, TerminatingUpdate<T>,
FindAndReplaceWithOptions<T>, TerminatingFindAndReplace<T>, FindAndReplaceWithProjection<T> {
@@ -66,9 +69,9 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Nullable private final Object replacement;
private final Class<T> targetType;
ExecutableUpdateSupport(MongoTemplate template, Class domainType, Query query, UpdateDefinition update,
String collection, FindAndModifyOptions findAndModifyOptions, FindAndReplaceOptions findAndReplaceOptions,
Object replacement, Class<T> targetType) {
ExecutableUpdateSupport(MongoTemplate template, Class domainType, Query query, @Nullable UpdateDefinition update,
@Nullable String collection, @Nullable FindAndModifyOptions findAndModifyOptions,
@Nullable FindAndReplaceOptions findAndReplaceOptions, @Nullable Object replacement, Class<T> targetType) {
this.template = template;
this.domainType = domainType;
@@ -82,6 +85,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public TerminatingUpdate<T> apply(UpdateDefinition update) {
Assert.notNull(update, "Update must not be null");
@@ -91,6 +95,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public UpdateWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty");
@@ -100,6 +105,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options) {
Assert.notNull(options, "Options must not be null");
@@ -109,6 +115,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public FindAndReplaceWithProjection<T> replaceWith(T replacement) {
Assert.notNull(replacement, "Replacement must not be null");
@@ -118,6 +125,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public FindAndReplaceWithProjection<T> withOptions(FindAndReplaceOptions options) {
Assert.notNull(options, "Options must not be null");
@@ -127,6 +135,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public TerminatingReplace withOptions(ReplaceOptions options) {
FindAndReplaceOptions target = new FindAndReplaceOptions();
@@ -138,6 +147,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public UpdateWithUpdate<T> matching(Query query) {
Assert.notNull(query, "Query must not be null");
@@ -147,6 +157,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@Contract("_ -> new")
public <R> FindAndReplaceWithOptions<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null");
@@ -171,6 +182,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@SuppressWarnings("NullAway")
public @Nullable T findAndModifyValue() {
return template.findAndModify(query, update,
@@ -179,6 +191,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@SuppressWarnings({ "unchecked", "NullAway" })
public @Nullable T findAndReplaceValue() {
return (T) template.findAndReplace(query, replacement,
@@ -187,6 +200,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
}
@Override
@SuppressWarnings({ "unchecked", "NullAway" })
public UpdateResult replaceFirst() {
if (replacement != null) {
@@ -198,6 +212,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName());
}
@SuppressWarnings("NullAway")
private UpdateResult doUpdate(boolean multi, boolean upsert) {
return template.doUpdate(getCollectionName(), query, update, domainType, upsert, multi);
}

View File

@@ -17,8 +17,9 @@ package org.springframework.data.mongodb.core;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
/**
* @author Mark Pollak
@@ -99,16 +100,19 @@ public class FindAndModifyOptions {
return options;
}
@Contract("_ -> this")
public FindAndModifyOptions returnNew(boolean returnNew) {
this.returnNew = returnNew;
return this;
}
@Contract("_ -> this")
public FindAndModifyOptions upsert(boolean upsert) {
this.upsert = upsert;
return this;
}
@Contract("_ -> this")
public FindAndModifyOptions remove(boolean remove) {
this.remove = remove;
return this;
@@ -121,6 +125,7 @@ public class FindAndModifyOptions {
* @return this.
* @since 2.0
*/
@Contract("_ -> this")
public FindAndModifyOptions collation(@Nullable Collation collation) {
this.collation = collation;

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.lang.Contract;
/**
* Options for
* <a href="https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndReplace/">findOneAndReplace</a>.
@@ -95,6 +97,7 @@ public class FindAndReplaceOptions extends ReplaceOptions {
*
* @return this.
*/
@Contract("-> this")
public FindAndReplaceOptions returnNew() {
this.returnNew = true;
@@ -106,6 +109,7 @@ public class FindAndReplaceOptions extends ReplaceOptions {
*
* @return this.
*/
@Contract("-> this")
public FindAndReplaceOptions upsert() {
super.upsert();

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb.core;
import java.util.function.Function;
import org.bson.Document;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.mongodb.ReadPreference;
@@ -76,8 +76,7 @@ public interface FindPublisherPreparer extends ReadPreferenceAware {
* @since 2.2
*/
@Override
@Nullable
default ReadPreference getReadPreference() {
default @Nullable ReadPreference getReadPreference() {
return null;
}
}

View File

@@ -18,9 +18,9 @@ package org.springframework.data.mongodb.core;
import java.util.function.Function;
import org.bson.conversions.Bson;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.CodecRegistryProvider;
import org.springframework.data.mongodb.util.BsonUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**

View File

@@ -20,6 +20,7 @@ import java.util.List;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
@@ -70,7 +71,7 @@ public class MappedDocument {
return hasId() && document.get(ID_FIELD) != null;
}
public Object getId() {
public @Nullable Object getId() {
return document.get(ID_FIELD);
}
@@ -86,7 +87,7 @@ public class MappedDocument {
return new Document(ID_FIELD, document.get(ID_FIELD));
}
public Object get(String key) {
public @Nullable Object get(String key) {
return document.get(key);
}

View File

@@ -24,7 +24,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.convert.MongoConverter;
@@ -46,6 +46,7 @@ import org.springframework.data.mongodb.core.schema.QueryCharacteristic;
import org.springframework.data.mongodb.core.schema.QueryCharacteristics;
import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -94,6 +95,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
}
@Override
@Contract("_ -> new")
public MongoJsonSchemaCreator filter(Predicate<JsonSchemaPropertyContext> filter) {
return new MappingMongoJsonSchemaCreator(converter, mappingContext, filter, mergeProperties);
}
@@ -111,6 +113,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
* @return new instance of {@link MongoJsonSchemaCreator}.
* @since 3.4
*/
@Contract("_, _ -> new")
public MongoJsonSchemaCreator withTypesFor(String path, Class<?>... types) {
LinkedMultiValueMap<String, Class<?>> clone = mergeProperties.clone();
@@ -183,6 +186,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
return schemaProperties;
}
@SuppressWarnings("NullAway")
private JsonSchemaProperty computeSchemaForProperty(List<MongoPersistentProperty> path) {
String stringPath = path.stream().map(MongoPersistentProperty::getName).collect(Collectors.joining("."));
@@ -373,7 +377,9 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
return schemaObject;
}
private String computePropertyFieldName(PersistentProperty<?> property) {
private String computePropertyFieldName(@Nullable PersistentProperty<?> property) {
Assert.notNull(property, "Property must not be null");
return property instanceof MongoPersistentProperty mongoPersistentProperty ? mongoPersistentProperty.getFieldName()
: property.getName();
@@ -445,7 +451,8 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
}
@Override
public <T> MongoPersistentEntity<T> resolveEntity(MongoPersistentProperty property) {
@SuppressWarnings("unchecked")
public <T> @Nullable MongoPersistentEntity<T> resolveEntity(MongoPersistentProperty property) {
return (MongoPersistentEntity<T>) mappingContext.getPersistentEntity(property);
}
}

View File

@@ -16,7 +16,7 @@
package org.springframework.data.mongodb.core;
import org.bson.Document;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.mongodb.WriteConcern;
@@ -72,28 +72,23 @@ public class MongoAction {
return collectionName;
}
@Nullable
public WriteConcern getDefaultWriteConcern() {
public @Nullable WriteConcern getDefaultWriteConcern() {
return defaultWriteConcern;
}
@Nullable
public Class<?> getEntityType() {
public @Nullable Class<?> getEntityType() {
return entityType;
}
@Nullable
public MongoActionOperation getMongoActionOperation() {
public @Nullable MongoActionOperation getMongoActionOperation() {
return mongoActionOperation;
}
@Nullable
public Document getQuery() {
public @Nullable Document getQuery() {
return query;
}
@Nullable
public Document getDocument() {
public @Nullable Document getDocument() {
return document;
}

View File

@@ -24,11 +24,11 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import org.bson.UuidRepresentation;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.SpringDataMongoDB;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -78,7 +78,7 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> imp
*
* @param credential can be {@literal null}.
*/
public void setCredential(@Nullable MongoCredential[] credential) {
public void setCredential(MongoCredential @Nullable[] credential) {
this.credential = Arrays.asList(credential);
}
@@ -119,8 +119,7 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> imp
}
@Override
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
@@ -316,13 +315,13 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> imp
settingsBuilder.accept(value);
}
private <S, T> T computeSettingsValue(Function<S, T> function, S defaultValueHolder, S settingsValueHolder,
private <S, T> @Nullable T computeSettingsValue(Function<S, T> function, S defaultValueHolder, S settingsValueHolder,
@Nullable T connectionStringValue) {
return computeSettingsValue(function.apply(defaultValueHolder), function.apply(settingsValueHolder),
connectionStringValue);
}
private <T> T computeSettingsValue(T defaultValue, T fromSettings, T fromConnectionString) {
private <T> @Nullable T computeSettingsValue(@Nullable T defaultValue, T fromSettings, @Nullable T fromConnectionString) {
boolean fromSettingsIsDefault = ObjectUtils.nullSafeEquals(defaultValue, fromSettings);
boolean fromConnectionStringIsDefault = ObjectUtils.nullSafeEquals(defaultValue, fromConnectionString);
@@ -337,7 +336,7 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> imp
return MongoClients.create(settings, SpringDataMongoDB.driverInformation());
}
private String getOrDefault(Object value, String defaultValue) {
private String getOrDefault(@Nullable Object value, String defaultValue) {
if(value == null) {
return defaultValue;

View File

@@ -15,12 +15,13 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.SessionAwareMethodInterceptor;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -132,6 +133,7 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
}
@Override
@Contract("_ -> new")
public MongoDatabaseFactory withSession(ClientSession session) {
return new MongoDatabaseFactorySupport.ClientSessionBoundMongoDbFactory(session, this);
}

View File

@@ -19,8 +19,8 @@ import java.util.Collections;
import java.util.Map;
import org.bson.BsonDocument;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import com.mongodb.AutoEncryptionSettings;
import com.mongodb.MongoClientSettings;
@@ -34,11 +34,11 @@ import com.mongodb.MongoClientSettings;
public class MongoEncryptionSettingsFactoryBean implements FactoryBean<AutoEncryptionSettings> {
private boolean bypassAutoEncryption;
private String keyVaultNamespace;
private Map<String, Object> extraOptions;
private MongoClientSettings keyVaultClientSettings;
private Map<String, Map<String, Object>> kmsProviders;
private Map<String, BsonDocument> schemaMap;
private @Nullable String keyVaultNamespace;
private @Nullable Map<String, Object> extraOptions;
private @Nullable MongoClientSettings keyVaultClientSettings;
private @Nullable Map<String, Map<String, Object>> kmsProviders;
private @Nullable Map<String, BsonDocument> schemaMap;
/**
* @param bypassAutoEncryption

View File

@@ -18,7 +18,7 @@ package org.springframework.data.mongodb.core;
import java.util.Set;
import org.bson.BsonInvalidOperationException;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
@@ -31,7 +31,6 @@ import org.springframework.data.mongodb.ClientSessionException;
import org.springframework.data.mongodb.TransientClientSessionException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.util.MongoDbErrorCodes;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import com.mongodb.MongoBulkWriteException;
@@ -69,12 +68,12 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
private static final Set<String> SECURITY_EXCEPTIONS = Set.of("MongoCryptException");
@Override
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return doTranslateException(ex);
}
@Nullable
@SuppressWarnings("NullAway")
DataAccessException doTranslateException(RuntimeException ex) {
// Check for well-known MongoException subclasses.

View File

@@ -139,8 +139,7 @@ public interface MongoJsonSchemaCreator {
* @return {@literal null} if the property is not an entity. It is nevertheless recommend to check
* {@link PersistentProperty#isEntity()} first.
*/
@Nullable
<T> MongoPersistentEntity<T> resolveEntity(MongoPersistentProperty property);
<T> @Nullable MongoPersistentEntity<T> resolveEntity(MongoPersistentProperty property);
}
@@ -162,6 +161,7 @@ public interface MongoJsonSchemaCreator {
return extracted(context.getProperty(), context);
}
@SuppressWarnings("NullAway")
private boolean extracted(MongoPersistentProperty property, JsonSchemaPropertyContext context) {
if (property.isAnnotationPresent(Encrypted.class)) {
return true;

View File

@@ -24,6 +24,7 @@ import java.util.function.Supplier;
import java.util.stream.Stream;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
@@ -49,7 +50,6 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.util.Lock;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -196,7 +196,8 @@ public interface MongoOperations extends FluentMongoOperations {
private @Nullable ClientSession session;
@Override
public <T> T execute(SessionCallback<T> action, Consumer<ClientSession> onComplete) {
@SuppressWarnings("NullAway")
public <T> @Nullable T execute(SessionCallback<T> action, Consumer<ClientSession> onComplete) {
lock.executeWithoutResult(() -> {
@@ -733,8 +734,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @param entityClass the parametrized type of the returned list.
* @return the converted object.
*/
@Nullable
<T> T findOne(Query query, Class<T> entityClass);
<T> @Nullable T findOne(Query query, Class<T> entityClass);
/**
* Map the results of an ad-hoc query on the specified collection to a single instance of an object of the specified
@@ -750,8 +750,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @param collectionName name of the collection to retrieve the objects from.
* @return the converted object.
*/
@Nullable
<T> T findOne(Query query, Class<T> entityClass, String collectionName);
<T> @Nullable T findOne(Query query, Class<T> entityClass, String collectionName);
/**
* Determine result of given {@link Query} contains at least one element. <br />
@@ -871,8 +870,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @param entityClass the type the document shall be converted into. Must not be {@literal null}.
* @return the document with the given id mapped onto the given target class.
*/
@Nullable
<T> T findById(Object id, Class<T> entityClass);
<T> @Nullable T findById(Object id, Class<T> entityClass);
/**
* Returns the document with the given id from the given collection mapped onto the given target class.
@@ -882,8 +880,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @param collectionName the collection to query for the document.
* @return he converted object or {@literal null} if document does not exist.
*/
@Nullable
<T> T findById(Object id, Class<T> entityClass, String collectionName);
<T> @Nullable T findById(Object id, Class<T> entityClass, String collectionName);
/**
* Finds the distinct values for a specified {@literal field} across a single {@link MongoCollection} or view and
@@ -960,8 +957,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @see Update
* @see AggregationUpdate
*/
@Nullable
<T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass);
<T> @Nullable T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass);
/**
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify </a>
@@ -980,8 +976,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @see Update
* @see AggregationUpdate
*/
@Nullable
<T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass, String collectionName);
<T> @Nullable T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass, String collectionName);
/**
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify </a>
@@ -1003,8 +998,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @see Update
* @see AggregationUpdate
*/
@Nullable
<T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass);
<T> @Nullable T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass);
/**
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify </a>
@@ -1027,8 +1021,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @see Update
* @see AggregationUpdate
*/
@Nullable
<T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass,
<T> @Nullable T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass,
String collectionName);
/**
@@ -1048,8 +1041,7 @@ public interface MongoOperations extends FluentMongoOperations {
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
@Nullable
default <T> T findAndReplace(Query query, T replacement) {
default <T> @Nullable T findAndReplace(Query query, T replacement) {
return findAndReplace(query, replacement, FindAndReplaceOptions.empty());
}
@@ -1068,8 +1060,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @return the converted object that was updated or {@literal null}, if not found.
* @since 2.1
*/
@Nullable
default <T> T findAndReplace(Query query, T replacement, String collectionName) {
default <T> @Nullable T findAndReplace(Query query, T replacement, String collectionName) {
return findAndReplace(query, replacement, FindAndReplaceOptions.empty(), collectionName);
}
@@ -1091,8 +1082,7 @@ public interface MongoOperations extends FluentMongoOperations {
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
@Nullable
default <T> T findAndReplace(Query query, T replacement, FindAndReplaceOptions options) {
default <T> @Nullable T findAndReplace(Query query, T replacement, FindAndReplaceOptions options) {
return findAndReplace(query, replacement, options, getCollectionName(ClassUtils.getUserClass(replacement)));
}
@@ -1112,8 +1102,7 @@ public interface MongoOperations extends FluentMongoOperations {
* as it is after the update.
* @since 2.1
*/
@Nullable
default <T> T findAndReplace(Query query, T replacement, FindAndReplaceOptions options, String collectionName) {
default <T> @Nullable T findAndReplace(Query query, T replacement, FindAndReplaceOptions options, String collectionName) {
Assert.notNull(replacement, "Replacement must not be null");
return findAndReplace(query, replacement, options, (Class<T>) ClassUtils.getUserClass(replacement), collectionName);
@@ -1137,8 +1126,7 @@ public interface MongoOperations extends FluentMongoOperations {
* as it is after the update.
* @since 2.1
*/
@Nullable
default <T> T findAndReplace(Query query, T replacement, FindAndReplaceOptions options, Class<T> entityType,
default <T> @Nullable T findAndReplace(Query query, T replacement, FindAndReplaceOptions options, Class<T> entityType,
String collectionName) {
return findAndReplace(query, replacement, options, entityType, collectionName, entityType);
@@ -1166,8 +1154,7 @@ public interface MongoOperations extends FluentMongoOperations {
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
@Nullable
default <S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
default <S, T> @Nullable T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
Class<T> resultType) {
return findAndReplace(query, replacement, options, entityType,
@@ -1194,8 +1181,7 @@ public interface MongoOperations extends FluentMongoOperations {
* as it is after the update.
* @since 2.1
*/
@Nullable
<S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
<S, T> @Nullable T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
String collectionName, Class<T> resultType);
/**
@@ -1211,8 +1197,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @param entityClass the parametrized type of the returned list.
* @return the converted object
*/
@Nullable
<T> T findAndRemove(Query query, Class<T> entityClass);
<T> @Nullable T findAndRemove(Query query, Class<T> entityClass);
/**
* Map the results of an ad-hoc query on the specified collection to a single instance of an object of the specified
@@ -1229,8 +1214,7 @@ public interface MongoOperations extends FluentMongoOperations {
* @param collectionName name of the collection to retrieve the objects from.
* @return the converted object.
*/
@Nullable
<T> T findAndRemove(Query query, Class<T> entityClass, String collectionName);
<T> @Nullable T findAndRemove(Query query, Class<T> entityClass, String collectionName);
/**
* Returns the number of documents for the given {@link Query} by querying the collection of the given entity class.

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import com.mongodb.ServerApi;
@@ -31,7 +31,7 @@ import com.mongodb.ServerApiVersion;
*/
public class MongoServerApiFactoryBean implements FactoryBean<ServerApi> {
private String version;
private @Nullable String version;
private @Nullable Boolean deprecationErrors;
private @Nullable Boolean strict;
@@ -59,9 +59,8 @@ public class MongoServerApiFactoryBean implements FactoryBean<ServerApi> {
this.strict = strict;
}
@Nullable
@Override
public ServerApi getObject() throws Exception {
public @Nullable ServerApi getObject() throws Exception {
Builder builder = ServerApi.builder().version(version());
@@ -81,6 +80,11 @@ public class MongoServerApiFactoryBean implements FactoryBean<ServerApi> {
}
private ServerApiVersion version() {
if(version == null) {
return ServerApiVersion.V1;
}
try {
// lookup by name eg. 'V1'
return ObjectUtils.caseInsensitiveValueOf(ServerApiVersion.values(), version);

View File

@@ -15,12 +15,22 @@
*/
package org.springframework.data.mongodb.core;
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import static org.springframework.data.mongodb.core.query.SerializationUtils.serializeToJsonSafely;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
@@ -31,6 +41,7 @@ import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -95,7 +106,18 @@ import org.springframework.data.mongodb.core.index.SearchIndexOperationsProvider
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.event.*;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterDeleteEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterLoadEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeDeleteEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.mongodb.core.mapping.event.MongoMappingEvent;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
import org.springframework.data.mongodb.core.query.BasicQuery;
@@ -110,7 +132,7 @@ import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.projection.EntityProjection;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.Optionals;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -133,7 +155,21 @@ import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import com.mongodb.client.model.*;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.CreateViewOptions;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.EstimatedDocumentCountOptions;
import com.mongodb.client.model.FindOneAndDeleteOptions;
import com.mongodb.client.model.FindOneAndReplaceOptions;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import com.mongodb.client.model.TimeSeriesGranularity;
import com.mongodb.client.model.TimeSeriesOptions;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.ValidationAction;
import com.mongodb.client.model.ValidationLevel;
import com.mongodb.client.model.ValidationOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
@@ -342,7 +378,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
public ReadPreference getReadPreference() {
public @Nullable ReadPreference getReadPreference() {
return this.readPreference;
}
@@ -478,7 +514,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doStream(query, entityType, collectionName, entityType);
}
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected <T> Stream<T> doStream(Query query, Class<?> entityType, String collectionName, Class<T> returnType) {
Assert.notNull(query, "Query must not be null");
@@ -511,7 +547,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
public Document executeCommand(String jsonCommand) {
Assert.hasText(jsonCommand, "JsonCommand must not be null nor empty");
@@ -520,7 +556,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
public Document executeCommand(Document command) {
Assert.notNull(command, "Command must not be null");
@@ -529,7 +565,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
public Document executeCommand(Document command, @Nullable ReadPreference readPreference) {
Assert.notNull(command, "Command must not be null");
@@ -576,7 +612,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
public <T> T execute(DbCallback<T> action) {
public <T> @Nullable T execute(DbCallback<T> action) {
Assert.notNull(action, "DbCallback must not be null");
@@ -589,14 +625,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
public <T> T execute(Class<?> entityClass, CollectionCallback<T> callback) {
public <T> @Nullable T execute(Class<?> entityClass, CollectionCallback<T> callback) {
Assert.notNull(entityClass, "EntityClass must not be null");
return execute(getCollectionName(entityClass), callback);
}
@Override
public <T> T execute(String collectionName, CollectionCallback<T> callback) {
public <T> @Nullable T execute(String collectionName, CollectionCallback<T> callback) {
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(callback, "CollectionCallback must not be null");
@@ -618,6 +654,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@Contract("_ -> new")
public MongoTemplate withSession(ClientSession session) {
Assert.notNull(session, "ClientSession must not be null");
@@ -691,6 +728,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doCreateView(name, source, aggregation.getAggregationPipeline(), options);
}
@SuppressWarnings("NullAway")
protected MongoCollection<Document> doCreateView(String name, String source, List<Document> pipeline,
@Nullable ViewOptions options) {
@@ -706,8 +744,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
public MongoCollection<Document> getCollection(String collectionName) {
@SuppressWarnings({ "ConstantConditions", "NullAway" })
@Contract("null -> fail")
public MongoCollection<Document> getCollection(@Nullable String collectionName) {
Assert.notNull(collectionName, "CollectionName must not be null");
@@ -720,7 +759,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
public boolean collectionExists(String collectionName) {
Assert.notNull(collectionName, "CollectionName must not be null");
@@ -854,7 +893,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
public boolean exists(Query query, @Nullable Class<?> entityClass, String collectionName) {
if (query == null) {
@@ -956,7 +995,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "NullAway" })
public <T> List<T> findDistinct(Query query, String field, String collectionName, Class<?> entityClass,
Class<T> resultClass) {
@@ -1074,20 +1113,22 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Nullable
@Override
public <T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass, String collectionName) {
public <T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass,
String collectionName) {
return findAndModify(query, update, new FindAndModifyOptions(), entityClass, collectionName);
}
@Nullable
@Override
public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass) {
public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options,
Class<T> entityClass) {
return findAndModify(query, update, options, entityClass, getCollectionName(entityClass));
}
@Nullable
@Override
public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass,
String collectionName) {
public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options,
Class<T> entityClass, String collectionName) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
@@ -1111,8 +1152,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
public <S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
String collectionName, Class<T> resultType) {
public <S, T> @Nullable T findAndReplace(Query query, S replacement, FindAndReplaceOptions options,
Class<S> entityType, String collectionName, Class<T> resultType) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(replacement, "Replacement must not be null");
@@ -1223,6 +1264,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doEstimatedCount(CollectionPreparerDelegate.of(this), collectionName, new EstimatedDocumentCountOptions());
}
@SuppressWarnings("NullAway")
protected long doEstimatedCount(CollectionPreparer<MongoCollection<Document>> collectionPreparer,
String collectionName, EstimatedDocumentCountOptions options) {
return execute(collectionName,
@@ -1240,6 +1282,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doExactCount(createDelegate(query), collectionName, mappedQuery, options);
}
@SuppressWarnings("NullAway")
protected long doExactCount(CollectionPreparer<MongoCollection<Document>> collectionPreparer, String collectionName,
Document filter, CountOptions options) {
return execute(collectionName, collection -> collectionPreparer.prepare(collection)
@@ -1543,7 +1586,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return maybeCallAfterSave(saved, dbDoc, collectionName);
}
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected Object insertDocument(String collectionName, Document document, Class<?> entityClass) {
if (LOGGER.isDebugEnabled()) {
@@ -1597,6 +1640,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return MappedDocument.toIds(documents);
}
@SuppressWarnings("NullAway")
protected Object saveDocument(String collectionName, Document dbDoc, Class<?> entityClass) {
if (LOGGER.isDebugEnabled()) {
@@ -1695,7 +1739,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doUpdate(collectionName, query, update, entityClass, false, true);
}
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected UpdateResult doUpdate(String collectionName, Query query, UpdateDefinition update,
@Nullable Class<?> entityClass, boolean upsert, boolean multi) {
@@ -1805,7 +1849,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doRemove(collectionName, query, entityClass, true);
}
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected <T> DeleteResult doRemove(String collectionName, Query query, @Nullable Class<T> entityClass,
boolean multi) {
@@ -2126,6 +2170,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @param entityClass
* @return
*/
@SuppressWarnings("NullAway")
protected <T> List<T> doFindAndDelete(String collectionName, Query query, Class<T> entityClass) {
List<T> result = find(query, entityClass, collectionName);
@@ -2159,7 +2204,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doAggregate(aggregation, collectionName, outputType, context.getAggregationOperationContext());
}
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected <O> AggregationResults<O> doAggregate(Aggregation aggregation, String collectionName, Class<O> outputType,
AggregationOperationContext context) {
@@ -2242,7 +2287,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
});
}
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected <O> Stream<O> aggregateStream(Aggregation aggregation, String collectionName, Class<O> outputType,
@Nullable AggregationOperationContext context) {
@@ -2357,7 +2402,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
public Set<String> getCollectionNames() {
return execute(db -> {
Set<String> result = new LinkedHashSet<>();
@@ -2441,7 +2486,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @return the collection that was created
* @since 3.3.3
*/
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
protected MongoCollection<Document> doCreateCollection(String collectionName,
CreateCollectionOptions collectionOptions) {
@@ -2520,8 +2565,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @return the converted object or {@literal null} if none exists.
*/
@Nullable
protected <T> T doFindOne(String collectionName, CollectionPreparer<MongoCollection<Document>> collectionPreparer,
Document query, Document fields, Class<T> entityClass) {
protected <T> T doFindOne(String collectionName,
CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields,
Class<T> entityClass) {
return doFindOne(collectionName, collectionPreparer, query, fields, CursorPreparer.NO_OP_PREPARER, entityClass);
}
@@ -2540,8 +2586,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
*/
@Nullable
@SuppressWarnings("ConstantConditions")
protected <T> T doFindOne(String collectionName, CollectionPreparer<MongoCollection<Document>> collectionPreparer,
Document query, Document fields, CursorPreparer preparer, Class<T> entityClass) {
protected <T> T doFindOne(String collectionName,
CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields,
CursorPreparer preparer, Class<T> entityClass) {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
@@ -2717,8 +2764,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @return the List of converted objects.
*/
@SuppressWarnings("ConstantConditions")
protected <T> T doFindAndRemove(CollectionPreparer collectionPreparer, String collectionName, Document query,
Document fields, Document sort, @Nullable Collation collation, Class<T> entityClass) {
protected <T> @Nullable T doFindAndRemove(CollectionPreparer collectionPreparer, String collectionName,
Document query, @Nullable Document fields, @Nullable Document sort, @Nullable Collation collation,
Class<T> entityClass) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("findAndRemove using query: %s fields: %s sort: %s for class: %s in collection: %s",
@@ -2733,8 +2781,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@SuppressWarnings("ConstantConditions")
protected <T> T doFindAndModify(CollectionPreparer collectionPreparer, String collectionName, Document query,
Document fields, Document sort, Class<T> entityClass, UpdateDefinition update,
protected <T> @Nullable T doFindAndModify(CollectionPreparer collectionPreparer, String collectionName,
Document query, @Nullable Document fields, @Nullable Document sort, Class<T> entityClass, UpdateDefinition update,
@Nullable FindAndModifyOptions options) {
if (options == null) {
@@ -2779,9 +2827,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* {@literal false} and {@link FindAndReplaceOptions#isUpsert() upsert} is {@literal false}.
*/
@Nullable
protected <T> T doFindAndReplace(CollectionPreparer collectionPreparer, String collectionName, Document mappedQuery,
Document mappedFields, Document mappedSort, @Nullable com.mongodb.client.model.Collation collation,
Class<?> entityType, Document replacement, FindAndReplaceOptions options, Class<T> resultType) {
protected <T> T doFindAndReplace(CollectionPreparer collectionPreparer, String collectionName,
Document mappedQuery, Document mappedFields, Document mappedSort,
com.mongodb.client.model.@Nullable Collation collation, Class<?> entityType, Document replacement,
FindAndReplaceOptions options, Class<T> resultType) {
EntityProjection<T, ?> projection = operations.introspectProjection(resultType, entityType);
@@ -2821,9 +2870,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @since 3.4
*/
@Nullable
private <T> T doFindAndReplace(CollectionPreparer collectionPreparer, String collectionName, Document mappedQuery,
Document mappedFields, Document mappedSort, @Nullable com.mongodb.client.model.Collation collation,
Class<?> entityType, Document replacement, FindAndReplaceOptions options, EntityProjection<T, ?> projection) {
private <T> T doFindAndReplace(CollectionPreparer collectionPreparer, String collectionName,
Document mappedQuery, Document mappedFields, Document mappedSort,
com.mongodb.client.model.@Nullable Collation collation, Class<?> entityType, Document replacement,
FindAndReplaceOptions options, EntityProjection<T, ?> projection) {
if (LOGGER.isDebugEnabled()) {
LOGGER
@@ -2839,6 +2889,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
collectionName);
}
@SuppressWarnings("NullAway")
private <S> UpdateResult doReplace(ReplaceOptions options, Class<S> entityType, String collectionName,
UpdateContext updateContext, CollectionPreparer<MongoCollection<Document>> collectionPreparer,
Document replacement) {
@@ -2999,13 +3050,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return getMappedSortObject(query.getSortObject(), type);
}
@Nullable
private Document getMappedSortObject(Document sortObject, Class<?> type) {
private @Nullable Document getMappedSortObject(@Nullable Document sortObject, Class<?> type) {
return getMappedSortObject(sortObject, mappingContext.getPersistentEntity(type));
}
@Nullable
private Document getMappedSortObject(Document sortObject, @Nullable MongoPersistentEntity<?> entity) {
private @Nullable Document getMappedSortObject(@Nullable Document sortObject, @Nullable MongoPersistentEntity<?> entity) {
if (ObjectUtils.isEmpty(sortObject)) {
return null;
@@ -3081,10 +3131,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
private final CollectionPreparer<MongoCollection<Document>> collectionPreparer;
private final Document query;
private final Document fields;
private final @Nullable com.mongodb.client.model.Collation collation;
private final com.mongodb.client.model.@Nullable Collation collation;
public FindCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, @Nullable com.mongodb.client.model.Collation collation) {
Document fields, com.mongodb.client.model.@Nullable Collation collation) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(fields, "Fields must not be null");
@@ -3120,10 +3170,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
private final CollectionPreparer collectionPreparer;
private final Document mappedQuery;
private final com.mongodb.client.model.Collation collation;
private final com.mongodb.client.model.@Nullable Collation collation;
ExistsCallback(CollectionPreparer collectionPreparer, Document mappedQuery,
com.mongodb.client.model.Collation collation) {
com.mongodb.client.model.@Nullable Collation collation) {
this.collectionPreparer = collectionPreparer;
this.mappedQuery = mappedQuery;
@@ -3148,12 +3198,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
private final CollectionPreparer<MongoCollection<Document>> collectionPreparer;
private final Document query;
private final Document fields;
private final Document sort;
private final @Nullable Document fields;
private final @Nullable Document sort;
private final Optional<Collation> collation;
FindAndRemoveCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, Document sort, @Nullable Collation collation) {
@Nullable Document fields, @Nullable Document sort, @Nullable Collation collation) {
this.collectionPreparer = collectionPreparer;
this.query = query;
@@ -3176,14 +3226,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
private final CollectionPreparer<MongoCollection<Document>> collectionPreparer;
private final Document query;
private final Document fields;
private final Document sort;
private final @Nullable Document fields;
private final @Nullable Document sort;
private final Object update;
private final List<Document> arrayFilters;
private final FindAndModifyOptions options;
FindAndModifyCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, Document sort, Object update, List<Document> arrayFilters, FindAndModifyOptions options) {
@Nullable Document fields, @Nullable Document sort, Object update, List<Document> arrayFilters,
FindAndModifyOptions options) {
this.collectionPreparer = collectionPreparer;
this.query = query;
@@ -3237,11 +3288,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
private final Document fields;
private final Document sort;
private final Document update;
private final @Nullable com.mongodb.client.model.Collation collation;
private final com.mongodb.client.model.@Nullable Collation collation;
private final FindAndReplaceOptions options;
FindAndReplaceCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, Document sort, Document update, @Nullable com.mongodb.client.model.Collation collation,
Document fields, Document sort, Document update, com.mongodb.client.model.@Nullable Collation collation,
FindAndReplaceOptions options) {
this.collectionPreparer = collectionPreparer;
this.query = query;
@@ -3347,10 +3398,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("unchecked")
public T doWith(Document document) {
if (document == null) {
return null;
}
maybeEmitEvent(new AfterLoadEvent<>(document, projection.getMappedType().getType(), collectionName));
Object entity = mongoConverter.project(projection, document);
@@ -3595,8 +3642,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
throw potentiallyConvertRuntimeException(ex, exceptionTranslator);
} finally {
cursor = null;
exceptionTranslator = null;
objectReadCallback = null;
}
}
}
@@ -3628,7 +3673,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
@Override
public MongoCollection<Document> getCollection(String collectionName) {
public MongoCollection<Document> getCollection(@Nullable String collectionName) {
// native MongoDB objects that offer methods with ClientSession must not be proxied.
return delegate.getCollection(collectionName);

View File

@@ -31,6 +31,7 @@ import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mapping.context.MappingContext;
@@ -62,7 +63,7 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
import org.springframework.data.mongodb.util.BsonUtils;
import org.springframework.data.projection.EntityProjection;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import com.mongodb.client.model.CountOptions;
@@ -283,6 +284,7 @@ class QueryOperations {
* @param <T>
* @return the {@link MappedDocument} containing the changes.
*/
@SuppressWarnings("NullAway")
<T> MappedDocument prepareId(@Nullable MongoPersistentEntity<T> entity) {
if (entity == null || source.hasId()) {
@@ -361,6 +363,7 @@ class QueryOperations {
return queryMapper.getMappedObject(getQueryObject(), entity);
}
@SuppressWarnings("NullAway")
Document getMappedFields(@Nullable MongoPersistentEntity<?> entity, EntityProjection<?, ?> projection) {
Document fields = evaluateFields(entity);
@@ -888,6 +891,8 @@ class QueryOperations {
*/
List<Document> getUpdatePipeline(@Nullable Class<?> domainType) {
Assert.isInstanceOf(AggregationUpdate.class, update);
Class<?> type = domainType != null ? domainType : Object.class;
AggregationOperationContext context = new RelaxedTypeBasedAggregationOperationContext(type, mappingContext,
@@ -901,6 +906,7 @@ class QueryOperations {
* @param entity
* @return
*/
@SuppressWarnings("NullAway")
Document getMappedUpdate(@Nullable MongoPersistentEntity<?> entity) {
if (update != null) {

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Flux;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
@@ -59,11 +60,11 @@ class ReactiveAggregationOperationSupport implements ReactiveAggregationOperatio
private final ReactiveMongoTemplate template;
private final Class<T> domainType;
private final Aggregation aggregation;
private final String collection;
private final @Nullable Aggregation aggregation;
private final @Nullable String collection;
ReactiveAggregationSupport(ReactiveMongoTemplate template, Class<T> domainType, Aggregation aggregation,
String collection) {
ReactiveAggregationSupport(ReactiveMongoTemplate template, Class<T> domainType, @Nullable Aggregation aggregation,
@Nullable String collection) {
this.template = template;
this.domainType = domainType;
@@ -89,6 +90,9 @@ class ReactiveAggregationOperationSupport implements ReactiveAggregationOperatio
@Override
public Flux<T> all() {
Assert.notNull(aggregation, "Aggregation must be set first");
return template.aggregate(aggregation, getCollectionName(aggregation), domainType);
}

View File

@@ -24,11 +24,11 @@ import java.util.function.Consumer;
import org.bson.BsonTimestamp;
import org.bson.BsonValue;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.ChangeStreamOptions.ChangeStreamOptionsBuilder;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -19,6 +19,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
@@ -26,7 +27,6 @@ import org.springframework.data.mongodb.core.CollectionPreparerSupport.ReactiveC
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.SerializationUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -67,10 +67,10 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
private final ReactiveMongoTemplate template;
private final Class<?> domainType;
private final Class<T> returnType;
private final String collection;
private final @Nullable String collection;
private final Query query;
ReactiveFindSupport(ReactiveMongoTemplate template, Class<?> domainType, Class<T> returnType, String collection,
ReactiveFindSupport(ReactiveMongoTemplate template, Class<?> domainType, Class<T> returnType, @Nullable String collection,
Query query) {
this.template = template;

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -50,9 +51,9 @@ class ReactiveInsertOperationSupport implements ReactiveInsertOperation {
private final ReactiveMongoTemplate template;
private final Class<T> domainType;
private final String collection;
private final @Nullable String collection;
ReactiveInsertSupport(ReactiveMongoTemplate template, Class<T> domainType, String collection) {
ReactiveInsertSupport(ReactiveMongoTemplate template, Class<T> domainType, @Nullable String collection) {
this.template = template;
this.domainType = domainType;

View File

@@ -17,9 +17,9 @@ package org.springframework.data.mongodb.core;
import reactor.core.publisher.Flux;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -89,8 +89,11 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public Flux<T> all() {
Assert.notNull(mapFunction, "MapFunction must be set first");
Assert.notNull(reduceFunction, "ReduceFunction must be set first");
return template.mapReduce(query, domainType, getCollectionName(), returnType, mapFunction, reduceFunction,
options);
options != null ? options : MapReduceOptions.options());
}
/*

View File

@@ -16,10 +16,10 @@
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.MongoClientSettings;
@@ -89,7 +89,7 @@ public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoCli
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
@@ -124,7 +124,9 @@ public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoCli
@Override
protected void destroyInstance(@Nullable MongoClient instance) throws Exception {
instance.close();
if (instance != null) {
instance.close();
}
}
}

View File

@@ -23,6 +23,7 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.data.domain.KeysetScrollPosition;
@@ -48,7 +49,6 @@ import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import static org.springframework.data.mongodb.core.query.SerializationUtils.serializeToJsonSafely;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -44,9 +44,9 @@ import org.bson.BsonValue;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -109,7 +109,18 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
import org.springframework.data.mongodb.core.mapping.event.*;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterDeleteEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterLoadEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeDeleteEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.mongodb.core.mapping.event.MongoMappingEvent;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeSaveCallback;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Collation;
@@ -120,7 +131,7 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
import org.springframework.data.projection.EntityProjection;
import org.springframework.data.util.Optionals;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -344,7 +355,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @param writeConcernResolver can be {@literal null}.
*/
public void setWriteConcernResolver(@Nullable WriteConcernResolver writeConcernResolver) {
this.writeConcernResolver = writeConcernResolver;
this.writeConcernResolver = writeConcernResolver != null ? writeConcernResolver
: DefaultWriteConcernResolver.INSTANCE;
}
/**
@@ -738,10 +750,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<Boolean> collectionExists(String collectionName) {
return createMono(db -> Flux.from(db.listCollectionNames()) //
.filter(s -> s.equals(collectionName)) //
.map(s -> true) //
.single(false));
return createMono(
db -> Flux.from(db.listCollectionNames()) //
.filter(s -> s.equals(collectionName)) //
.map(s -> true) //
.single(false));
}
@Override
@@ -898,7 +911,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Mono<List<T>> result = doFind(collectionName, ReactiveCollectionPreparerDelegate.of(query),
keysetPaginationQuery.query(), keysetPaginationQuery.fields(), sourceClass,
new QueryFindPublisherPreparer(query, keysetPaginationQuery.sort(), limit, 0, sourceClass), callback)
.collectList();
.collectList();
return result.map(it -> ScrollUtils.createWindow(query, it, sourceClass, operations));
}
@@ -906,7 +919,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Mono<List<T>> result = doFind(collectionName, ReactiveCollectionPreparerDelegate.of(query), query.getQueryObject(),
query.getFieldsObject(), sourceClass,
new QueryFindPublisherPreparer(query, query.getSortObject(), limit, query.getSkip(), sourceClass), callback)
.collectList();
.collectList();
return result.map(
it -> ScrollUtils.createWindow(it, query.getLimit(), OffsetScrollPosition.positionFunction(query.getSkip())));
@@ -1145,6 +1158,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
@Override
@SuppressWarnings("NullAway")
public <S, T> Mono<T> findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
String collectionName, Class<T> resultType) {
@@ -1350,6 +1364,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return doInsert(collectionName, objectToSave, this.mongoConverter);
}
@SuppressWarnings("NullAway")
protected <T> Mono<T> doInsert(String collectionName, T objectToSave, MongoWriter<Object> writer) {
return Mono.just(PersistableEntityModel.of(objectToSave, collectionName)) //
@@ -1400,6 +1415,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return Flux.from(objectsToSave).flatMapSequential(this::insertAll);
}
@SuppressWarnings("NullAway")
protected <T> Flux<T> doInsertAll(Collection<? extends T> listToSave, MongoWriter<Object> writer) {
Map<String, List<T>> elementsByCollection = new HashMap<>();
@@ -1416,6 +1432,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
.concatMap(collectionName -> doInsertBatch(collectionName, elementsByCollection.get(collectionName), writer));
}
@SuppressWarnings("NullAway")
protected <T> Flux<T> doInsertBatch(String collectionName, Collection<? extends T> batchToSave,
MongoWriter<Object> writer) {
@@ -1536,6 +1553,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
});
}
@SuppressWarnings("NullAway")
protected <T> Mono<T> doSave(String collectionName, T objectToSave, MongoWriter<Object> writer) {
assertUpdateableIdIfNotSet(objectToSave);
@@ -1629,6 +1647,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return collectionToUse;
}
@SuppressWarnings("NullAway")
protected Mono<Object> saveDocument(String collectionName, Document document, Class<?> entityClass) {
if (LOGGER.isDebugEnabled()) {
@@ -1732,7 +1751,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return doUpdate(collectionName, query, update, entityClass, false, true);
}
protected Mono<UpdateResult> doUpdate(String collectionName, Query query, @Nullable UpdateDefinition update,
@SuppressWarnings("NullAway")
protected Mono<UpdateResult> doUpdate(String collectionName, Query query, UpdateDefinition update,
@Nullable Class<?> entityClass, boolean upsert, boolean multi) {
MongoPersistentEntity<?> entity = entityClass == null ? null : getPersistentEntity(entityClass);
@@ -1814,7 +1834,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Document updateObj = updateContext.getMappedUpdate(entity);
if (containsVersionProperty(queryObj, entity))
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity %s to collection %s".formatted(entity.getName(), collectionName));
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity %s to collection %s"
.formatted(entity.getName(), collectionName));
}
}
});
@@ -2012,18 +2033,18 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Flux<T> tail(@Nullable Query query, Class<T> entityClass, String collectionName) {
ReactiveCollectionPreparerDelegate collectionPreparer = ReactiveCollectionPreparerDelegate.of(query);
if (query == null) {
LOGGER.debug(String.format("Tail for class: %s in collection: %s", entityClass, collectionName));
return executeFindMultiInternal(
collection -> new FindCallback(collectionPreparer, null).doInCollection(collection)
collection -> new FindCallback(CollectionPreparer.identity(), null).doInCollection(collection)
.cursorType(CursorType.TailableAwait),
FindPublisherPreparer.NO_OP_PREPARER, new ReadDocumentCallback<>(mongoConverter, entityClass, collectionName),
collectionName);
}
ReactiveCollectionPreparerDelegate collectionPreparer = ReactiveCollectionPreparerDelegate.of(query);
return doFind(collectionName, collectionPreparer, query.getQueryObject(), query.getFieldsObject(), entityClass,
new TailingQueryFindPublisherPreparer(query, entityClass));
}
@@ -2382,8 +2403,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
serializeToJsonSafely(mappedQuery), mappedFields, entityClass, collectionName));
}
return executeFindMultiInternal(new FindCallback(collectionPreparer, mappedQuery, mappedFields), preparer,
objectCallback, collectionName);
return executeFindMultiInternal(new FindCallback(collectionPreparer, mappedQuery, mappedFields),
preparer != null ? preparer : FindPublisherPreparer.NO_OP_PREPARER, objectCallback, collectionName);
}
CollectionPreparer<MongoCollection<Document>> createCollectionPreparer(Query query) {
@@ -2448,8 +2469,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @return the List of converted objects.
*/
protected <T> Mono<T> doFindAndRemove(String collectionName,
CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields, Document sort,
@Nullable Collation collation, Class<T> entityClass) {
CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields,
@Nullable Document sort, @Nullable Collation collation, Class<T> entityClass) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("findAndRemove using query: %s fields: %s sort: %s for class: %s in collection: %s",
@@ -2464,8 +2485,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
protected <T> Mono<T> doFindAndModify(String collectionName,
CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields, Document sort,
Class<T> entityClass, UpdateDefinition update, FindAndModifyOptions options) {
CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields,
@Nullable Document sort, Class<T> entityClass, UpdateDefinition update, FindAndModifyOptions options) {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
UpdateContext updateContext = queryOperations.updateSingleContext(update, query, false);
@@ -2481,8 +2502,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
LOGGER.debug(String.format(
"findAndModify using query: %s fields: %s sort: %s for class: %s and update: %s " + "in collection: %s",
serializeToJsonSafely(mappedQuery), fields, serializeToJsonSafely(sort), entityClass,
serializeToJsonSafely(mappedUpdate),
collectionName));
serializeToJsonSafely(mappedUpdate), collectionName));
}
return executeFindOneInternal(
@@ -2659,8 +2679,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @see #setWriteConcern(WriteConcern)
* @see #setWriteConcernResolver(WriteConcernResolver)
*/
@Nullable
protected WriteConcern prepareWriteConcern(MongoAction mongoAction) {
protected @Nullable WriteConcern prepareWriteConcern(MongoAction mongoAction) {
WriteConcern wc = writeConcernResolver.resolve(mongoAction);
return potentiallyForceAcknowledgedWrite(wc);
@@ -2679,7 +2698,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (ObjectUtils.nullSafeEquals(WriteResultChecking.EXCEPTION, writeResultChecking)) {
if (wc == null || wc.getWObject() == null
|| (wc.getWObject()instanceof Number concern && concern.intValue() < 1)) {
|| (wc.getWObject() instanceof Number concern && concern.intValue() < 1)) {
return WriteConcern.ACKNOWLEDGED;
}
}
@@ -2725,7 +2744,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
* @return
*/
private <T> Flux<T> executeFindMultiInternal(ReactiveCollectionQueryCallback<Document> collectionCallback,
@Nullable FindPublisherPreparer preparer, DocumentCallback<T> objectCallback, String collectionName) {
FindPublisherPreparer preparer, DocumentCallback<T> objectCallback, String collectionName) {
return createFlux(collectionName, collection -> {
return Flux.from(preparer.initiateFind(collection, collectionCallback::doInCollection))
@@ -2764,8 +2783,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return resolved == null ? ex : resolved;
}
@Nullable
private MongoPersistentEntity<?> getPersistentEntity(@Nullable Class<?> type) {
private @Nullable MongoPersistentEntity<?> getPersistentEntity(@Nullable Class<?> type) {
return type == null ? null : mappingContext.getPersistentEntity(type);
}
@@ -2785,8 +2803,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return converter;
}
@Nullable
private Document getMappedSortObject(Query query, Class<?> type) {
@Contract("null, _ -> null")
private @Nullable Document getMappedSortObject(@Nullable Query query, Class<?> type) {
if (query == null) {
return null;
@@ -2795,8 +2813,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return getMappedSortObject(query.getSortObject(), type);
}
@Nullable
private Document getMappedSortObject(Document sortObject, Class<?> type) {
@Contract("null, _ -> null")
private @Nullable Document getMappedSortObject(@Nullable Document sortObject, Class<?> type) {
if (ObjectUtils.isEmpty(sortObject)) {
return null;
@@ -2862,7 +2880,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
this(collectionPreparer, query, null);
}
FindCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query, Document fields) {
FindCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, @Nullable Document query,
@Nullable Document fields) {
this.collectionPreparer = collectionPreparer;
this.query = query;
this.fields = fields;
@@ -2898,11 +2917,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
private final CollectionPreparer<MongoCollection<Document>> collectionPreparer;
private final Document query;
private final Document fields;
private final Document sort;
private final @Nullable Document sort;
private final Optional<Collation> collation;
FindAndRemoveCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, Document sort, @Nullable Collation collation) {
Document fields, @Nullable Document sort, @Nullable Collation collation) {
this.collectionPreparer = collectionPreparer;
this.query = query;
this.fields = fields;
@@ -2928,14 +2947,15 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
private final CollectionPreparer<MongoCollection<Document>> collectionPreparer;
private final Document query;
private final Document fields;
private final Document sort;
private final @Nullable Document fields;
private final @Nullable Document sort;
private final Object update;
private final List<Document> arrayFilters;
private final FindAndModifyOptions options;
FindAndModifyCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, Document sort, Object update, List<Document> arrayFilters, FindAndModifyOptions options) {
@Nullable Document fields, @Nullable Document sort, Object update, List<Document> arrayFilters,
FindAndModifyOptions options) {
this.collectionPreparer = collectionPreparer;
this.query = query;
@@ -2973,7 +2993,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
private static FindOneAndUpdateOptions convertToFindOneAndUpdateOptions(FindAndModifyOptions options,
Document fields, Document sort, List<Document> arrayFilters) {
@Nullable Document fields, @Nullable Document sort, List<Document> arrayFilters) {
FindOneAndUpdateOptions result = new FindOneAndUpdateOptions();
@@ -3009,11 +3029,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
private final Document fields;
private final Document sort;
private final Document update;
private final @Nullable com.mongodb.client.model.Collation collation;
private final com.mongodb.client.model.@Nullable Collation collation;
private final FindAndReplaceOptions options;
FindAndReplaceCallback(CollectionPreparer<MongoCollection<Document>> collectionPreparer, Document query,
Document fields, Document sort, Document update, com.mongodb.client.model.Collation collation,
Document fields, Document sort, Document update, com.mongodb.client.model.@Nullable Collation collation,
FindAndReplaceOptions options) {
this.collectionPreparer = collectionPreparer;
this.query = query;
@@ -3049,7 +3069,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
}
private static FindOneAndDeleteOptions convertToFindOneAndDeleteOptions(Document fields, Document sort) {
private static FindOneAndDeleteOptions convertToFindOneAndDeleteOptions(@Nullable Document fields,
@Nullable Document sort) {
FindOneAndDeleteOptions result = new FindOneAndDeleteOptions();
result = result.projection(fields).sort(sort);

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -54,9 +55,9 @@ class ReactiveRemoveOperationSupport implements ReactiveRemoveOperation {
private final ReactiveMongoTemplate template;
private final Class<T> domainType;
private final Query query;
private final String collection;
private final @Nullable String collection;
ReactiveRemoveSupport(ReactiveMongoTemplate template, Class<T> domainType, Query query, String collection) {
ReactiveRemoveSupport(ReactiveMongoTemplate template, Class<T> domainType, Query query, @Nullable String collection) {
this.template = template;
this.domainType = domainType;

View File

@@ -17,9 +17,9 @@ package org.springframework.data.mongodb.core;
import reactor.core.publisher.Mono;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -57,16 +57,16 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
private final ReactiveMongoTemplate template;
private final Class<?> domainType;
private final Query query;
private final org.springframework.data.mongodb.core.query.UpdateDefinition update;
@Nullable private final String collection;
@Nullable private final FindAndModifyOptions findAndModifyOptions;
@Nullable private final FindAndReplaceOptions findAndReplaceOptions;
@Nullable private final Object replacement;
private final org.springframework.data.mongodb.core.query.@Nullable UpdateDefinition update;
private final @Nullable String collection;
private final @Nullable FindAndModifyOptions findAndModifyOptions;
private final @Nullable FindAndReplaceOptions findAndReplaceOptions;
private final @Nullable Object replacement;
private final Class<T> targetType;
ReactiveUpdateSupport(ReactiveMongoTemplate template, Class<?> domainType, Query query, UpdateDefinition update,
String collection, FindAndModifyOptions findAndModifyOptions, FindAndReplaceOptions findAndReplaceOptions,
Object replacement, Class<T> targetType) {
ReactiveUpdateSupport(ReactiveMongoTemplate template, Class<?> domainType, Query query, @Nullable UpdateDefinition update,
@Nullable String collection, @Nullable FindAndModifyOptions findAndModifyOptions, @Nullable FindAndReplaceOptions findAndReplaceOptions,
@Nullable Object replacement, Class<T> targetType) {
this.template = template;
this.domainType = domainType;
@@ -108,6 +108,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
}
@Override
@SuppressWarnings("NullAway")
public Mono<T> findAndModify() {
String collectionName = getCollectionName();
@@ -118,7 +119,11 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
}
@Override
@SuppressWarnings({"unchecked","rawtypes"})
public Mono<T> findAndReplace() {
Assert.notNull(replacement, "Replacement must be set first");
return template.findAndReplace(query, replacement,
findAndReplaceOptions != null ? findAndReplaceOptions : FindAndReplaceOptions.none(), (Class) domainType,
getCollectionName(), targetType);
@@ -186,6 +191,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
}
@Override
@SuppressWarnings("NullAway")
public Mono <UpdateResult> replaceFirst() {
if (replacement != null) {
@@ -197,6 +203,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName());
}
@SuppressWarnings("NullAway")
private Mono<UpdateResult> doUpdate(boolean multi, boolean upsert) {
return template.doUpdate(getCollectionName(), query, update, domainType, upsert, multi);
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import com.mongodb.ReadConcern;

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import com.mongodb.ReadPreference;

View File

@@ -16,6 +16,7 @@
package org.springframework.data.mongodb.core;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Contract;
/**
* Options for {@link org.springframework.data.mongodb.core.MongoOperations#replace(Query, Object) replace operations}. Defaults to
@@ -69,6 +70,7 @@ public class ReplaceOptions {
*
* @return this.
*/
@Contract("-> this")
public ReplaceOptions upsert() {
this.upsert = true;

View File

@@ -17,9 +17,9 @@ package org.springframework.data.mongodb.core;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.lang.Nullable;
/**

View File

@@ -29,6 +29,7 @@ import org.springframework.data.domain.ScrollPosition.Direction;
import org.springframework.data.domain.Window;
import org.springframework.data.mongodb.core.EntityOperations.Entity;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.Assert;
/**
* Utilities to run scroll queries and create {@link Window} results.
@@ -48,7 +49,11 @@ class ScrollUtils {
*/
static KeysetScrollQuery createKeysetPaginationQuery(Query query, String idPropertyName) {
KeysetScrollPosition keyset = query.getKeyset();
Assert.notNull(keyset, "Query.keyset must not be null");
KeysetScrollDirector director = KeysetScrollDirector.of(keyset.getDirection());
Document sortObject = director.getSortObject(idPropertyName, query);
Document fieldsObject = director.getFieldsObject(query.getFieldsObject(), sortObject);
@@ -61,6 +66,9 @@ class ScrollUtils {
Document sortObject = query.getSortObject();
KeysetScrollPosition keyset = query.getKeyset();
Assert.notNull(keyset, "Query.keyset must not be null");
Direction direction = keyset.getDirection();
KeysetScrollDirector director = KeysetScrollDirector.of(direction);

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
/**
* Callback interface for executing operations within a {@link com.mongodb.session.ClientSession}.

View File

@@ -17,10 +17,10 @@ package org.springframework.data.mongodb.core;
import java.util.function.Consumer;
import org.springframework.lang.Nullable;
import com.mongodb.client.ClientSession;
import org.jspecify.annotations.Nullable;
/**
* Gateway interface to execute {@link ClientSession} bound operations against MongoDB via a {@link SessionCallback}.
* <br />
@@ -42,8 +42,7 @@ public interface SessionScoped {
* @param <T> return type.
* @return a result object returned by the action. Can be {@literal null}.
*/
@Nullable
default <T> T execute(SessionCallback<T> action) {
default <T> @Nullable T execute(SessionCallback<T> action) {
return execute(action, session -> {});
}
@@ -60,6 +59,5 @@ public interface SessionScoped {
* @param <T> return type.
* @return a result object returned by the action. Can be {@literal null}.
*/
@Nullable
<T> T execute(SessionCallback<T> action, Consumer<ClientSession> doFinally);
<T> @Nullable T execute(SessionCallback<T> action, Consumer<ClientSession> doFinally);
}

View File

@@ -18,13 +18,13 @@ package org.springframework.data.mongodb.core;
import reactor.core.publisher.Mono;
import org.bson.codecs.configuration.CodecRegistry;
import org.jspecify.annotations.Nullable;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.SessionAwareMethodInterceptor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

View File

@@ -17,8 +17,9 @@ package org.springframework.data.mongodb.core;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
/**
* Immutable object holding additional options to be applied when creating a MongoDB
@@ -59,6 +60,7 @@ public class ViewOptions {
* @param collation the {@link Collation} to use for language-specific string comparison.
* @return new instance of {@link ViewOptions}.
*/
@Contract("_ -> new")
public ViewOptions collation(Collation collation) {
return new ViewOptions(collation);
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import com.mongodb.WriteConcern;

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import com.mongodb.WriteConcern;

View File

@@ -26,6 +26,7 @@ import java.util.Map;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
@@ -282,7 +283,7 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
* @since 2.1
*/
@SuppressWarnings("unchecked")
protected <T> T get(Object key) {
protected <T> @Nullable T get(Object key) {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");

Some files were not shown because too many files have changed in this diff Show More