DATAMONGO-1919 - Allow reactive-only usage of ReactiveMongoTemplate.

We now support reactive-only usage of Spring Data MongoDB without the need to use the synchronous driver or even having it on the class path. We conditionally register CodeWScope/CodeWithScope types that are bundled with the particular driver distributions.

NoOpDbRefResolver is now a top-level type to be used with a reactive-only MongoMappingContext.

Original Pull Request: #572
This commit is contained in:
Mark Paluch
2018-06-14 14:54:32 +02:00
committed by Christoph Strobl
parent 78c2ab290d
commit 2d36fc3050
8 changed files with 111 additions and 81 deletions

View File

@@ -22,6 +22,7 @@ import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import com.mongodb.reactivestreams.client.MongoClient;
@@ -80,7 +81,7 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
@Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter converter = new MappingMongoConverter(ReactiveMongoTemplate.NO_OP_REF_RESOLVER,
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE,
mongoMappingContext());
converter.setCustomConversions(customConversions());

View File

@@ -32,8 +32,6 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import org.bson.BsonTimestamp;
import org.bson.BsonValue;
import org.bson.Document;
@@ -77,7 +75,16 @@ import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.PrefixingDelegatingAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.JsonSchemaMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MongoJsonSchemaMapper;
import org.springframework.data.mongodb.core.convert.MongoWriter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
import org.springframework.data.mongodb.core.index.ReactiveIndexOperations;
import org.springframework.data.mongodb.core.index.ReactiveMongoPersistentEntityIndexCreator;
@@ -96,7 +103,6 @@ import org.springframework.data.mongodb.core.mapping.event.MongoMappingEvent;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.Meta;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
@@ -119,7 +125,6 @@ import com.mongodb.ClientSessionOptions;
import com.mongodb.CursorType;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBRef;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
@@ -156,7 +161,7 @@ import com.mongodb.util.JSONParseException;
*/
public class ReactiveMongoTemplate implements ReactiveMongoOperations, ApplicationContextAware {
public static final DbRefResolver NO_OP_REF_RESOLVER = new NoOpDbRefResolver();
public static final DbRefResolver NO_OP_REF_RESOLVER = NoOpDbRefResolver.INSTANCE;
private static final Logger LOGGER = LoggerFactory.getLogger(ReactiveMongoTemplate.class);
private static final String ID_FIELD = "_id";
@@ -3287,54 +3292,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return new ArrayList<>(documents);
}
/**
* No-Operation {@link org.springframework.data.mongodb.core.mapping.DBRef} resolver.
*
* @author Mark Paluch
*/
static class NoOpDbRefResolver implements DbRefResolver {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
*/
@Override
@Nullable
public Object resolveDbRef(@Nonnull MongoPersistentProperty property, @Nonnull DBRef dbref,
@Nonnull DbRefResolverCallback callback, @Nonnull DbRefProxyHandler proxyHandler) {
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#created(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.Object)
*/
@Override
@Nullable
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity<?> entity, Object id) {
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)
*/
@Override
public Document fetch(DBRef dbRef) {
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#bulkFetch(java.util.List)
*/
@Override
public List<Document> bulkFetch(List<DBRef> dbRefs) {
return Collections.emptyList();
}
}
/**
* {@link MongoTemplate} extension bound to a specific {@link ClientSession} that is applied when interacting with the
* server through the driver API.

View File

@@ -22,6 +22,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.DBRef;
@@ -59,9 +60,15 @@ public interface DbRefResolver {
* @param id will never be {@literal null}.
* @return
*/
DBRef createDbRef(@Nullable org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity<?> entity,
Object id);
default DBRef createDbRef(@Nullable org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity<?> entity, Object id) {
if (annotation != null && StringUtils.hasText(annotation.db())) {
return new DBRef(annotation.db(), entity.getCollection(), id);
}
return new DBRef(entity.getCollection(), id);
}
/**
* Actually loads the {@link DBRef} from the datasource.

View File

@@ -104,21 +104,6 @@ public class DefaultDbRefResolver implements DbRefResolver {
return callback.resolve(property);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#created(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.Object)
*/
@Override
public DBRef createDbRef(@Nullable org.springframework.data.mongodb.core.mapping.DBRef annotation,
MongoPersistentEntity<?> entity, Object id) {
if (annotation != null && StringUtils.hasText(annotation.db())) {
return new DBRef(annotation.db(), entity.getCollection(), id);
}
return new DBRef(entity.getCollection(), id);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2018 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
*
* http://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.core.convert;
import java.util.List;
import javax.annotation.Nonnull;
import org.bson.Document;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.DBRef;
/**
* No-Operation {@link org.springframework.data.mongodb.core.mapping.DBRef} resolver throwing
* {@link UnsupportedOperationException} when attempting to resolve database references.
*
* @author Mark Paluch
* @since 2.1
*/
public enum NoOpDbRefResolver implements DbRefResolver {
INSTANCE;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
*/
@Override
@Nullable
public Object resolveDbRef(@Nonnull MongoPersistentProperty property, @Nonnull DBRef dbref,
@Nonnull DbRefResolverCallback callback, @Nonnull DbRefProxyHandler proxyHandler) {
throw new UnsupportedOperationException("DBRef resolution not supported!");
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)
*/
@Override
public Document fetch(DBRef dbRef) {
throw new UnsupportedOperationException("DBRef resolution not supported!");
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#bulkFetch(java.util.List)
*/
@Override
public List<Document> bulkFetch(List<DBRef> dbRefs) {
throw new UnsupportedOperationException("DBRef resolution not supported!");
}
}

View File

@@ -24,7 +24,6 @@ import java.util.regex.Pattern;
import org.bson.BsonObjectId;
import org.bson.types.Binary;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.mongodb.util.MongoClientVersion;
@@ -37,6 +36,7 @@ import com.mongodb.DBRef;
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
*/
public abstract class MongoSimpleTypes {
@@ -53,15 +53,21 @@ public abstract class MongoSimpleTypes {
simpleTypes.add(DBRef.class);
simpleTypes.add(ObjectId.class);
simpleTypes.add(BsonObjectId.class);
simpleTypes.add(CodeWScope.class);
simpleTypes.add(org.bson.Document.class);
simpleTypes.add(Pattern.class);
simpleTypes.add(Binary.class);
simpleTypes.add(UUID.class);
if (ClassUtils.isPresent("org.bson.types.CodeWScope", MongoSimpleTypes.class.getClassLoader())) {
simpleTypes.add(resolveClassName("org.bson.types.CodeWScope"));
}
if (ClassUtils.isPresent("org.bson.types.CodeWithScope", MongoSimpleTypes.class.getClassLoader())) {
simpleTypes.add(resolveClassName("org.bson.types.CodeWithScope"));
}
if (MongoClientVersion.isMongo34Driver()) {
simpleTypes
.add(ClassUtils.resolveClassName("org.bson.types.Decimal128", MongoSimpleTypes.class.getClassLoader()));
simpleTypes.add(resolveClassName("org.bson.types.Decimal128"));
}
MONGO_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes);
@@ -71,4 +77,8 @@ public abstract class MongoSimpleTypes {
public static final SimpleTypeHolder HOLDER = new SimpleTypeHolder(MONGO_SIMPLE_TYPES, true);
private MongoSimpleTypes() {}
private static Class<?> resolveClassName(String className) {
return ClassUtils.resolveClassName(className, MongoSimpleTypes.class.getClassLoader());
}
}

View File

@@ -41,8 +41,8 @@ import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplateUnitTests.AutogenerateableId;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.BasicQuery;
@@ -107,7 +107,7 @@ public class ReactiveMongoTemplateUnitTests {
when(aggregatePublisher.first()).thenReturn(findPublisher);
this.mappingContext = new MongoMappingContext();
this.converter = new MappingMongoConverter(new NoOpDbRefResolver(), mappingContext);
this.converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
this.template = new ReactiveMongoTemplate(factory, converter);
}

View File

@@ -39,10 +39,10 @@ import org.reactivestreams.Publisher;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate.ReactiveSessionBoundMongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
@@ -64,6 +64,7 @@ import com.mongodb.reactivestreams.client.MongoDatabase;
* Unit tests for {@link ReactiveSessionBoundMongoTemplate}.
*
* @author Christoph Strobl
* @author Mark Paluch
*/
@SuppressWarnings("unchecked")
@RunWith(MockitoJUnitRunner.Silent.class)
@@ -124,7 +125,7 @@ public class ReactiveSessionBoundMongoTemplateUnitTests {
factory = new SimpleReactiveMongoDatabaseFactory(client, "foo");
this.mappingContext = new MongoMappingContext();
this.converter = new MappingMongoConverter(new NoOpDbRefResolver(), mappingContext);
this.converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
this.template = new ReactiveSessionBoundMongoTemplate(clientSession, new ReactiveMongoTemplate(factory, converter));
}