committed by
Mark Paluch
parent
0c5a908cf4
commit
6531bc792b
@@ -18,11 +18,9 @@ package org.springframework.data.mongodb.core;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -90,9 +88,6 @@ abstract class IndexConverters {
|
||||
if (indexOptions.containsKey("bits")) {
|
||||
ops = ops.bits((Integer) indexOptions.get("bits"));
|
||||
}
|
||||
if (indexOptions.containsKey("bucketSize")) {
|
||||
MongoCompatibilityAdapter.indexOptionsAdapter(ops).setBucketSize(((Number) indexOptions.get("bucketSize")).doubleValue());
|
||||
}
|
||||
if (indexOptions.containsKey("default_language")) {
|
||||
ops = ops.defaultLanguage(indexOptions.get("default_language").toString());
|
||||
}
|
||||
|
||||
@@ -25,9 +25,7 @@ import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.bson.UuidRepresentation;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -57,8 +55,6 @@ public class MongoClientSettingsFactoryBean extends AbstractFactoryBean<MongoCli
|
||||
|
||||
private CodecRegistry codecRegistry = DEFAULT_MONGO_SETTINGS.getCodecRegistry();
|
||||
|
||||
@Nullable private Object streamFactoryFactory = MongoCompatibilityAdapter
|
||||
.clientSettingsAdapter(DEFAULT_MONGO_SETTINGS).getStreamFactoryFactory();
|
||||
@Nullable private TransportSettings transportSettings;
|
||||
|
||||
private ReadPreference readPreference = DEFAULT_MONGO_SETTINGS.getReadPreference();
|
||||
@@ -371,16 +367,6 @@ public class MongoClientSettingsFactoryBean extends AbstractFactoryBean<MongoCli
|
||||
this.readPreference = readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param streamFactoryFactory
|
||||
* @deprecated since 4.3, will be removed in the MongoDB 5.0 driver in favor of
|
||||
* {@code com.mongodb.connection.TransportSettings}.
|
||||
*/
|
||||
@Deprecated(since = "4.3")
|
||||
public void setStreamFactoryFactory(Object streamFactoryFactory) {
|
||||
this.streamFactoryFactory = streamFactoryFactory;
|
||||
}
|
||||
|
||||
public void setTransportSettings(@Nullable TransportSettings transportSettings) {
|
||||
this.transportSettings = transportSettings;
|
||||
}
|
||||
@@ -492,10 +478,6 @@ public class MongoClientSettingsFactoryBean extends AbstractFactoryBean<MongoCli
|
||||
builder.transportSettings(transportSettings);
|
||||
}
|
||||
|
||||
if (streamFactoryFactory != null) {
|
||||
MongoCompatibilityAdapter.clientSettingsBuilderAdapter(builder).setStreamFactoryFactory(streamFactoryFactory);
|
||||
}
|
||||
|
||||
if (retryReads != null) {
|
||||
builder = builder.retryReads(retryReads);
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
|
||||
import org.springframework.data.mongodb.core.timeseries.Granularity;
|
||||
import org.springframework.data.mongodb.core.validation.Validator;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
import org.springframework.data.projection.EntityProjection;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.data.util.Optionals;
|
||||
@@ -728,7 +727,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
|
||||
return execute(db -> {
|
||||
|
||||
for (String name : MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db).listCollectionNames()) {
|
||||
for (String name : db.listCollectionNames()) {
|
||||
if (name.equals(collectionName)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1980,11 +1979,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
mapReduce = mapReduce.jsMode(mapReduceOptions.getJavaScriptMode());
|
||||
}
|
||||
|
||||
if (mapReduceOptions.getOutputSharded().isPresent()) {
|
||||
MongoCompatibilityAdapter.mapReduceIterableAdapter(mapReduce)
|
||||
.sharded(mapReduceOptions.getOutputSharded().get());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(mapReduceOptions.getOutputCollection()) && !mapReduceOptions.usesInlineOutput()) {
|
||||
|
||||
mapReduce = mapReduce.collectionName(mapReduceOptions.getOutputCollection())
|
||||
@@ -2367,7 +2361,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
public Set<String> getCollectionNames() {
|
||||
return execute(db -> {
|
||||
Set<String> result = new LinkedHashSet<>();
|
||||
for (String name : MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db).listCollectionNames()) {
|
||||
for (String name : db.listCollectionNames()) {
|
||||
result.add(name);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -118,7 +118,6 @@ import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
import org.springframework.data.projection.EntityProjection;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -739,7 +738,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> collectionExists(String collectionName) {
|
||||
return createMono(db -> Flux.from(MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(db).listCollectionNames()) //
|
||||
return createMono(db -> Flux.from(db.listCollectionNames()) //
|
||||
.filter(s -> s.equals(collectionName)) //
|
||||
.map(s -> true) //
|
||||
.single(false));
|
||||
@@ -787,7 +786,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
@Override
|
||||
public Flux<String> getCollectionNames() {
|
||||
return createFlux(db -> MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(db).listCollectionNames());
|
||||
return createFlux(db -> db.listCollectionNames());
|
||||
}
|
||||
|
||||
public Mono<MongoDatabase> getMongoDatabase() {
|
||||
@@ -2176,10 +2175,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
publisher = publisher.jsMode(options.getJavaScriptMode());
|
||||
}
|
||||
|
||||
if (options.getOutputSharded().isPresent()) {
|
||||
MongoCompatibilityAdapter.mapReducePublisherAdapter(publisher).sharded(options.getOutputSharded().get());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(options.getOutputCollection()) && !options.usesInlineOutput()) {
|
||||
publisher = publisher.collectionName(options.getOutputCollection()).action(options.getMapReduceAction());
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.encryption;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoCompatibilityAdapter.rangeOptionsAdapter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -124,7 +122,7 @@ public class MongoClientEncryption implements Encryption<BsonValue, BsonBinary>
|
||||
Assert.isInstanceOf(Integer.class, trimFactor, () -> String
|
||||
.format("Expected to find a %s but it turned out to be %s.", Integer.class, trimFactor.getClass()));
|
||||
|
||||
rangeOptionsAdapter(encryptionRangeOptions).trimFactor((Integer) trimFactor);
|
||||
encryptionRangeOptions.trimFactor((Integer) trimFactor);
|
||||
}
|
||||
|
||||
if (attributes.containsKey("sparsity")) {
|
||||
|
||||
@@ -114,16 +114,6 @@ public @interface GeoSpatialIndexed {
|
||||
*/
|
||||
GeoSpatialIndexType type() default GeoSpatialIndexType.GEO_2D;
|
||||
|
||||
/**
|
||||
* The bucket size for {@link GeoSpatialIndexType#GEO_HAYSTACK} indexes, in coordinate units.
|
||||
*
|
||||
* @since 1.4
|
||||
* @return {@literal 1.0} by default.
|
||||
* @deprecated since MongoDB server version 4.4
|
||||
*/
|
||||
@Deprecated
|
||||
double bucketSize() default 1.0;
|
||||
|
||||
/**
|
||||
* The name of the additional field to use for {@link GeoSpatialIndexType#GEO_HAYSTACK} indexes
|
||||
*
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Optional;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.query.Collation;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -41,7 +40,6 @@ public class GeospatialIndex implements IndexDefinition {
|
||||
private @Nullable Integer max;
|
||||
private @Nullable Integer bits;
|
||||
private GeoSpatialIndexType type = GeoSpatialIndexType.GEO_2D;
|
||||
private Double bucketSize = MongoClientVersion.isVersion5orNewer() ? null : 1.0;
|
||||
private @Nullable String additionalField;
|
||||
private Optional<IndexFilter> filter = Optional.empty();
|
||||
private Optional<Collation> collation = Optional.empty();
|
||||
@@ -107,17 +105,6 @@ public class GeospatialIndex implements IndexDefinition {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bucketSize
|
||||
* @return this.
|
||||
* @deprecated since MongoDB server version 4.4
|
||||
*/
|
||||
@Deprecated
|
||||
public GeospatialIndex withBucketSize(double bucketSize) {
|
||||
this.bucketSize = bucketSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldName
|
||||
* @return this.
|
||||
@@ -203,14 +190,9 @@ public class GeospatialIndex implements IndexDefinition {
|
||||
break;
|
||||
|
||||
case GEO_2DSPHERE:
|
||||
|
||||
break;
|
||||
|
||||
case GEO_HAYSTACK:
|
||||
|
||||
if (bucketSize != null) {
|
||||
document.put("bucketSize", bucketSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
@@ -55,7 +54,6 @@ import org.springframework.data.mongodb.core.query.Collation;
|
||||
import org.springframework.data.mongodb.util.BsonUtils;
|
||||
import org.springframework.data.mongodb.util.DotPath;
|
||||
import org.springframework.data.mongodb.util.DurationUtil;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.data.mongodb.util.spel.ExpressionUtils;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -711,23 +709,6 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
.named(pathAwareIndexName(index.name(), dotPath, persistentProperty.getOwner(), persistentProperty));
|
||||
}
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer()) {
|
||||
|
||||
Optional<Double> defaultBucketSize = MergedAnnotation.of(GeoSpatialIndexed.class).getDefaultValue("bucketSize",
|
||||
Double.class);
|
||||
if (!defaultBucketSize.isPresent() || index.bucketSize() != defaultBucketSize.get()) {
|
||||
indexDefinition.withBucketSize(index.bucketSize());
|
||||
} else {
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info(
|
||||
"GeoSpatialIndexed.bucketSize no longer supported by Mongo Client 5 or newer. Ignoring bucketSize for path %s."
|
||||
.formatted(dotPath));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
indexDefinition.withBucketSize(index.bucketSize());
|
||||
}
|
||||
|
||||
indexDefinition.typed(index.type()).withAdditionalField(index.additionalField());
|
||||
|
||||
return new IndexDefinitionHolder(dotPath, indexDefinition, collection);
|
||||
|
||||
@@ -45,7 +45,6 @@ public class MapReduceOptions {
|
||||
private Boolean verbose = Boolean.TRUE;
|
||||
private @Nullable Integer limit;
|
||||
|
||||
private Optional<Boolean> outputSharded = Optional.empty();
|
||||
private Optional<String> finalizeFunction = Optional.empty();
|
||||
private Optional<Collation> collation = Optional.empty();
|
||||
|
||||
@@ -152,19 +151,6 @@ public class MapReduceOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true and combined with an output mode that writes to a collection, the output collection will be sharded using
|
||||
* the _id field. For MongoDB 1.9+
|
||||
*
|
||||
* @param outputShared if true, output will be sharded based on _id key.
|
||||
* @return MapReduceOptions so that methods can be chained in a fluent API style
|
||||
*/
|
||||
public MapReduceOptions outputSharded(boolean outputShared) {
|
||||
|
||||
this.outputSharded = Optional.of(outputShared);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the finalize function
|
||||
*
|
||||
@@ -245,10 +231,6 @@ public class MapReduceOptions {
|
||||
return this.outputDatabase;
|
||||
}
|
||||
|
||||
public Optional<Boolean> getOutputSharded() {
|
||||
return this.outputSharded;
|
||||
}
|
||||
|
||||
public Map<String, Object> getScopeVariables() {
|
||||
return this.scopeVariables;
|
||||
}
|
||||
@@ -336,7 +318,6 @@ public class MapReduceOptions {
|
||||
}
|
||||
|
||||
outputDatabase.ifPresent(val -> out.append("db", val));
|
||||
outputSharded.ifPresent(val -> out.append("sharded", val));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,7 @@ package org.springframework.data.mongodb.observability;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.springframework.data.mongodb.observability.MongoObservation.LowCardinalityCommandKeyNames;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
@@ -78,16 +75,6 @@ class DefaultMongoHandlerObservationConvention implements MongoHandlerObservatio
|
||||
keyValues = keyValues.and(LowCardinalityCommandKeyNames.NET_TRANSPORT.withValue("IP.TCP"),
|
||||
LowCardinalityCommandKeyNames.NET_PEER_NAME.withValue(serverAddress.getHost()),
|
||||
LowCardinalityCommandKeyNames.NET_PEER_PORT.withValue("" + serverAddress.getPort()));
|
||||
|
||||
InetSocketAddress socketAddress = MongoCompatibilityAdapter.serverAddressAdapter(serverAddress)
|
||||
.getSocketAddress();
|
||||
|
||||
if (socketAddress != null) {
|
||||
|
||||
keyValues = keyValues.and(
|
||||
LowCardinalityCommandKeyNames.NET_SOCK_PEER_ADDR.withValue(socketAddress.getHostName()),
|
||||
LowCardinalityCommandKeyNames.NET_SOCK_PEER_PORT.withValue("" + socketAddress.getPort()));
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionId connectionId = connectionDescription.getConnectionId();
|
||||
|
||||
@@ -1,417 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.MongoClientSettings.Builder;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.client.ClientSession;
|
||||
import com.mongodb.client.MapReduceIterable;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.MongoIterable;
|
||||
import com.mongodb.client.model.IndexOptions;
|
||||
import com.mongodb.client.model.vault.RangeOptions;
|
||||
import com.mongodb.reactivestreams.client.MapReducePublisher;
|
||||
|
||||
/**
|
||||
* Compatibility adapter to bridge functionality across different MongoDB driver versions.
|
||||
* <p>
|
||||
* This class is for internal use within the framework and should not be used by applications.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Ross Lawley
|
||||
* @since 4.3
|
||||
*/
|
||||
public class MongoCompatibilityAdapter {
|
||||
|
||||
private static final String NO_LONGER_SUPPORTED = "%s is no longer supported on Mongo Client 5 or newer";
|
||||
private static final String NOT_SUPPORTED_ON_4 = "%s is not supported on Mongo Client 4";
|
||||
|
||||
private static final @Nullable Method getStreamFactoryFactory = ReflectionUtils.findMethod(MongoClientSettings.class,
|
||||
"getStreamFactoryFactory");
|
||||
|
||||
private static final @Nullable Method setBucketSize = ReflectionUtils.findMethod(IndexOptions.class, "bucketSize",
|
||||
Double.class);
|
||||
|
||||
private static final @Nullable Method setTrimFactor;
|
||||
|
||||
static {
|
||||
|
||||
// method name changed in between
|
||||
Method trimFactor = ReflectionUtils.findMethod(RangeOptions.class, "setTrimFactor", Integer.class);
|
||||
if (trimFactor != null) {
|
||||
setTrimFactor = trimFactor;
|
||||
} else {
|
||||
setTrimFactor = ReflectionUtils.findMethod(RangeOptions.class, "trimFactor", Integer.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@link MongoClientSettings.Builder}.
|
||||
*
|
||||
* @param builder
|
||||
* @return
|
||||
*/
|
||||
public static ClientSettingsBuilderAdapter clientSettingsBuilderAdapter(MongoClientSettings.Builder builder) {
|
||||
return new MongoStreamFactoryFactorySettingsConfigurer(builder)::setStreamFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@link MongoClientSettings}.
|
||||
*
|
||||
* @param clientSettings
|
||||
* @return
|
||||
*/
|
||||
public static ClientSettingsAdapter clientSettingsAdapter(MongoClientSettings clientSettings) {
|
||||
return new ClientSettingsAdapter() {
|
||||
@Override
|
||||
public <T> T getStreamFactoryFactory() {
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer() || getStreamFactoryFactory == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (T) ReflectionUtils.invokeMethod(getStreamFactoryFactory, clientSettings);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@link IndexOptions}.
|
||||
*
|
||||
* @param options
|
||||
* @return
|
||||
*/
|
||||
public static IndexOptionsAdapter indexOptionsAdapter(IndexOptions options) {
|
||||
return bucketSize -> {
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer() || setBucketSize == null) {
|
||||
throw new UnsupportedOperationException(NO_LONGER_SUPPORTED.formatted("IndexOptions.bucketSize"));
|
||||
}
|
||||
|
||||
ReflectionUtils.invokeMethod(setBucketSize, options, bucketSize);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@code MapReduceIterable}.
|
||||
*
|
||||
* @param iterable
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static MapReduceIterableAdapter mapReduceIterableAdapter(Object iterable) {
|
||||
return sharded -> {
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer()) {
|
||||
throw new UnsupportedOperationException(NO_LONGER_SUPPORTED.formatted("sharded"));
|
||||
}
|
||||
|
||||
// Use MapReduceIterable to avoid package-protected access violations to
|
||||
// com.mongodb.client.internal.MapReduceIterableImpl
|
||||
Method shardedMethod = ReflectionUtils.findMethod(MapReduceIterable.class, "sharded", boolean.class);
|
||||
ReflectionUtils.invokeMethod(shardedMethod, iterable, sharded);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@link RangeOptions}.
|
||||
*
|
||||
* @param options
|
||||
* @return
|
||||
*/
|
||||
public static RangeOptionsAdapter rangeOptionsAdapter(RangeOptions options) {
|
||||
return trimFactor -> {
|
||||
|
||||
if (!MongoClientVersion.isVersion5orNewer() || setTrimFactor == null) {
|
||||
throw new UnsupportedOperationException(NOT_SUPPORTED_ON_4.formatted("RangeOptions.trimFactor"));
|
||||
}
|
||||
|
||||
ReflectionUtils.invokeMethod(setTrimFactor, options, trimFactor);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@code MapReducePublisher}.
|
||||
*
|
||||
* @param publisher
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static MapReducePublisherAdapter mapReducePublisherAdapter(Object publisher) {
|
||||
return sharded -> {
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer()) {
|
||||
throw new UnsupportedOperationException(NO_LONGER_SUPPORTED.formatted("sharded"));
|
||||
}
|
||||
|
||||
// Use MapReducePublisher to avoid package-protected access violations to MapReducePublisherImpl
|
||||
Method shardedMethod = ReflectionUtils.findMethod(MapReducePublisher.class, "sharded", boolean.class);
|
||||
ReflectionUtils.invokeMethod(shardedMethod, publisher, sharded);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a compatibility adapter for {@link ServerAddress}.
|
||||
*
|
||||
* @param serverAddress
|
||||
* @return
|
||||
*/
|
||||
public static ServerAddressAdapter serverAddressAdapter(ServerAddress serverAddress) {
|
||||
return () -> {
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method serverAddressMethod = ReflectionUtils.findMethod(ServerAddress.class, "getSocketAddress");
|
||||
Object value = ReflectionUtils.invokeMethod(serverAddressMethod, serverAddress);
|
||||
return value != null ? InetSocketAddress.class.cast(value) : null;
|
||||
};
|
||||
}
|
||||
|
||||
public static MongoDatabaseAdapterBuilder mongoDatabaseAdapter() {
|
||||
return MongoDatabaseAdapter::new;
|
||||
}
|
||||
|
||||
public static ReactiveMongoDatabaseAdapterBuilder reactiveMongoDatabaseAdapter() {
|
||||
return ReactiveMongoDatabaseAdapter::new;
|
||||
}
|
||||
|
||||
public interface IndexOptionsAdapter {
|
||||
void setBucketSize(double bucketSize);
|
||||
}
|
||||
|
||||
public interface ClientSettingsAdapter {
|
||||
@Nullable
|
||||
<T> T getStreamFactoryFactory();
|
||||
}
|
||||
|
||||
public interface ClientSettingsBuilderAdapter {
|
||||
<T> void setStreamFactoryFactory(T streamFactory);
|
||||
}
|
||||
|
||||
public interface MapReduceIterableAdapter {
|
||||
void sharded(boolean sharded);
|
||||
}
|
||||
|
||||
public interface MapReducePublisherAdapter {
|
||||
void sharded(boolean sharded);
|
||||
}
|
||||
|
||||
public interface ServerAddressAdapter {
|
||||
@Nullable
|
||||
InetSocketAddress getSocketAddress();
|
||||
}
|
||||
|
||||
public interface MongoDatabaseAdapterBuilder {
|
||||
MongoDatabaseAdapter forDb(com.mongodb.client.MongoDatabase db);
|
||||
}
|
||||
|
||||
public interface RangeOptionsAdapter {
|
||||
void trimFactor(Integer trimFactor);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "DataFlowIssue" })
|
||||
public static class MongoDatabaseAdapter {
|
||||
|
||||
@Nullable //
|
||||
private static final Method LIST_COLLECTION_NAMES_METHOD;
|
||||
|
||||
@Nullable //
|
||||
private static final Method LIST_COLLECTION_NAMES_METHOD_SESSION;
|
||||
|
||||
private static final Class<?> collectionNamesReturnType;
|
||||
|
||||
private final MongoDatabase db;
|
||||
|
||||
static {
|
||||
|
||||
if (MongoClientVersion.isSyncClientPresent()) {
|
||||
|
||||
LIST_COLLECTION_NAMES_METHOD = ReflectionUtils.findMethod(MongoDatabase.class, "listCollectionNames");
|
||||
LIST_COLLECTION_NAMES_METHOD_SESSION = ReflectionUtils.findMethod(MongoDatabase.class, "listCollectionNames",
|
||||
ClientSession.class);
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer()) {
|
||||
try {
|
||||
collectionNamesReturnType = ClassUtils.forName("com.mongodb.client.ListCollectionNamesIterable",
|
||||
MongoDatabaseAdapter.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Unable to load com.mongodb.client.ListCollectionNamesIterable", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
collectionNamesReturnType = ClassUtils.forName("com.mongodb.client.MongoIterable",
|
||||
MongoDatabaseAdapter.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Unable to load com.mongodb.client.ListCollectionNamesIterable", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LIST_COLLECTION_NAMES_METHOD = null;
|
||||
LIST_COLLECTION_NAMES_METHOD_SESSION = null;
|
||||
collectionNamesReturnType = Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
public MongoDatabaseAdapter(MongoDatabase db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public Class<? extends MongoIterable<String>> collectionNameIterableType() {
|
||||
return (Class<? extends MongoIterable<String>>) collectionNamesReturnType;
|
||||
}
|
||||
|
||||
public MongoIterable<String> listCollectionNames() {
|
||||
|
||||
Assert.state(LIST_COLLECTION_NAMES_METHOD != null, "No method listCollectionNames present for %s".formatted(db));
|
||||
return (MongoIterable<String>) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD, db);
|
||||
}
|
||||
|
||||
public MongoIterable<String> listCollectionNames(ClientSession clientSession) {
|
||||
Assert.state(LIST_COLLECTION_NAMES_METHOD != null,
|
||||
"No method listCollectionNames(ClientSession) present for %s".formatted(db));
|
||||
return (MongoIterable<String>) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD_SESSION, db,
|
||||
clientSession);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ReactiveMongoDatabaseAdapterBuilder {
|
||||
ReactiveMongoDatabaseAdapter forDb(com.mongodb.reactivestreams.client.MongoDatabase db);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "DataFlowIssue" })
|
||||
public static class ReactiveMongoDatabaseAdapter {
|
||||
|
||||
@Nullable //
|
||||
private static final Method LIST_COLLECTION_NAMES_METHOD;
|
||||
|
||||
@Nullable //
|
||||
private static final Method LIST_COLLECTION_NAMES_METHOD_SESSION;
|
||||
|
||||
private static final Class<?> collectionNamesReturnType;
|
||||
|
||||
private final com.mongodb.reactivestreams.client.MongoDatabase db;
|
||||
|
||||
static {
|
||||
|
||||
if (MongoClientVersion.isReactiveClientPresent()) {
|
||||
|
||||
LIST_COLLECTION_NAMES_METHOD = ReflectionUtils
|
||||
.findMethod(com.mongodb.reactivestreams.client.MongoDatabase.class, "listCollectionNames");
|
||||
LIST_COLLECTION_NAMES_METHOD_SESSION = ReflectionUtils.findMethod(
|
||||
com.mongodb.reactivestreams.client.MongoDatabase.class, "listCollectionNames",
|
||||
com.mongodb.reactivestreams.client.ClientSession.class);
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer()) {
|
||||
try {
|
||||
collectionNamesReturnType = ClassUtils.forName(
|
||||
"com.mongodb.reactivestreams.client.ListCollectionNamesPublisher",
|
||||
ReactiveMongoDatabaseAdapter.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("com.mongodb.reactivestreams.client.ListCollectionNamesPublisher", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
collectionNamesReturnType = ClassUtils.forName("org.reactivestreams.Publisher",
|
||||
ReactiveMongoDatabaseAdapter.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("org.reactivestreams.Publisher", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LIST_COLLECTION_NAMES_METHOD = null;
|
||||
LIST_COLLECTION_NAMES_METHOD_SESSION = null;
|
||||
collectionNamesReturnType = Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
ReactiveMongoDatabaseAdapter(com.mongodb.reactivestreams.client.MongoDatabase db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public Class<? extends Publisher<String>> collectionNamePublisherType() {
|
||||
return (Class<? extends Publisher<String>>) collectionNamesReturnType;
|
||||
|
||||
}
|
||||
|
||||
public Publisher<String> listCollectionNames() {
|
||||
Assert.state(LIST_COLLECTION_NAMES_METHOD != null, "No method listCollectionNames present for %s".formatted(db));
|
||||
return (Publisher<String>) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD, db);
|
||||
}
|
||||
|
||||
public Publisher<String> listCollectionNames(com.mongodb.reactivestreams.client.ClientSession clientSession) {
|
||||
Assert.state(LIST_COLLECTION_NAMES_METHOD != null,
|
||||
"No method listCollectionNames(ClientSession) present for %s".formatted(db));
|
||||
return (Publisher<String>) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD_SESSION, db, clientSession);
|
||||
}
|
||||
}
|
||||
|
||||
static class MongoStreamFactoryFactorySettingsConfigurer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(MongoStreamFactoryFactorySettingsConfigurer.class);
|
||||
|
||||
private static final String STREAM_FACTORY_NAME = "com.mongodb.connection.StreamFactoryFactory";
|
||||
private static final boolean STREAM_FACTORY_PRESENT = ClassUtils.isPresent(STREAM_FACTORY_NAME,
|
||||
MongoCompatibilityAdapter.class.getClassLoader());
|
||||
private final MongoClientSettings.Builder settingsBuilder;
|
||||
|
||||
static boolean isStreamFactoryPresent() {
|
||||
return STREAM_FACTORY_PRESENT;
|
||||
}
|
||||
|
||||
public MongoStreamFactoryFactorySettingsConfigurer(Builder settingsBuilder) {
|
||||
this.settingsBuilder = settingsBuilder;
|
||||
}
|
||||
|
||||
void setStreamFactory(Object streamFactory) {
|
||||
|
||||
if (MongoClientVersion.isVersion5orNewer() && isStreamFactoryPresent()) {
|
||||
logger.warn("StreamFactoryFactory is no longer available. Use TransportSettings instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> streamFactoryType = ClassUtils.forName(STREAM_FACTORY_NAME, streamFactory.getClass().getClassLoader());
|
||||
|
||||
if (!ClassUtils.isAssignable(streamFactoryType, streamFactory.getClass())) {
|
||||
throw new IllegalArgumentException("Expected %s but found %s".formatted(streamFactoryType, streamFactory));
|
||||
}
|
||||
|
||||
Method setter = ReflectionUtils.findMethod(settingsBuilder.getClass(), "streamFactoryFactory",
|
||||
streamFactoryType);
|
||||
if (setter != null) {
|
||||
ReflectionUtils.invokeMethod(setter, settingsBuilder, streamFactoryType.cast(streamFactory));
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalArgumentException("Cannot set StreamFactoryFactory for %s".formatted(settingsBuilder), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import com.mongodb.reactivestreams.client.ListCollectionNamesPublisher;
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.BsonValueCodec;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
@@ -58,7 +59,6 @@ import com.mongodb.reactivestreams.client.MapReducePublisher;
|
||||
import com.mongodb.reactivestreams.client.MongoClient;
|
||||
import com.mongodb.reactivestreams.client.MongoCollection;
|
||||
import com.mongodb.reactivestreams.client.MongoDatabase;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ReactiveSessionBoundMongoTemplate}.
|
||||
@@ -94,7 +94,7 @@ public class ReactiveSessionBoundMongoTemplateUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
mock(MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(database).collectionNamePublisherType());
|
||||
mock(ListCollectionNamesPublisher.class);
|
||||
when(client.getDatabase(anyString())).thenReturn(database);
|
||||
when(codecRegistry.get(any(Class.class))).thenReturn(new BsonValueCodec());
|
||||
when(database.getCodecRegistry()).thenReturn(codecRegistry);
|
||||
|
||||
@@ -49,7 +49,6 @@ import com.mongodb.client.model.CountOptions;
|
||||
import com.mongodb.client.model.DeleteOptions;
|
||||
import com.mongodb.client.model.FindOneAndUpdateOptions;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
|
||||
/**
|
||||
* Unit test for {@link SessionBoundMongoTemplate} making sure a proxied {@link MongoCollection} and
|
||||
@@ -90,7 +89,7 @@ public class SessionBoundMongoTemplateUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
collectionNamesIterable = mock(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(database).collectionNameIterableType());
|
||||
collectionNamesIterable = mock(ListCollectionNamesIterable.class);
|
||||
when(client.getDatabase(anyString())).thenReturn(database);
|
||||
when(codecRegistry.get(any(Class.class))).thenReturn(new BsonValueCodec());
|
||||
when(database.getCodecRegistry()).thenReturn(codecRegistry);
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
@@ -506,7 +505,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
assertThat(indexDefinition.getIndexKeys()).containsEntry("location", "geoHaystack").containsEntry("What light?",
|
||||
1);
|
||||
assertThat(indexDefinition.getIndexOptions()).containsEntry("name", "my_geo_index_name")
|
||||
.containsEntry("bucketSize", 2.0);
|
||||
.doesNotContainKey("bucketSize");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2112
|
||||
@@ -558,9 +557,6 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
@AliasFor(annotation = GeoSpatialIndexed.class, attribute = "additionalField")
|
||||
String theAdditionalFieldINeedToDefine() default "What light?";
|
||||
|
||||
@AliasFor(annotation = GeoSpatialIndexed.class, attribute = "bucketSize")
|
||||
double size() default 2;
|
||||
|
||||
@AliasFor(annotation = GeoSpatialIndexed.class, attribute = "type")
|
||||
GeoSpatialIndexType indexType() default GeoSpatialIndexType.GEO_HAYSTACK;
|
||||
}
|
||||
|
||||
@@ -80,9 +80,9 @@ public class IndexUnitTests {
|
||||
public void testGeospatialIndexGeoHaystack() {
|
||||
|
||||
GeospatialIndex i = new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_HAYSTACK)
|
||||
.withAdditionalField("name").withBucketSize(40);
|
||||
.withAdditionalField("name");
|
||||
assertThat(i.getIndexKeys()).isEqualTo(Document.parse("{ \"location\" : \"geoHaystack\" , \"name\" : 1}"));
|
||||
assertThat(i.getIndexOptions()).isEqualTo(Document.parse("{ \"bucketSize\" : 40.0}"));
|
||||
assertThat(i.getIndexOptions()).isEqualTo(Document.parse("{ }"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -32,8 +32,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.springframework.data.mongodb.test.util.CleanMongoDB.Struct;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
|
||||
import com.mongodb.client.ListCollectionNamesIterable;
|
||||
import com.mongodb.client.ListDatabasesIterable;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
@@ -74,11 +74,11 @@ class CleanMongoDBTests {
|
||||
when(mongoClientMock.getDatabase(eq("db2"))).thenReturn(db2mock);
|
||||
|
||||
// collections have to exist
|
||||
MongoIterable<String> collectionIterable = mock(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db1mock).collectionNameIterableType());
|
||||
MongoIterable<String> collectionIterable = mock(ListCollectionNamesIterable.class);
|
||||
when(collectionIterable.into(any(Collection.class))).thenReturn(Arrays.asList("db1collection1", "db1collection2"));
|
||||
doReturn(collectionIterable).when(db1mock).listCollectionNames();
|
||||
|
||||
MongoIterable<String> collectionIterable2 = mock(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db2mock).collectionNameIterableType());
|
||||
MongoIterable<String> collectionIterable2 = mock(ListCollectionNamesIterable.class);
|
||||
when(collectionIterable2.into(any(Collection.class))).thenReturn(Collections.singletonList("db2collection1"));
|
||||
doReturn(collectionIterable2).when(db2mock).listCollectionNames();
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.mapping.callback.EntityCallbacks;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.util.MongoCompatibilityAdapter;
|
||||
import org.testcontainers.shaded.org.awaitility.Awaitility;
|
||||
|
||||
import com.mongodb.MongoWriteException;
|
||||
@@ -96,7 +95,7 @@ public class MongoTestTemplate extends MongoTemplate {
|
||||
}
|
||||
|
||||
public void flushDatabase() {
|
||||
flush(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(getDb()).listCollectionNames());
|
||||
flush(getDb().listCollectionNames());
|
||||
}
|
||||
|
||||
public void flush(Iterable<String> collections) {
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.mongodb.test.util.ExcludeReactiveClientFromClassPath;
|
||||
import org.springframework.data.mongodb.test.util.ExcludeSyncClientFromClassPath;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class MongoCompatibilityAdapterUnitTests {
|
||||
|
||||
@Test // GH-4578
|
||||
@ExcludeReactiveClientFromClassPath
|
||||
void returnsListCollectionNameIterableTypeCorrectly() {
|
||||
|
||||
String expectedType = MongoClientVersion.isVersion5orNewer() ? "ListCollectionNamesIterable" : "MongoIterable";
|
||||
assertThat(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(null).collectionNameIterableType())
|
||||
.satisfies(type -> assertThat(ClassUtils.getShortName(type)).isEqualTo(expectedType));
|
||||
|
||||
}
|
||||
|
||||
@Test // GH-4578
|
||||
@ExcludeSyncClientFromClassPath
|
||||
void returnsListCollectionNamePublisherTypeCorrectly() {
|
||||
|
||||
String expectedType = MongoClientVersion.isVersion5orNewer() ? "ListCollectionNamesPublisher" : "Publisher";
|
||||
assertThat(MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(null).collectionNamePublisherType())
|
||||
.satisfies(type -> assertThat(ClassUtils.getShortName(type)).isEqualTo(expectedType));
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user