Compare commits
116 Commits
issue/4429
...
1.9.8.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
678e967318 | ||
|
|
ce6193a541 | ||
|
|
a3c21bf3af | ||
|
|
850e95946a | ||
|
|
c316aceda1 | ||
|
|
3385d96213 | ||
|
|
fa7d783940 | ||
|
|
39ba28cdae | ||
|
|
7a32d40dd0 | ||
|
|
6593fef803 | ||
|
|
5de3cb9ba3 | ||
|
|
cd42b19718 | ||
|
|
eacfd2c172 | ||
|
|
439616c788 | ||
|
|
40c3204fb8 | ||
|
|
6ad5f62d66 | ||
|
|
1585cc420d | ||
|
|
856f156318 | ||
|
|
00d9da3027 | ||
|
|
53eaaa02a0 | ||
|
|
315b642b3b | ||
|
|
958752e72f | ||
|
|
6b1dbe372e | ||
|
|
a644187131 | ||
|
|
681a4f9855 | ||
|
|
f2be1b2ca9 | ||
|
|
3c203eba8e | ||
|
|
f3b0665d94 | ||
|
|
9f43d3fc5a | ||
|
|
95985fffc8 | ||
|
|
6c6ac6da5b | ||
|
|
c1ac8767b7 | ||
|
|
96068eb0e2 | ||
|
|
36d2e0942b | ||
|
|
b585783b75 | ||
|
|
3924b6f12a | ||
|
|
2674880946 | ||
|
|
6c6f953a42 | ||
|
|
772e8ac85e | ||
|
|
2bbffed62b | ||
|
|
685990bdd6 | ||
|
|
ff83ac3fb4 | ||
|
|
6827a09f26 | ||
|
|
a5148f89c1 | ||
|
|
995a680823 | ||
|
|
9f0abb69fd | ||
|
|
d65eebe9c3 | ||
|
|
ca4f1f1b7c | ||
|
|
46b119ce71 | ||
|
|
fc0dd7d094 | ||
|
|
712d8be7bb | ||
|
|
536dcc14ca | ||
|
|
dc44c3a455 | ||
|
|
8e90366712 | ||
|
|
ed36fd7260 | ||
|
|
31a6a74743 | ||
|
|
001ff508b5 | ||
|
|
6882fa9d10 | ||
|
|
91eaae0ef6 | ||
|
|
785dc6ab78 | ||
|
|
f011a9a4ee | ||
|
|
c6c58050e7 | ||
|
|
5fce8bcac6 | ||
|
|
2f522bae5c | ||
|
|
2e6f91924d | ||
|
|
15f7a9c74a | ||
|
|
49f52f0258 | ||
|
|
396ea471fb | ||
|
|
eef17dd000 | ||
|
|
84dc03b9d1 | ||
|
|
0ce220d54f | ||
|
|
b693136396 | ||
|
|
3c117db43b | ||
|
|
075ccb1d00 | ||
|
|
e3bddd1c19 | ||
|
|
22b113ce64 | ||
|
|
0f5e91b091 | ||
|
|
557a528690 | ||
|
|
762569c826 | ||
|
|
ad7d82f521 | ||
|
|
04deaacbec | ||
|
|
ec443f2b5e | ||
|
|
f1b04ff354 | ||
|
|
62dd7d070a | ||
|
|
5df92a86a3 | ||
|
|
2ca3df1ff4 | ||
|
|
a8751249fd | ||
|
|
19abff826e | ||
|
|
5f199cf81f | ||
|
|
eb26b78a19 | ||
|
|
3d0053c61a | ||
|
|
7b15d246e8 | ||
|
|
b75f4a2834 | ||
|
|
d6ac4c6df5 | ||
|
|
02f56c88f5 | ||
|
|
cd35b9ed2a | ||
|
|
e8944a6c3a | ||
|
|
6fcbc225eb | ||
|
|
f06eda488c | ||
|
|
0ef910445d | ||
|
|
b22ee9d27c | ||
|
|
859a0e83c8 | ||
|
|
b35f151b80 | ||
|
|
17afb07e45 | ||
|
|
b407963344 | ||
|
|
8b31ba1836 | ||
|
|
0cf6edae43 | ||
|
|
0824105377 | ||
|
|
dc936a5b7b | ||
|
|
c8fe02e48e | ||
|
|
32547db306 | ||
|
|
41902154ca | ||
|
|
2354ced1bf | ||
|
|
791cc3a1b8 | ||
|
|
021c03fbbf | ||
|
|
e4a59f29d0 |
20
.travis.yml
20
.travis.yml
@@ -3,13 +3,29 @@ language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
services:
|
||||
- mongodb
|
||||
before_script:
|
||||
- mongod --version
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- PROFILE=ci
|
||||
- PROFILE=mongo-next
|
||||
- PROFILE=mongo3
|
||||
- PROFILE=mongo3-next
|
||||
- PROFILE=mongo31
|
||||
- PROFILE=mongo32
|
||||
- PROFILE=mongo33
|
||||
- PROFILE=mongo34-next
|
||||
|
||||
# Current MongoDB version is 2.4.2 as of 2016-04, see https://github.com/travis-ci/travis-ci/issues/3694
|
||||
# apt-get starts a MongoDB instance so it's not started using before_script
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- mongodb-3.2-precise
|
||||
packages:
|
||||
- mongodb-org-server
|
||||
- mongodb-org-shell
|
||||
|
||||
sudo: false
|
||||
|
||||
|
||||
41
pom.xml
41
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.9.0.RELEASE</version>
|
||||
<version>1.9.8.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>1.8.0.RELEASE</version>
|
||||
<version>1.8.8.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -28,8 +28,8 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>1.12.0.RELEASE</springdata.commons>
|
||||
<mongo>2.14.0</mongo>
|
||||
<springdata.commons>1.12.8.RELEASE</springdata.commons>
|
||||
<mongo>2.14.3</mongo>
|
||||
<mongo.osgi>2.13.0</mongo.osgi>
|
||||
</properties>
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
<id>mongo-next</id>
|
||||
<properties>
|
||||
<mongo>2.14.0-SNAPSHOT</mongo>
|
||||
<mongo>2.15.0-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -148,16 +148,41 @@
|
||||
|
||||
<id>mongo31</id>
|
||||
<properties>
|
||||
<mongo>3.1.0</mongo>
|
||||
<mongo>3.1.1</mongo>
|
||||
</properties>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo32-next</id>
|
||||
<id>mongo32</id>
|
||||
<properties>
|
||||
<mongo>3.2.0-SNAPSHOT</mongo>
|
||||
<mongo>3.2.2</mongo>
|
||||
</properties>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo33</id>
|
||||
<properties>
|
||||
<mongo>3.3.0</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mongo-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo34-next</id>
|
||||
<properties>
|
||||
<mongo>3.4.0-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.9.0.RELEASE</version>
|
||||
<version>1.9.8.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>1.9.0.RELEASE</version>
|
||||
<version>1.9.8.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.9.0.RELEASE</version>
|
||||
<version>1.9.8.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.9.0.RELEASE</version>
|
||||
<version>1.9.8.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2016 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.
|
||||
@@ -30,6 +30,7 @@ import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,7 @@ import com.mongodb.WriteConcern;
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @auhtor Christoph Strobl
|
||||
*/
|
||||
public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
|
||||
@@ -58,8 +60,8 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
protected String collectionPattern = "%c";
|
||||
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
|
||||
protected String applicationId = System.getProperty("APPLICATION_ID", null);
|
||||
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE;
|
||||
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL;
|
||||
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.ACKNOWLEDGED;
|
||||
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.UNACKNOWLEDGED;
|
||||
protected Mongo mongo;
|
||||
protected DB db;
|
||||
|
||||
@@ -128,7 +130,7 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
}
|
||||
|
||||
protected void connectToMongo() throws UnknownHostException {
|
||||
this.mongo = new Mongo(host, port);
|
||||
this.mongo = new MongoClient(host, port);
|
||||
this.db = mongo.getDB(database);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2016 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.
|
||||
@@ -22,37 +22,44 @@ import java.util.Calendar;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.MDC;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MongoLog4jAppender}.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoLog4jAppenderIntegrationTests {
|
||||
|
||||
static final String NAME = MongoLog4jAppenderIntegrationTests.class.getName();
|
||||
|
||||
private static final Logger log = Logger.getLogger(NAME);
|
||||
Mongo mongo;
|
||||
MongoClient mongo;
|
||||
DB db;
|
||||
String collection;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
mongo = new Mongo("localhost", 27017);
|
||||
mongo = new MongoClient("localhost", 27017);
|
||||
db = mongo.getDB("logs");
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
collection = String.valueOf(now.get(Calendar.YEAR)) + String.format("%1$02d", now.get(Calendar.MONTH) + 1);
|
||||
db.getCollection(collection).drop();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
db.getCollection(collection).remove(new BasicDBObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -64,7 +71,6 @@ public class MongoLog4jAppenderIntegrationTests {
|
||||
log.error("ERROR message");
|
||||
|
||||
DBCursor msgs = db.getCollection(collection).find();
|
||||
|
||||
assertThat(msgs.count(), is(4));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.9.0.RELEASE</version>
|
||||
<version>1.9.8.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -361,7 +361,9 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
* @param filters
|
||||
*/
|
||||
public NegatingFilter(TypeFilter... filters) {
|
||||
Assert.notNull(filters);
|
||||
|
||||
Assert.notNull(filters, "TypeFilters must not be null");
|
||||
|
||||
this.delegates = new HashSet<TypeFilter>(Arrays.asList(filters));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 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.
|
||||
@@ -15,24 +15,24 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.*;
|
||||
import static org.springframework.data.mongodb.config.BeanNames.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
|
||||
import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,6 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
||||
|
||||
defaultDependenciesIfNecessary(registry, annotationMetadata);
|
||||
super.registerBeanDefinitions(annotationMetadata, registry);
|
||||
}
|
||||
|
||||
@@ -85,7 +84,11 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
|
||||
builder.addConstructorArgReference(MAPPING_CONTEXT_BEAN_NAME);
|
||||
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(MongoMappingContextLookup.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
|
||||
builder.addConstructorArgValue(definition.getBeanDefinition());
|
||||
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
||||
}
|
||||
|
||||
@@ -102,29 +105,58 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
|
||||
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(AuditingEventListener.class);
|
||||
listenerBeanDefinitionBuilder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(
|
||||
getAuditingHandlerBeanName(), registry));
|
||||
listenerBeanDefinitionBuilder
|
||||
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
||||
|
||||
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
|
||||
AuditingEventListener.class.getName(), registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register default bean definitions for a {@link MongoMappingContext} and an {@link IsNewStrategyFactory} in case we
|
||||
* don't find beans with the assumed names in the registry.
|
||||
*
|
||||
* @param registry the {@link BeanDefinitionRegistry} to use to register the components into.
|
||||
* @param source the source which the registered components shall be registered with
|
||||
* Simple helper to be able to wire the {@link MappingContext} from a {@link MappingMongoConverter} bean available in
|
||||
* the application context.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private void defaultDependenciesIfNecessary(BeanDefinitionRegistry registry, Object source) {
|
||||
static class MongoMappingContextLookup
|
||||
implements FactoryBean<MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
||||
|
||||
if (!registry.containsBeanDefinition(MAPPING_CONTEXT_BEAN_NAME)) {
|
||||
private final MappingMongoConverter converter;
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition(MongoMappingContext.class);
|
||||
definition.setRole(ROLE_INFRASTRUCTURE);
|
||||
definition.setSource(source);
|
||||
/**
|
||||
* Creates a new {@link MongoMappingContextLookup} for the given {@link MappingMongoConverter}.
|
||||
*
|
||||
* @param converter must not be {@literal null}.
|
||||
*/
|
||||
public MongoMappingContextLookup(MappingMongoConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(MAPPING_CONTEXT_BEAN_NAME, definition);
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
@Override
|
||||
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getObject() throws Exception {
|
||||
return converter.getMappingContext();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return MappingContext.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BulkWriteException;
|
||||
import com.mongodb.BulkWriteOperation;
|
||||
import com.mongodb.BulkWriteRequestBuilder;
|
||||
@@ -38,6 +39,7 @@ import com.mongodb.WriteConcern;
|
||||
*
|
||||
* @author Tobias Trelle
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.9
|
||||
*/
|
||||
class DefaultBulkOperations implements BulkOperations {
|
||||
@@ -117,7 +119,15 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
Assert.notNull(document, "Document must not be null!");
|
||||
|
||||
bulk.insert((DBObject) mongoOperations.getConverter().convertToMongoType(document));
|
||||
if (document instanceof DBObject) {
|
||||
|
||||
bulk.insert((DBObject) document);
|
||||
return this;
|
||||
}
|
||||
|
||||
DBObject sink = new BasicDBObject();
|
||||
mongoOperations.getConverter().write(document, sink);
|
||||
bulk.insert(sink);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -15,17 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.domain.Sort.Direction.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||
import org.springframework.data.mongodb.core.index.IndexField;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DBCollection;
|
||||
@@ -42,12 +40,12 @@ import com.mongodb.MongoException;
|
||||
*/
|
||||
public class DefaultIndexOperations implements IndexOperations {
|
||||
|
||||
private static final Double ONE = Double.valueOf(1);
|
||||
private static final Double MINUS_ONE = Double.valueOf(-1);
|
||||
private static final Collection<String> TWO_D_IDENTIFIERS = Arrays.asList("2d", "2dsphere");
|
||||
private static final String PARTIAL_FILTER_EXPRESSION_KEY = "partialFilterExpression";
|
||||
|
||||
private final MongoOperations mongoOperations;
|
||||
private final String collectionName;
|
||||
private final QueryMapper mapper;
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultIndexOperations}.
|
||||
@@ -56,12 +54,26 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
* @param collectionName must not be {@literal null}.
|
||||
*/
|
||||
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName) {
|
||||
this(mongoOperations, collectionName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultIndexOperations}.
|
||||
*
|
||||
* @param mongoOperations must not be {@literal null}.
|
||||
* @param collectionName must not be {@literal null}.
|
||||
* @param type Type used for mapping potential partial index filter expression. Can be {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName, Class<?> type) {
|
||||
|
||||
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
|
||||
Assert.notNull(collectionName, "Collection name can not be null!");
|
||||
|
||||
this.mongoOperations = mongoOperations;
|
||||
this.collectionName = collectionName;
|
||||
this.mapper = new QueryMapper(mongoOperations.getConverter());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -69,9 +81,20 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
* @see org.springframework.data.mongodb.core.IndexOperations#ensureIndex(org.springframework.data.mongodb.core.index.IndexDefinition)
|
||||
*/
|
||||
public void ensureIndex(final IndexDefinition indexDefinition) {
|
||||
|
||||
mongoOperations.execute(collectionName, new CollectionCallback<Object>() {
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
DBObject indexOptions = indexDefinition.getIndexOptions();
|
||||
|
||||
if (indexOptions != null && indexOptions.containsField(PARTIAL_FILTER_EXPRESSION_KEY)) {
|
||||
|
||||
Assert.isInstanceOf(DBObject.class, indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
|
||||
|
||||
indexOptions.put(PARTIAL_FILTER_EXPRESSION_KEY,
|
||||
mapper.getMappedObject((DBObject) indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY),
|
||||
lookupPersistentEntity(type, collectionName)));
|
||||
}
|
||||
|
||||
if (indexOptions != null) {
|
||||
collection.createIndex(indexDefinition.getIndexKeys(), indexOptions);
|
||||
} else {
|
||||
@@ -79,6 +102,24 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MongoPersistentEntity<?> lookupPersistentEntity(Class<?> entityType, String collection) {
|
||||
|
||||
if (entityType != null) {
|
||||
return mongoOperations.getConverter().getMappingContext().getPersistentEntity(entityType);
|
||||
}
|
||||
|
||||
Collection<? extends MongoPersistentEntity<?>> entities = mongoOperations.getConverter().getMappingContext()
|
||||
.getPersistentEntities();
|
||||
|
||||
for (MongoPersistentEntity<?> entity : entities) {
|
||||
if (entity.getCollection().equals(collection)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,7 +167,9 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
public List<IndexInfo> getIndexInfo() {
|
||||
|
||||
return mongoOperations.execute(collectionName, new CollectionCallback<List<IndexInfo>>() {
|
||||
|
||||
public List<IndexInfo> doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
|
||||
List<DBObject> dbObjectList = collection.getIndexInfo();
|
||||
return getIndexData(dbObjectList);
|
||||
}
|
||||
@@ -136,44 +179,7 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
List<IndexInfo> indexInfoList = new ArrayList<IndexInfo>();
|
||||
|
||||
for (DBObject ix : dbObjectList) {
|
||||
|
||||
DBObject keyDbObject = (DBObject) ix.get("key");
|
||||
int numberOfElements = keyDbObject.keySet().size();
|
||||
|
||||
List<IndexField> indexFields = new ArrayList<IndexField>(numberOfElements);
|
||||
|
||||
for (String key : keyDbObject.keySet()) {
|
||||
|
||||
Object value = keyDbObject.get(key);
|
||||
|
||||
if (TWO_D_IDENTIFIERS.contains(value)) {
|
||||
indexFields.add(IndexField.geo(key));
|
||||
} else if ("text".equals(value)) {
|
||||
|
||||
DBObject weights = (DBObject) ix.get("weights");
|
||||
for (String fieldName : weights.keySet()) {
|
||||
indexFields.add(IndexField.text(fieldName, Float.valueOf(weights.get(fieldName).toString())));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Double keyValue = new Double(value.toString());
|
||||
|
||||
if (ONE.equals(keyValue)) {
|
||||
indexFields.add(IndexField.create(key, ASC));
|
||||
} else if (MINUS_ONE.equals(keyValue)) {
|
||||
indexFields.add(IndexField.create(key, DESC));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String name = ix.get("name").toString();
|
||||
|
||||
boolean unique = ix.containsField("unique") ? (Boolean) ix.get("unique") : false;
|
||||
boolean dropDuplicates = ix.containsField("dropDups") ? (Boolean) ix.get("dropDups") : false;
|
||||
boolean sparse = ix.containsField("sparse") ? (Boolean) ix.get("sparse") : false;
|
||||
String language = ix.containsField("default_language") ? (String) ix.get("default_language") : "";
|
||||
indexInfoList.add(new IndexInfo(indexFields, name, unique, dropDuplicates, sparse, language));
|
||||
indexInfoList.add(IndexInfo.indexInfoOf(ix));
|
||||
}
|
||||
|
||||
return indexInfoList;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -98,7 +98,7 @@ class DefaultScriptOperations implements ScriptOperations {
|
||||
|
||||
@Override
|
||||
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||
return db.eval(script.getCode(), convertScriptArgs(args));
|
||||
return db.eval(script.getCode(), convertScriptArgs(false, args));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -155,7 +155,7 @@ class DefaultScriptOperations implements ScriptOperations {
|
||||
return scriptNames;
|
||||
}
|
||||
|
||||
private Object[] convertScriptArgs(Object... args) {
|
||||
private Object[] convertScriptArgs(boolean quote, Object... args) {
|
||||
|
||||
if (ObjectUtils.isEmpty(args)) {
|
||||
return args;
|
||||
@@ -164,15 +164,15 @@ class DefaultScriptOperations implements ScriptOperations {
|
||||
List<Object> convertedValues = new ArrayList<Object>(args.length);
|
||||
|
||||
for (Object arg : args) {
|
||||
convertedValues.add(arg instanceof String ? String.format("'%s'", arg) : this.mongoOperations.getConverter()
|
||||
.convertToMongoType(arg));
|
||||
convertedValues.add(arg instanceof String && quote ? String.format("'%s'", arg)
|
||||
: this.mongoOperations.getConverter().convertToMongoType(arg));
|
||||
}
|
||||
|
||||
return convertedValues.toArray();
|
||||
}
|
||||
|
||||
private String convertAndJoinScriptArgs(Object... args) {
|
||||
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(args));
|
||||
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(true, args));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -27,7 +27,8 @@ import com.mongodb.Mongo;
|
||||
* Mongo server administration exposed via JMX annotations
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Darimont
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@ManagedResource(description = "Mongo Admin Operations")
|
||||
public class MongoAdmin implements MongoAdminOperations {
|
||||
@@ -35,10 +36,11 @@ public class MongoAdmin implements MongoAdminOperations {
|
||||
private final Mongo mongo;
|
||||
private String username;
|
||||
private String password;
|
||||
private String authenticationDatabaseName;
|
||||
private String authenticationDatabaseName;
|
||||
|
||||
public MongoAdmin(Mongo mongo) {
|
||||
Assert.notNull(mongo);
|
||||
|
||||
Assert.notNull(mongo, "Mongo must not be null!");
|
||||
this.mongo = mongo;
|
||||
}
|
||||
|
||||
@@ -84,16 +86,16 @@ public class MongoAdmin implements MongoAdminOperations {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authenticationDatabaseName to use to authenticate with the Mongo database.
|
||||
*
|
||||
* @param authenticationDatabaseName The authenticationDatabaseName to use.
|
||||
*/
|
||||
public void setAuthenticationDatabaseName(String authenticationDatabaseName) {
|
||||
this.authenticationDatabaseName = authenticationDatabaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authenticationDatabaseName to use to authenticate with the Mongo database.
|
||||
*
|
||||
* @param authenticationDatabaseName The authenticationDatabaseName to use.
|
||||
*/
|
||||
public void setAuthenticationDatabaseName(String authenticationDatabaseName) {
|
||||
this.authenticationDatabaseName = authenticationDatabaseName;
|
||||
}
|
||||
|
||||
DB getDB(String databaseName) {
|
||||
return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password), authenticationDatabaseName);
|
||||
return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password), authenticationDatabaseName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ import com.mongodb.util.JSONParseException;
|
||||
|
||||
/**
|
||||
* Primary implementation of {@link MongoOperations}.
|
||||
*
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Graeme Rocher
|
||||
* @author Mark Pollack
|
||||
@@ -138,6 +138,7 @@ import com.mongodb.util.JSONParseException;
|
||||
* @author Chuong Ngo
|
||||
* @author Christoph Strobl
|
||||
* @author Doménique Tilleuil
|
||||
* @author Laszlo Csontos
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
@@ -174,7 +175,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Constructor used for a basic template configuration
|
||||
*
|
||||
*
|
||||
* @param mongo must not be {@literal null}.
|
||||
* @param databaseName must not be {@literal null} or empty.
|
||||
*/
|
||||
@@ -185,7 +186,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Constructor used for a template configuration with user credentials in the form of
|
||||
* {@link org.springframework.data.authentication.UserCredentials}
|
||||
*
|
||||
*
|
||||
* @param mongo must not be {@literal null}.
|
||||
* @param databaseName must not be {@literal null} or empty.
|
||||
* @param userCredentials
|
||||
@@ -196,7 +197,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Constructor used for a basic template configuration.
|
||||
*
|
||||
*
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
*/
|
||||
public MongoTemplate(MongoDbFactory mongoDbFactory) {
|
||||
@@ -205,13 +206,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Constructor used for a basic template configuration.
|
||||
*
|
||||
*
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
* @param mongoConverter
|
||||
*/
|
||||
public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) {
|
||||
|
||||
Assert.notNull(mongoDbFactory);
|
||||
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
|
||||
|
||||
this.mongoDbFactory = mongoDbFactory;
|
||||
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
||||
@@ -234,7 +235,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Configures the {@link WriteResultChecking} to be used with the template. Setting {@literal null} will reset the
|
||||
* default of {@value #DEFAULT_WRITE_RESULT_CHECKING}.
|
||||
*
|
||||
*
|
||||
* @param resultChecking
|
||||
*/
|
||||
public void setWriteResultChecking(WriteResultChecking resultChecking) {
|
||||
@@ -245,7 +246,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* Configures the {@link WriteConcern} to be used with the template. If none is configured the {@link WriteConcern}
|
||||
* configured on the {@link MongoDbFactory} will apply. If you configured a {@link Mongo} instance no
|
||||
* {@link WriteConcern} will be used.
|
||||
*
|
||||
*
|
||||
* @param writeConcern
|
||||
*/
|
||||
public void setWriteConcern(WriteConcern writeConcern) {
|
||||
@@ -254,7 +255,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Configures the {@link WriteConcernResolver} to be used with the template.
|
||||
*
|
||||
*
|
||||
* @param writeConcernResolver
|
||||
*/
|
||||
public void setWriteConcernResolver(WriteConcernResolver writeConcernResolver) {
|
||||
@@ -264,7 +265,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Used by @{link {@link #prepareCollection(DBCollection)} to set the {@link ReadPreference} before any operations are
|
||||
* performed.
|
||||
*
|
||||
*
|
||||
* @param readPreference
|
||||
*/
|
||||
public void setReadPreference(ReadPreference readPreference) {
|
||||
@@ -291,7 +292,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* they were registered for the current {@link MappingContext}. If no creator for the current {@link MappingContext}
|
||||
* can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get
|
||||
* created appropriately for entity types persisted through this {@link MongoTemplate} instance.
|
||||
*
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
private void prepareIndexCreator(ApplicationContext context) {
|
||||
@@ -311,15 +312,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default {@link org.springframework.data.mongodb.core.core.convert.MongoConverter}.
|
||||
*
|
||||
* Returns the default {@link org.springframework.data.mongodb.core.convert.MongoConverter}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public MongoConverter getConverter() {
|
||||
return this.mongoConverter;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
|
||||
*/
|
||||
@@ -412,7 +413,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Execute a MongoDB query and iterate over the query results on a per-document basis with a
|
||||
* {@link DocumentCallbackHandler} using the provided CursorPreparer.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification, must not be {@literal null}.
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
@@ -423,7 +424,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
protected void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch,
|
||||
CursorPreparer preparer) {
|
||||
|
||||
Assert.notNull(query);
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
|
||||
DBObject queryObject = queryMapper.getMappedObject(query.getQueryObject(), null);
|
||||
DBObject sortObject = query.getSortObject();
|
||||
@@ -439,7 +440,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
public <T> T execute(DbCallback<T> action) {
|
||||
|
||||
Assert.notNull(action);
|
||||
Assert.notNull(action, "DbCallbackmust not be null!");
|
||||
|
||||
try {
|
||||
DB db = this.getDb();
|
||||
@@ -455,7 +456,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
public <T> T execute(String collectionName, CollectionCallback<T> callback) {
|
||||
|
||||
Assert.notNull(callback);
|
||||
Assert.notNull(callback, "CollectionCallback must not be null!");
|
||||
|
||||
try {
|
||||
DBCollection collection = getAndPrepareCollection(getDb(), collectionName);
|
||||
@@ -541,7 +542,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
public IndexOperations indexOps(Class<?> entityClass) {
|
||||
return new DefaultIndexOperations(this, determineCollectionName(entityClass));
|
||||
return new DefaultIndexOperations(this, determineCollectionName(entityClass), entityClass);
|
||||
}
|
||||
|
||||
public BulkOperations bulkOps(BulkMode bulkMode, String collectionName) {
|
||||
@@ -683,7 +684,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/*
|
||||
* As MongoDB currently (2.4.4) doesn't support the skipping of elements in near queries
|
||||
* we skip the elements ourselves to avoid at least the document 2 object mapping overhead.
|
||||
*
|
||||
*
|
||||
* @see https://jira.mongodb.org/browse/SERVER-3925
|
||||
*/
|
||||
if (index >= elementsToSkip) {
|
||||
@@ -733,7 +734,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
public long count(Query query, Class<?> entityClass) {
|
||||
Assert.notNull(entityClass);
|
||||
|
||||
Assert.notNull(entityClass, "Entity class must not be null!");
|
||||
return count(query, entityClass, determineCollectionName(entityClass));
|
||||
}
|
||||
|
||||
@@ -747,7 +749,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
*/
|
||||
public long count(Query query, Class<?> entityClass, String collectionName) {
|
||||
|
||||
Assert.hasText(collectionName);
|
||||
Assert.hasText(collectionName, "Collection name must not be null or empty!");
|
||||
|
||||
final DBObject dbObject = query == null ? null
|
||||
: queryMapper.getMappedObject(query.getQueryObject(),
|
||||
entityClass == null ? null : mappingContext.getPersistentEntity(entityClass));
|
||||
@@ -788,7 +791,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Prepare the collection before any processing is done using it. This allows a convenient way to apply settings like
|
||||
* slaveOk() etc. Can be overridden in sub-classes.
|
||||
*
|
||||
*
|
||||
* @param collection
|
||||
*/
|
||||
protected void prepareCollection(DBCollection collection) {
|
||||
@@ -802,7 +805,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* settings in sub-classes. <br />
|
||||
* In case of using MongoDB Java driver version 3 the returned {@link WriteConcern} will be defaulted to
|
||||
* {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}.
|
||||
*
|
||||
*
|
||||
* @param writeConcern any WriteConcern already configured or null
|
||||
* @return The prepared WriteConcern or null
|
||||
*/
|
||||
@@ -826,11 +829,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
initializeVersionProperty(objectToSave);
|
||||
|
||||
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
DBObject dbDoc = toDbObject(objectToSave, writer);
|
||||
|
||||
@@ -918,21 +919,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
protected <T> void doInsertBatch(String collectionName, Collection<? extends T> batchToSave, MongoWriter<T> writer) {
|
||||
|
||||
Assert.notNull(writer);
|
||||
Assert.notNull(writer, "MongoWriter must not be null!");
|
||||
|
||||
List<DBObject> dbObjectList = new ArrayList<DBObject>();
|
||||
|
||||
for (T o : batchToSave) {
|
||||
|
||||
initializeVersionProperty(o);
|
||||
BasicDBObject dbDoc = new BasicDBObject();
|
||||
|
||||
maybeEmitEvent(new BeforeConvertEvent<T>(o, collectionName));
|
||||
|
||||
BasicDBObject dbDoc = new BasicDBObject();
|
||||
writer.write(o, dbDoc);
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<T>(o, dbDoc, collectionName));
|
||||
dbObjectList.add(dbDoc);
|
||||
}
|
||||
List<ObjectId> ids = insertDBObjectList(collectionName, dbObjectList);
|
||||
|
||||
List<Object> ids = consolidateIdentifiers(insertDBObjectList(collectionName, dbObjectList), dbObjectList);
|
||||
|
||||
int i = 0;
|
||||
for (T obj : batchToSave) {
|
||||
if (i < ids.size()) {
|
||||
@@ -945,14 +949,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
public void save(Object objectToSave) {
|
||||
|
||||
Assert.notNull(objectToSave);
|
||||
Assert.notNull(objectToSave, "Object to save must not be null!");
|
||||
save(objectToSave, determineEntityCollectionName(objectToSave));
|
||||
}
|
||||
|
||||
public void save(Object objectToSave, String collectionName) {
|
||||
|
||||
Assert.notNull(objectToSave);
|
||||
Assert.hasText(collectionName);
|
||||
Assert.notNull(objectToSave, "Object to save must not be null!");
|
||||
Assert.hasText(collectionName, "Collection name must not be null or empty!");
|
||||
|
||||
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(objectToSave.getClass());
|
||||
|
||||
@@ -981,6 +985,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
doInsert(collectionName, objectToSave, this.mongoConverter);
|
||||
} else {
|
||||
|
||||
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
// Create query for entity with the id and old version
|
||||
@@ -992,7 +997,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
|
||||
this.mongoConverter.write(objectToSave, dbObject);
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject, collectionName));
|
||||
@@ -1005,9 +1009,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
DBObject dbDoc = toDbObject(objectToSave, writer);
|
||||
|
||||
@@ -1037,6 +1040,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: 2.0 - Change method signature to return List<Object> and return all identifiers (DATAMONGO-1513,
|
||||
// DATAMONGO-1519)
|
||||
protected List<ObjectId> insertDBObjectList(final String collectionName, final List<DBObject> dbDocList) {
|
||||
if (dbDocList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
@@ -1196,7 +1201,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
public WriteResult remove(Object object, String collection) {
|
||||
|
||||
Assert.hasText(collection);
|
||||
Assert.hasText(collection, "Collection name must not be null or empty!");
|
||||
|
||||
if (object == null) {
|
||||
return null;
|
||||
@@ -1208,7 +1213,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Returns {@link Entry} containing the field name of the id property as {@link Entry#getKey()} and the {@link Id}s
|
||||
* property value as its {@link Entry#getValue()}.
|
||||
*
|
||||
*
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
@@ -1235,7 +1240,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Returns a {@link Query} for the given entity by its id.
|
||||
*
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -1247,7 +1252,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Returns a {@link Query} for the given entities by their ids.
|
||||
*
|
||||
*
|
||||
* @param objects must not be {@literal null} or {@literal empty}.
|
||||
* @return
|
||||
*/
|
||||
@@ -1518,7 +1523,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* Retrieve and remove all documents matching the given {@code query} by calling {@link #find(Query, Class, String)}
|
||||
* and {@link #remove(Query, Class, String)}, whereas the {@link Query} for {@link #remove(Query, Class, String)} is
|
||||
* constructed out of the find result.
|
||||
*
|
||||
*
|
||||
* @param collectionName
|
||||
* @param query
|
||||
* @param entityClass
|
||||
@@ -1558,7 +1563,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Returns the potentially mapped results of the given {@commandResult} contained some.
|
||||
*
|
||||
*
|
||||
* @param outputType
|
||||
* @param commandResult
|
||||
* @return
|
||||
@@ -1670,7 +1675,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Create the specified collection using the provided options
|
||||
*
|
||||
*
|
||||
* @param collectionName
|
||||
* @param collectionOptions
|
||||
* @return the collection that was created
|
||||
@@ -1691,7 +1696,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter.
|
||||
* The query document is specified as a standard {@link DBObject} and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from.
|
||||
* @param query the query document that specifies the criteria used to find a record.
|
||||
* @param fields the document that specifies the fields to be returned.
|
||||
@@ -1716,7 +1721,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter. The
|
||||
* query document is specified as a standard DBObject and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param fields the document that specifies the fields to be returned
|
||||
@@ -1732,7 +1737,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. The object is
|
||||
* converted from the MongoDB native representation using an instance of {@see MongoConverter}. The query document is
|
||||
* specified as a standard DBObject and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from.
|
||||
* @param query the query document that specifies the criteria used to find a record.
|
||||
* @param fields the document that specifies the fields to be returned.
|
||||
@@ -1785,7 +1790,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* The first document that matches the query is returned and also removed from the collection in the database.
|
||||
* <p/>
|
||||
* The query document is specified as a standard DBObject and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -1836,7 +1841,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Populates the id property of the saved object, if it's not set already.
|
||||
*
|
||||
*
|
||||
* @param savedObject
|
||||
* @param id
|
||||
*/
|
||||
@@ -1886,7 +1891,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* <li>Execute the given {@link ConnectionCallback} for a {@link DBObject}.</li>
|
||||
* <li>Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.</li>
|
||||
* <ol>
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* @param collectionCallback the callback to retrieve the {@link DBObject} with
|
||||
* @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
|
||||
@@ -1915,7 +1920,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* <li>Iterate over the {@link DBCursor} and applies the given {@link DbObjectCallback} to each of the
|
||||
* {@link DBObject}s collecting the actual result {@link List}.</li>
|
||||
* <ol>
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* @param collectionCallback the callback to retrieve the {@link DBCursor} with
|
||||
* @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it
|
||||
@@ -2022,7 +2027,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Handles {@link WriteResult} errors based on the configured {@link WriteResultChecking}.
|
||||
*
|
||||
*
|
||||
* @param writeResult
|
||||
* @param query
|
||||
* @param operation
|
||||
@@ -2066,7 +2071,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Inspects the given {@link CommandResult} for erros and potentially throws an
|
||||
* {@link InvalidDataAccessApiUsageException} for that error.
|
||||
*
|
||||
*
|
||||
* @param result must not be {@literal null}.
|
||||
* @param source must not be {@literal null}.
|
||||
*/
|
||||
@@ -2104,7 +2109,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original
|
||||
* exception if the conversation failed. Thus allows safe re-throwing of the return value.
|
||||
*
|
||||
*
|
||||
* @param ex the exception to translate
|
||||
* @param exceptionTranslator the {@link PersistenceExceptionTranslator} to be used for translation
|
||||
* @return
|
||||
@@ -2115,12 +2120,34 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return resolved == null ? ex : resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all identifiers for the given documents. Will augment the given identifiers and fill in only the ones that
|
||||
* are {@literal null} currently. This would've been better solved in {@link #insertDBObjectList(String, List)}
|
||||
* directly but would require a signature change of that method.
|
||||
*
|
||||
* @param ids
|
||||
* @param documents
|
||||
* @return TODO: Remove for 2.0 and change method signature of {@link #insertDBObjectList(String, List)}.
|
||||
*/
|
||||
private static List<Object> consolidateIdentifiers(List<ObjectId> ids, List<DBObject> documents) {
|
||||
|
||||
List<Object> result = new ArrayList<Object>(ids.size());
|
||||
|
||||
for (int i = 0; i < ids.size(); i++) {
|
||||
|
||||
ObjectId objectId = ids.get(i);
|
||||
result.add(objectId == null ? documents.get(i).get(ID_FIELD) : objectId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Callback implementations
|
||||
|
||||
/**
|
||||
* Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification
|
||||
* {@link DBObject} and executes that against the {@link DBCollection}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
@@ -2154,7 +2181,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification
|
||||
* {@link DBObject} and executes that against the {@link DBCollection}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
@@ -2168,7 +2195,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
public FindCallback(DBObject query, DBObject fields) {
|
||||
this.query = query;
|
||||
this.query = query == null ? new BasicDBObject() : query;
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
@@ -2185,7 +2212,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification
|
||||
* {@link DBObject} and executes that against the {@link DBCollection}.
|
||||
*
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
private static class FindAndRemoveCallback implements CollectionCallback<DBObject> {
|
||||
@@ -2230,7 +2257,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Simple internal callback to allow operations on a {@link DBObject}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@@ -2243,7 +2270,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Simple {@link DbObjectCallback} that will transform {@link DBObject} into the given target type using the given
|
||||
* {@link MongoReader}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@@ -2255,8 +2282,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
public ReadDbObjectCallback(EntityReader<? super T, DBObject> reader, Class<T> type, String collectionName) {
|
||||
|
||||
Assert.notNull(reader);
|
||||
Assert.notNull(type);
|
||||
Assert.notNull(reader, "EntityReader must not be null!");
|
||||
Assert.notNull(type, "Entity type must not be null!");
|
||||
|
||||
this.reader = reader;
|
||||
this.type = type;
|
||||
this.collectionName = collectionName;
|
||||
@@ -2363,7 +2391,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* {@link DbObjectCallback} that assumes a {@link GeoResult} to be created, delegates actual content unmarshalling to
|
||||
* a delegate and creates a {@link GeoResult} from the result.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class GeoNearResultDbObjectCallback<T> implements DbObjectCallback<GeoResult<T>> {
|
||||
@@ -2374,11 +2402,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
/**
|
||||
* Creates a new {@link GeoNearResultDbObjectCallback} using the given {@link DbObjectCallback} delegate for
|
||||
* {@link GeoResult} content unmarshalling.
|
||||
*
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public GeoNearResultDbObjectCallback(DbObjectCallback<T> delegate, Metric metric) {
|
||||
Assert.notNull(delegate);
|
||||
|
||||
Assert.notNull(delegate, "DocumentCallback must not be null!");
|
||||
|
||||
this.delegate = delegate;
|
||||
this.metric = metric;
|
||||
}
|
||||
@@ -2396,7 +2426,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* A {@link CloseableIterator} that is backed by a MongoDB {@link Cursor}.
|
||||
*
|
||||
*
|
||||
* @since 1.7
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@@ -2408,7 +2438,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CloseableIterableCursorAdapter} backed by the given {@link Cursor}.
|
||||
*
|
||||
*
|
||||
* @param cursor
|
||||
* @param exceptionTranslator
|
||||
* @param objectReadCallback
|
||||
|
||||
@@ -248,11 +248,22 @@ public class Aggregation {
|
||||
*
|
||||
* @param elementsToSkip must not be less than zero.
|
||||
* @return
|
||||
* @deprecated prepare to get this one removed in favor of {@link #skip(long)}.
|
||||
*/
|
||||
public static SkipOperation skip(int elementsToSkip) {
|
||||
return new SkipOperation(elementsToSkip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SkipOperation} skipping the given number of elements.
|
||||
*
|
||||
* @param elementsToSkip must not be less than zero.
|
||||
* @return
|
||||
*/
|
||||
public static SkipOperation skip(long elementsToSkip) {
|
||||
return new SkipOperation(elementsToSkip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LimitOperation} limiting the result to the given number of elements.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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.
|
||||
@@ -20,16 +20,17 @@ import com.mongodb.DBObject;
|
||||
/**
|
||||
* An {@link AggregationExpression} can be used with field expressions in aggregation pipeline stages like
|
||||
* {@code project} and {@code group}.
|
||||
*
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
interface AggregationExpression {
|
||||
public interface AggregationExpression {
|
||||
|
||||
/**
|
||||
* Turns the {@link AggregationExpression} into a {@link DBObject} within the given
|
||||
* {@link AggregationOperationContext}.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -29,6 +29,7 @@ import com.mongodb.DBObject;
|
||||
* @author Tobias Trelle
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @param <T> The class in which the results are mapped onto.
|
||||
* @since 1.3
|
||||
*/
|
||||
@@ -46,8 +47,8 @@ public class AggregationResults<T> implements Iterable<T> {
|
||||
*/
|
||||
public AggregationResults(List<T> mappedResults, DBObject rawResults) {
|
||||
|
||||
Assert.notNull(mappedResults);
|
||||
Assert.notNull(rawResults);
|
||||
Assert.notNull(mappedResults, "List of mapped results must not be null!");
|
||||
Assert.notNull(rawResults, "Raw results must not be null!");
|
||||
|
||||
this.mappedResults = Collections.unmodifiableList(mappedResults);
|
||||
this.rawResults = rawResults;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
|
||||
@@ -552,7 +553,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
/**
|
||||
* Generates an {@code $mod} expression that divides the value of the given field by the previously mentioned field
|
||||
* and returns the remainder.
|
||||
*
|
||||
*
|
||||
* @param fieldReference
|
||||
* @return
|
||||
*/
|
||||
@@ -566,7 +567,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return project("size");
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@@ -622,6 +623,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
static class FieldProjection extends Projection {
|
||||
|
||||
@@ -640,7 +642,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
private FieldProjection(Field field, Object value) {
|
||||
|
||||
super(field);
|
||||
super(new ExposedField(field.getName(), true));
|
||||
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
@@ -732,7 +734,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
this.values = Arrays.asList(values);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2016 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.
|
||||
@@ -38,7 +38,7 @@ public class SkipOperation implements AggregationOperation {
|
||||
/**
|
||||
* Creates a new {@link SkipOperation} skipping the given number of elements.
|
||||
*
|
||||
* @param skipCount number of documents to skip.
|
||||
* @param skipCount number of documents to skip, must not be less than zero.
|
||||
*/
|
||||
public SkipOperation(long skipCount) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -34,6 +34,7 @@ import com.mongodb.DBObject;
|
||||
* property references into document field names.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @since 1.3
|
||||
*/
|
||||
public class TypeBasedAggregationOperationContext implements AggregationOperationContext {
|
||||
@@ -95,7 +96,7 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(
|
||||
field.getTarget(), type);
|
||||
Field mappedField = field(propertyPath.getLeafProperty().getName(),
|
||||
Field mappedField = field(field.getName(),
|
||||
propertyPath.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE));
|
||||
|
||||
return new FieldReference(new ExposedField(mappedField, true));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -23,6 +23,7 @@ import org.springframework.util.Assert;
|
||||
* Conversion registration information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ConverterRegistration {
|
||||
|
||||
@@ -39,7 +40,7 @@ class ConverterRegistration {
|
||||
*/
|
||||
public ConverterRegistration(ConvertiblePair convertiblePair, boolean isReading, boolean isWriting) {
|
||||
|
||||
Assert.notNull(convertiblePair);
|
||||
Assert.notNull(convertiblePair, "ConvertiblePair must not be null!");
|
||||
|
||||
this.convertiblePair = convertiblePair;
|
||||
this.reading = isReading;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -56,6 +56,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CustomConversions {
|
||||
|
||||
@@ -88,7 +89,7 @@ public class CustomConversions {
|
||||
*/
|
||||
public CustomConversions(List<?> converters) {
|
||||
|
||||
Assert.notNull(converters);
|
||||
Assert.notNull(converters, "List of converters must not be null!");
|
||||
|
||||
this.readingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||
this.writingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||
@@ -345,8 +346,8 @@ public class CustomConversions {
|
||||
private static Class<?> getCustomTarget(Class<?> sourceType, Class<?> requestedTargetType,
|
||||
Collection<ConvertiblePair> pairs) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
Assert.notNull(pairs);
|
||||
Assert.notNull(sourceType, "Source Class must not be null!");
|
||||
Assert.notNull(pairs, "Collection of ConvertiblePair must not be null!");
|
||||
|
||||
if (requestedTargetType != null && pairs.contains(new ConvertiblePair(sourceType, requestedTargetType))) {
|
||||
return requestedTargetType;
|
||||
|
||||
@@ -114,6 +114,40 @@ class DBObjectAccessor {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the underlying {@link DBObject} has a value ({@literal null} or non-{@literal null}) for the given
|
||||
* {@link MongoPersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean hasValue(MongoPersistentProperty property) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
String fieldName = property.getFieldName();
|
||||
|
||||
if (!fieldName.contains(".")) {
|
||||
return this.dbObject.containsField(fieldName);
|
||||
}
|
||||
|
||||
String[] parts = fieldName.split("\\.");
|
||||
Map<String, Object> source = this.dbObject;
|
||||
Object result = null;
|
||||
|
||||
for (int i = 1; i < parts.length; i++) {
|
||||
|
||||
result = source.get(parts[i - 1]);
|
||||
source = getAsMap(result);
|
||||
|
||||
if (source == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return source.containsKey(parts[parts.length - 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given source object as map, i.e. {@link BasicDBObject}s and maps as is or {@literal null} otherwise.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2016 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.
|
||||
@@ -180,8 +180,8 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
|
||||
Serializable {
|
||||
static class LazyLoadingInterceptor
|
||||
implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor, Serializable {
|
||||
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD;
|
||||
|
||||
@@ -387,7 +387,8 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
} catch (RuntimeException ex) {
|
||||
|
||||
DataAccessException translatedException = this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
throw new LazyLoadingException("Unable to lazily resolve DBRef!", translatedException);
|
||||
throw new LazyLoadingException("Unable to lazily resolve DBRef!",
|
||||
translatedException != null ? translatedException : ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -41,6 +41,7 @@ import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
import org.springframework.data.mongodb.core.query.GeoCommand;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.NumberUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
@@ -53,6 +54,7 @@ import com.mongodb.DBObject;
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thiago Diniz da Silveira
|
||||
* @since 1.5
|
||||
*/
|
||||
abstract class GeoConverters {
|
||||
@@ -121,7 +123,7 @@ abstract class GeoConverters {
|
||||
return DbObjectToGeoJsonPointConverter.INSTANCE.convert(source);
|
||||
}
|
||||
|
||||
return new Point((Double) source.get("x"), (Double) source.get("y"));
|
||||
return new Point(toPrimitiveDoubleValue(source.get("x")), toPrimitiveDoubleValue(source.get("y")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,9 +257,12 @@ abstract class GeoConverters {
|
||||
}
|
||||
|
||||
DBObject center = (DBObject) source.get("center");
|
||||
Double radius = (Double) source.get("radius");
|
||||
Number radius = (Number) source.get("radius");
|
||||
|
||||
Distance distance = new Distance(radius);
|
||||
Assert.notNull(center, "Center must not be null!");
|
||||
Assert.notNull(radius, "Radius must not be null!");
|
||||
|
||||
Distance distance = new Distance(toPrimitiveDoubleValue(radius));
|
||||
|
||||
if (source.containsField("metric")) {
|
||||
|
||||
@@ -267,9 +272,6 @@ abstract class GeoConverters {
|
||||
distance = distance.in(Metrics.valueOf(metricString));
|
||||
}
|
||||
|
||||
Assert.notNull(center, "Center must not be null!");
|
||||
Assert.notNull(radius, "Radius must not be null!");
|
||||
|
||||
return new Circle(DbObjectToPointConverter.INSTANCE.convert(center), distance);
|
||||
}
|
||||
}
|
||||
@@ -326,9 +328,12 @@ abstract class GeoConverters {
|
||||
}
|
||||
|
||||
DBObject center = (DBObject) source.get("center");
|
||||
Double radius = (Double) source.get("radius");
|
||||
Number radius = (Number) source.get("radius");
|
||||
|
||||
Distance distance = new Distance(radius);
|
||||
Assert.notNull(center, "Center must not be null!");
|
||||
Assert.notNull(radius, "Radius must not be null!");
|
||||
|
||||
Distance distance = new Distance(toPrimitiveDoubleValue(radius));
|
||||
|
||||
if (source.containsField("metric")) {
|
||||
|
||||
@@ -338,9 +343,6 @@ abstract class GeoConverters {
|
||||
distance = distance.in(Metrics.valueOf(metricString));
|
||||
}
|
||||
|
||||
Assert.notNull(center, "Center must not be null!");
|
||||
Assert.notNull(radius, "Radius must not be null!");
|
||||
|
||||
return new Sphere(DbObjectToPointConverter.INSTANCE.convert(center), distance);
|
||||
}
|
||||
}
|
||||
@@ -599,8 +601,8 @@ abstract class GeoConverters {
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Point"),
|
||||
String.format("Cannot convert type '%s' to Point.", source.get("type")));
|
||||
|
||||
List<Double> dbl = (List<Double>) source.get("coordinates");
|
||||
return new GeoJsonPoint(dbl.get(0).doubleValue(), dbl.get(1).doubleValue());
|
||||
List<Number> dbl = (List<Number>) source.get("coordinates");
|
||||
return new GeoJsonPoint(toPrimitiveDoubleValue(dbl.get(0)), toPrimitiveDoubleValue(dbl.get(1)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,9 +834,10 @@ abstract class GeoConverters {
|
||||
|
||||
Assert.isInstanceOf(List.class, point);
|
||||
|
||||
List<Double> coordinatesList = (List<Double>) point;
|
||||
List<Number> coordinatesList = (List<Number>) point;
|
||||
|
||||
points.add(new GeoJsonPoint(coordinatesList.get(0).doubleValue(), coordinatesList.get(1).doubleValue()));
|
||||
points.add(new GeoJsonPoint(toPrimitiveDoubleValue(coordinatesList.get(0)),
|
||||
toPrimitiveDoubleValue(coordinatesList.get(1))));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
@@ -849,4 +852,10 @@ abstract class GeoConverters {
|
||||
static GeoJsonPolygon toGeoJsonPolygon(BasicDBList dbList) {
|
||||
return new GeoJsonPolygon(toListOfPoint((BasicDBList) dbList.get(0)));
|
||||
}
|
||||
|
||||
private static double toPrimitiveDoubleValue(Object value) {
|
||||
|
||||
Assert.isInstanceOf(Number.class, value, "Argument must be a Number.");
|
||||
return NumberUtils.convertNumberToTargetClass((Number) value, Double.class).doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2011-2015 by the original author(s).
|
||||
* Copyright 2011-2017 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
|
||||
* 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,
|
||||
@@ -20,6 +20,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -95,7 +96,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
/**
|
||||
* Creates a new {@link MappingMongoConverter} given the new {@link DbRefResolver} and {@link MappingContext}.
|
||||
*
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
* @param dbRefResolver must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public MappingMongoConverter(DbRefResolver dbRefResolver,
|
||||
@@ -258,14 +259,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
// make sure id property is set before all other properties
|
||||
Object idValue = null;
|
||||
final DBObjectAccessor dbObjectAccessor = new DBObjectAccessor(dbo);
|
||||
|
||||
if (idProperty != null) {
|
||||
if (idProperty != null && dbObjectAccessor.hasValue(idProperty)) {
|
||||
idValue = getValueInternal(idProperty, dbo, evaluator, path);
|
||||
accessor.setProperty(idProperty, idValue);
|
||||
}
|
||||
|
||||
final ObjectPath currentPath = path.push(result, entity,
|
||||
idValue != null ? dbo.get(idProperty.getFieldName()) : null);
|
||||
final ObjectPath currentPath = path.push(result, entity, idValue != null ? dbObjectAccessor.get(idProperty) : null);
|
||||
|
||||
// Set properties not already set in the constructor
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
@@ -276,7 +277,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dbo.containsField(prop.getFieldName()) || entity.isConstructorArgument(prop)) {
|
||||
if (entity.isConstructorArgument(prop) || !dbObjectAccessor.hasValue(prop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -289,7 +290,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||
|
||||
final MongoPersistentProperty property = association.getInverse();
|
||||
Object value = dbo.get(property.getFieldName());
|
||||
Object value = dbObjectAccessor.get(property);
|
||||
|
||||
if (value == null || entity.isConstructorArgument(property)) {
|
||||
return;
|
||||
@@ -309,16 +310,16 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.MongoWriter#toDBRef(java.lang.Object, org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
|
||||
*/
|
||||
public DBRef toDBRef(Object object, MongoPersistentProperty referingProperty) {
|
||||
public DBRef toDBRef(Object object, MongoPersistentProperty referringProperty) {
|
||||
|
||||
org.springframework.data.mongodb.core.mapping.DBRef annotation = null;
|
||||
|
||||
if (referingProperty != null) {
|
||||
annotation = referingProperty.getDBRef();
|
||||
if (referringProperty != null) {
|
||||
annotation = referringProperty.getDBRef();
|
||||
Assert.isTrue(annotation != null, "The referenced property has to be mapped with @DBRef!");
|
||||
}
|
||||
|
||||
@@ -327,14 +328,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return ((LazyLoadingProxy) object).toDBRef();
|
||||
}
|
||||
|
||||
return createDBRef(object, referingProperty);
|
||||
return createDBRef(object, referringProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Root entry method into write conversion. Adds a type discriminator to the {@link DBObject}. Shouldn't be called for
|
||||
* nested conversions.
|
||||
*
|
||||
* @see org.springframework.data.mongodb.core.core.convert.MongoWriter#write(java.lang.Object, com.mongodb.DBObject)
|
||||
* @see org.springframework.data.mongodb.core.convert.MongoWriter#write(java.lang.Object, com.mongodb.DBObject)
|
||||
*/
|
||||
public void write(final Object obj, final DBObject dbo) {
|
||||
|
||||
@@ -477,7 +478,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
DBRef dbRefObj = null;
|
||||
|
||||
/*
|
||||
* If we already have a LazyLoadingProxy, we use it's cached DBRef value instead of
|
||||
* If we already have a LazyLoadingProxy, we use it's cached DBRef value instead of
|
||||
* unnecessarily initializing it only to convert it to a DBRef a few instructions later.
|
||||
*/
|
||||
if (obj instanceof LazyLoadingProxy) {
|
||||
@@ -824,7 +825,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
protected DBRef createDBRef(Object target, MongoPersistentProperty property) {
|
||||
|
||||
Assert.notNull(target);
|
||||
Assert.notNull(target, "Target object must not be null!");
|
||||
|
||||
if (target instanceof DBRef) {
|
||||
return (DBRef) target;
|
||||
@@ -885,10 +886,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
Class<?> collectionType = targetType.getType();
|
||||
|
||||
if (sourceValue.isEmpty()) {
|
||||
return getPotentiallyConvertedSimpleRead(new HashSet<Object>(), collectionType);
|
||||
}
|
||||
|
||||
TypeInformation<?> componentType = targetType.getComponentType();
|
||||
Class<?> rawComponentType = componentType == null ? null : componentType.getType();
|
||||
|
||||
@@ -896,9 +893,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>()
|
||||
: CollectionFactory.createCollection(collectionType, rawComponentType, sourceValue.size());
|
||||
|
||||
for (int i = 0; i < sourceValue.size(); i++) {
|
||||
if (sourceValue.isEmpty()) {
|
||||
return getPotentiallyConvertedSimpleRead(items, collectionType);
|
||||
}
|
||||
|
||||
Object dbObjItem = sourceValue.get(i);
|
||||
for (Object dbObjItem : sourceValue) {
|
||||
|
||||
if (dbObjItem instanceof DBRef) {
|
||||
items.add(
|
||||
@@ -992,20 +991,32 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
if (obj instanceof DBObject) {
|
||||
|
||||
DBObject newValueDbo = new BasicDBObject();
|
||||
|
||||
for (String vk : ((DBObject) obj).keySet()) {
|
||||
|
||||
Object o = ((DBObject) obj).get(vk);
|
||||
newValueDbo.put(vk, convertToMongoType(o, typeHint));
|
||||
}
|
||||
|
||||
return newValueDbo;
|
||||
}
|
||||
|
||||
if (obj instanceof Map) {
|
||||
DBObject result = new BasicDBObject();
|
||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
|
||||
result.put(entry.getKey().toString(), convertToMongoType(entry.getValue(), typeHint));
|
||||
|
||||
Map<Object, Object> converted = new LinkedHashMap<Object, Object>();
|
||||
|
||||
for (Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
|
||||
|
||||
TypeInformation<? extends Object> valueTypeHint = typeHint != null && typeHint.getMapValueType() != null
|
||||
? typeHint.getMapValueType() : typeHint;
|
||||
|
||||
converted.put(getPotentiallyConvertedSimpleWrite(entry.getKey()).toString(),
|
||||
convertToMongoType(entry.getValue(), valueTypeHint));
|
||||
}
|
||||
return result;
|
||||
|
||||
return new BasicDBObject(converted);
|
||||
}
|
||||
|
||||
if (obj.getClass().isArray()) {
|
||||
@@ -1042,7 +1053,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
/**
|
||||
* Removes the type information from the entire conversion result.
|
||||
*
|
||||
*
|
||||
* @param object
|
||||
* @param recursively whether to apply the removal recursively
|
||||
* @return
|
||||
@@ -1103,22 +1114,22 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
/**
|
||||
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and
|
||||
* {@link ObjectPath}.
|
||||
*
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param path can be {@literal null}.
|
||||
*/
|
||||
public MongoDbPropertyValueProvider(DBObject source, SpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||
|
||||
Assert.notNull(source);
|
||||
Assert.notNull(evaluator);
|
||||
Assert.notNull(source, "DBObject must not be null!");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null!");
|
||||
|
||||
this.source = new DBObjectAccessor(source);
|
||||
this.evaluator = evaluator;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@@ -1161,7 +1172,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELExpressionParameterValueProvider#potentiallyConvertSpelValue(java.lang.Object, org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
|
||||
@@ -81,7 +81,10 @@ abstract class MongoConverters {
|
||||
converters.add(DBObjectToNamedMongoScriptCoverter.INSTANCE);
|
||||
converters.add(CurrencyToStringConverter.INSTANCE);
|
||||
converters.add(StringToCurrencyConverter.INSTANCE);
|
||||
converters.add(NumberToNumberConverterFactory.INSTANCE);
|
||||
converters.add(AtomicIntegerToIntegerConverter.INSTANCE);
|
||||
converters.add(AtomicLongToLongConverter.INSTANCE);
|
||||
converters.add(LongToAtomicLongConverter.INSTANCE);
|
||||
converters.add(IntegerToAtomicIntegerConverter.INSTANCE);
|
||||
|
||||
return converters;
|
||||
}
|
||||
@@ -374,4 +377,68 @@ abstract class MongoConverters {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ConverterFactory} implementation converting {@link AtomicLong} into {@link Long}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
@WritingConverter
|
||||
public static enum AtomicLongToLongConverter implements Converter<AtomicLong, Long> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Long convert(AtomicLong source) {
|
||||
return NumberUtils.convertNumberToTargetClass(source, Long.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ConverterFactory} implementation converting {@link AtomicInteger} into {@link Integer}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
@WritingConverter
|
||||
public static enum AtomicIntegerToIntegerConverter implements Converter<AtomicInteger, Integer> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Integer convert(AtomicInteger source) {
|
||||
return NumberUtils.convertNumberToTargetClass(source, Integer.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ConverterFactory} implementation converting {@link Long} into {@link AtomicLong}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum LongToAtomicLongConverter implements Converter<Long, AtomicLong> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public AtomicLong convert(Long source) {
|
||||
return source != null ? new AtomicLong(source) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ConverterFactory} implementation converting {@link Integer} into {@link AtomicInteger}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum IntegerToAtomicIntegerConverter implements Converter<Integer, AtomicInteger> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public AtomicInteger convert(Integer source) {
|
||||
return source != null ? new AtomicInteger(source) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -58,6 +58,7 @@ import com.mongodb.DBRef;
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class QueryMapper {
|
||||
|
||||
@@ -66,7 +67,7 @@ public class QueryMapper {
|
||||
static final ClassTypeInformation<?> NESTED_DOCUMENT = ClassTypeInformation.from(NestedDocument.class);
|
||||
|
||||
private enum MetaMapping {
|
||||
FORCE, WHEN_PRESENT, IGNORE;
|
||||
FORCE, WHEN_PRESENT, IGNORE
|
||||
}
|
||||
|
||||
private final ConversionService conversionService;
|
||||
@@ -81,7 +82,7 @@ public class QueryMapper {
|
||||
*/
|
||||
public QueryMapper(MongoConverter converter) {
|
||||
|
||||
Assert.notNull(converter);
|
||||
Assert.notNull(converter, "MongoConverter must not be null!");
|
||||
|
||||
this.conversionService = converter.getConversionService();
|
||||
this.converter = converter;
|
||||
@@ -316,7 +317,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
if (isNestedKeyword(value)) {
|
||||
return getMappedKeyword(new Keyword((DBObject) value), null);
|
||||
return getMappedKeyword(new Keyword((DBObject) value), documentField.getPropertyEntity());
|
||||
}
|
||||
|
||||
if (isAssociationConversionNecessary(documentField, value)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.util.Assert;
|
||||
* Represents a geospatial sphere value.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @since 1.5
|
||||
*/
|
||||
public class Sphere implements Shape {
|
||||
@@ -46,8 +47,8 @@ public class Sphere implements Shape {
|
||||
@PersistenceConstructor
|
||||
public Sphere(Point center, Distance radius) {
|
||||
|
||||
Assert.notNull(center);
|
||||
Assert.notNull(radius);
|
||||
Assert.notNull(center, "Center point must not be null!");
|
||||
Assert.notNull(radius, "Radius must not be null!");
|
||||
Assert.isTrue(radius.getValue() >= 0, "Radius must not be negative!");
|
||||
|
||||
this.center = center;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2016 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.
|
||||
@@ -39,6 +39,7 @@ public class GeospatialIndex implements IndexDefinition {
|
||||
private GeoSpatialIndexType type = GeoSpatialIndexType.GEO_2D;
|
||||
private Double bucketSize = 1.0;
|
||||
private String additionalField;
|
||||
private IndexFilter filter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeospatialIndex} for the given field.
|
||||
@@ -119,6 +120,22 @@ public class GeospatialIndex implements IndexDefinition {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Only index the documents in a collection that meet a specified {@link IndexFilter filter expression}.
|
||||
*
|
||||
* @param filter can be {@literal null}.
|
||||
* @return
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/core/index-partial/">https://docs.mongodb.com/manual/core/index-partial/</a>
|
||||
* @since 1.10
|
||||
*/
|
||||
public GeospatialIndex partial(IndexFilter filter) {
|
||||
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DBObject getIndexKeys() {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
@@ -186,6 +203,10 @@ public class GeospatialIndex implements IndexDefinition {
|
||||
break;
|
||||
}
|
||||
|
||||
if (filter != null) {
|
||||
dbo.put("partialFilterExpression", filter.getFilterObject());
|
||||
}
|
||||
|
||||
return dbo;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
* Copyright 2010-2016 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.
|
||||
@@ -63,6 +63,8 @@ public class Index implements IndexDefinition {
|
||||
|
||||
private long expire = -1;
|
||||
|
||||
private IndexFilter filter;
|
||||
|
||||
public Index() {}
|
||||
|
||||
public Index(String key, Direction direction) {
|
||||
@@ -176,6 +178,21 @@ public class Index implements IndexDefinition {
|
||||
return unique();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only index the documents in a collection that meet a specified {@link IndexFilter filter expression}.
|
||||
*
|
||||
* @param filter can be {@literal null}.
|
||||
* @return
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/core/index-partial/">https://docs.mongodb.com/manual/core/index-partial/</a>
|
||||
* @since 1.10
|
||||
*/
|
||||
public Index partial(IndexFilter filter) {
|
||||
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexDefinition#getIndexKeys()
|
||||
@@ -213,6 +230,9 @@ public class Index implements IndexDefinition {
|
||||
dbo.put("expireAfterSeconds", expire);
|
||||
}
|
||||
|
||||
if (filter != null) {
|
||||
dbo.put("partialFilterExpression", filter.getFilterObject());
|
||||
}
|
||||
return dbo;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2017 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.
|
||||
@@ -44,8 +44,13 @@ public final class IndexField {
|
||||
|
||||
private IndexField(String key, Direction direction, Type type, Float weight) {
|
||||
|
||||
Assert.hasText(key);
|
||||
Assert.isTrue(direction != null ^ (Type.GEO.equals(type) || Type.TEXT.equals(type)));
|
||||
Assert.hasText(key, "Key must not be null or empty");
|
||||
|
||||
if (Type.GEO.equals(type) || Type.TEXT.equals(type)) {
|
||||
Assert.isTrue(direction == null, "Geo/Text indexes must not have a direction!");
|
||||
} else {
|
||||
Assert.notNull(direction, "Default indexes require a direction");
|
||||
}
|
||||
|
||||
this.key = key;
|
||||
this.direction = direction;
|
||||
@@ -58,17 +63,21 @@ public final class IndexField {
|
||||
*
|
||||
* @deprecated use {@link #create(String, Direction)}.
|
||||
* @param key must not be {@literal null} or emtpy.
|
||||
* @param direction must not be {@literal null}.
|
||||
* @param order must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static IndexField create(String key, Order order) {
|
||||
Assert.notNull(order);
|
||||
|
||||
Assert.notNull(order, "Order must not be null!");
|
||||
|
||||
return new IndexField(key, order.toDirection(), Type.DEFAULT);
|
||||
}
|
||||
|
||||
public static IndexField create(String key, Direction order) {
|
||||
Assert.notNull(order);
|
||||
|
||||
Assert.notNull(order, "Direction must not be null!");
|
||||
|
||||
return new IndexField(key, order, Type.DEFAULT);
|
||||
}
|
||||
|
||||
@@ -128,7 +137,7 @@ public final class IndexField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns wheter the {@link IndexField} is a text index field.
|
||||
* Returns whether the {@link IndexField} is a text index field.
|
||||
*
|
||||
* @return true if type is {@link Type#TEXT}
|
||||
* @since 1.6
|
||||
@@ -158,7 +167,7 @@ public final class IndexField {
|
||||
&& this.type == that.type;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@@ -173,7 +182,7 @@ public final class IndexField {
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2016 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.index;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Use {@link IndexFilter} to create the partial filter expression used when creating
|
||||
* <a href="https://docs.mongodb.com/manual/core/index-partial/">Partial Indexes</a>.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public interface IndexFilter {
|
||||
|
||||
/**
|
||||
* Get the raw (unmapped) filter expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DBObject getFilterObject();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.index;
|
||||
|
||||
import static org.springframework.data.domain.Sort.Direction.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -23,13 +26,20 @@ import java.util.List;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class IndexInfo {
|
||||
|
||||
private static final Double ONE = Double.valueOf(1);
|
||||
private static final Double MINUS_ONE = Double.valueOf(-1);
|
||||
private static final Collection<String> TWO_D_IDENTIFIERS = Arrays.asList("2d", "2dsphere");
|
||||
|
||||
private final List<IndexField> indexFields;
|
||||
|
||||
private final String name;
|
||||
@@ -37,6 +47,7 @@ public class IndexInfo {
|
||||
private final boolean dropDuplicates;
|
||||
private final boolean sparse;
|
||||
private final String language;
|
||||
private String partialFilterExpression;
|
||||
|
||||
/**
|
||||
* @deprecated Will be removed in 1.7. Please use {@link #IndexInfo(List, String, boolean, boolean, boolean, String)}
|
||||
@@ -62,6 +73,64 @@ public class IndexInfo {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IndexInfo} parsing required properties from the given {@literal sourceDocument}.
|
||||
*
|
||||
* @param sourceDocument
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static IndexInfo indexInfoOf(DBObject sourceDocument) {
|
||||
|
||||
DBObject keyDbObject = (DBObject) sourceDocument.get("key");
|
||||
int numberOfElements = keyDbObject.keySet().size();
|
||||
|
||||
List<IndexField> indexFields = new ArrayList<IndexField>(numberOfElements);
|
||||
|
||||
for (String key : keyDbObject.keySet()) {
|
||||
|
||||
Object value = keyDbObject.get(key);
|
||||
|
||||
if (TWO_D_IDENTIFIERS.contains(value)) {
|
||||
|
||||
indexFields.add(IndexField.geo(key));
|
||||
|
||||
} else if ("text".equals(value)) {
|
||||
|
||||
DBObject weights = (DBObject) sourceDocument.get("weights");
|
||||
|
||||
for (String fieldName : weights.keySet()) {
|
||||
indexFields.add(IndexField.text(fieldName, Float.valueOf(weights.get(fieldName).toString())));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Double keyValue = new Double(value.toString());
|
||||
|
||||
if (ONE.equals(keyValue)) {
|
||||
indexFields.add(IndexField.create(key, ASC));
|
||||
} else if (MINUS_ONE.equals(keyValue)) {
|
||||
indexFields.add(IndexField.create(key, DESC));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String name = sourceDocument.get("name").toString();
|
||||
|
||||
boolean unique = sourceDocument.containsField("unique") ? (Boolean) sourceDocument.get("unique") : false;
|
||||
boolean dropDuplicates = sourceDocument.containsField("dropDups") ? (Boolean) sourceDocument.get("dropDups")
|
||||
: false;
|
||||
boolean sparse = sourceDocument.containsField("sparse") ? (Boolean) sourceDocument.get("sparse") : false;
|
||||
String language = sourceDocument.containsField("default_language") ? (String) sourceDocument.get("default_language")
|
||||
: "";
|
||||
String partialFilter = sourceDocument.containsField("partialFilterExpression")
|
||||
? sourceDocument.get("partialFilterExpression").toString() : "";
|
||||
|
||||
IndexInfo info = new IndexInfo(indexFields, name, unique, dropDuplicates, sparse, language);
|
||||
info.partialFilterExpression = partialFilter;
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the individual index fields of the index.
|
||||
*
|
||||
@@ -79,7 +148,8 @@ public class IndexInfo {
|
||||
*/
|
||||
public boolean isIndexForFields(Collection<String> keys) {
|
||||
|
||||
Assert.notNull(keys);
|
||||
Assert.notNull(keys, "Collection of keys must not be null!");
|
||||
|
||||
List<String> indexKeys = new ArrayList<String>(indexFields.size());
|
||||
|
||||
for (IndexField field : indexFields) {
|
||||
@@ -113,10 +183,19 @@ public class IndexInfo {
|
||||
return language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.0
|
||||
*/
|
||||
public String getPartialFilterExpression() {
|
||||
return partialFilterExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IndexInfo [indexFields=" + indexFields + ", name=" + name + ", unique=" + unique + ", dropDuplicates="
|
||||
+ dropDuplicates + ", sparse=" + sparse + ", language=" + language + "]";
|
||||
+ dropDuplicates + ", sparse=" + sparse + ", language=" + language + ", partialFilterExpression="
|
||||
+ partialFilterExpression + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,6 +209,7 @@ public class IndexInfo {
|
||||
result = prime * result + (sparse ? 1231 : 1237);
|
||||
result = prime * result + (unique ? 1231 : 1237);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(language);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(partialFilterExpression);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -171,6 +251,9 @@ public class IndexInfo {
|
||||
if (!ObjectUtils.nullSafeEquals(language, other.language)) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(partialFilterExpression, other.partialFilterExpression)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MongoMappingEventPublisher implements ApplicationEventPublisher {
|
||||
|
||||
@@ -46,7 +47,7 @@ public class MongoMappingEventPublisher implements ApplicationEventPublisher {
|
||||
*/
|
||||
public MongoMappingEventPublisher(MongoPersistentEntityIndexCreator indexCreator) {
|
||||
|
||||
Assert.notNull(indexCreator);
|
||||
Assert.notNull(indexCreator, "MongoPersistentEntityIndexCreator must not be null!");
|
||||
this.indexCreator = indexCreator;
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ public class MongoMappingEventPublisher implements ApplicationEventPublisher {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationEventPublisher#publishEvent(java.lang.Object)
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -79,9 +79,9 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
|
||||
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory,
|
||||
IndexResolver indexResolver) {
|
||||
|
||||
Assert.notNull(mongoDbFactory);
|
||||
Assert.notNull(mappingContext);
|
||||
Assert.notNull(indexResolver);
|
||||
Assert.notNull(mappingContext, "MongoMappingContext must not be null!");
|
||||
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
|
||||
Assert.notNull(indexResolver, "IndexResolver must not be null!");
|
||||
|
||||
this.mongoDbFactory = mongoDbFactory;
|
||||
this.mappingContext = mappingContext;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2016. 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.index;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* {@link IndexFilter} implementation for usage with plain {@link DBObject} as well as {@link CriteriaDefinition} filter
|
||||
* expressions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class PartialIndexFilter implements IndexFilter {
|
||||
|
||||
private final @NonNull Object filterExpression;
|
||||
|
||||
/**
|
||||
* Create new {@link PartialIndexFilter} for given {@link DBObject filter expression}.
|
||||
*
|
||||
* @param where must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static PartialIndexFilter of(DBObject where) {
|
||||
return new PartialIndexFilter(where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link PartialIndexFilter} for given {@link CriteriaDefinition filter expression}.
|
||||
*
|
||||
* @param where must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static PartialIndexFilter of(CriteriaDefinition where) {
|
||||
return new PartialIndexFilter(where);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexFilter#getFilterObject()
|
||||
*/
|
||||
public DBObject getFilterObject() {
|
||||
|
||||
if (filterExpression instanceof DBObject) {
|
||||
return (DBObject) filterExpression;
|
||||
}
|
||||
|
||||
if (filterExpression instanceof CriteriaDefinition) {
|
||||
return ((CriteriaDefinition) filterExpression).getCriteriaObject();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Unknown type %s used as filter expression.", filterExpression.getClass()));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -39,6 +39,7 @@ public class TextIndexDefinition implements IndexDefinition {
|
||||
private Set<TextIndexedFieldSpec> fieldSpecs;
|
||||
private String defaultLanguage;
|
||||
private String languageOverride;
|
||||
private IndexFilter filter;
|
||||
|
||||
TextIndexDefinition() {
|
||||
fieldSpecs = new LinkedHashSet<TextIndexedFieldSpec>();
|
||||
@@ -129,6 +130,10 @@ public class TextIndexDefinition implements IndexDefinition {
|
||||
options.put("language_override", languageOverride);
|
||||
}
|
||||
|
||||
if (filter != null) {
|
||||
options.put("partialFilterExpression", filter.getFilterObject());
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -288,8 +293,8 @@ public class TextIndexDefinition implements IndexDefinition {
|
||||
public TextIndexDefinitionBuilder onField(String fieldname, Float weight) {
|
||||
|
||||
if (this.instance.fieldSpecs.contains(ALL_FIELDS)) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format("Cannot add %s to field spec for all fields.",
|
||||
fieldname));
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("Cannot add %s to field spec for all fields.", fieldname));
|
||||
}
|
||||
|
||||
this.instance.fieldSpecs.add(new TextIndexedFieldSpec(fieldname, weight));
|
||||
@@ -318,15 +323,30 @@ public class TextIndexDefinition implements IndexDefinition {
|
||||
public TextIndexDefinitionBuilder withLanguageOverride(String fieldname) {
|
||||
|
||||
if (StringUtils.hasText(this.instance.languageOverride)) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format(
|
||||
"Cannot set language override on %s as it is already defined on %s.", fieldname,
|
||||
this.instance.languageOverride));
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("Cannot set language override on %s as it is already defined on %s.", fieldname,
|
||||
this.instance.languageOverride));
|
||||
}
|
||||
|
||||
this.instance.languageOverride = fieldname;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only index the documents that meet the specified {@link IndexFilter filter expression}.
|
||||
*
|
||||
* @param filter can be {@literal null}.
|
||||
* @return
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/core/index-partial/">https://docs.mongodb.com/manual/core/index-partial/</a>
|
||||
* @since 1.10
|
||||
*/
|
||||
public TextIndexDefinitionBuilder partial(IndexFilter filter) {
|
||||
|
||||
this.instance.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextIndexDefinition build() {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -51,6 +51,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, MongoPersistentProperty> implements
|
||||
MongoPersistentEntity<T>, ApplicationContextAware {
|
||||
@@ -138,7 +139,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
return getTextScoreProperty() != null;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.BasicPersistentEntity#verify()
|
||||
*/
|
||||
@@ -200,7 +201,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
@Override
|
||||
protected MongoPersistentProperty returnPropertyIfBetterIdPropertyCandidateOrNull(MongoPersistentProperty property) {
|
||||
|
||||
Assert.notNull(property);
|
||||
Assert.notNull(property, "MongoPersistentProperty must not be null!");
|
||||
|
||||
if (!property.isIdProperty()) {
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* Copyright (c) 2011-2017 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,8 @@ 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;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
@@ -34,6 +36,7 @@ import com.mongodb.DBRef;
|
||||
* Simple constant holder for a {@link SimpleTypeHolder} enriched with Mongo specific simple types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public abstract class MongoSimpleTypes {
|
||||
|
||||
@@ -54,12 +57,17 @@ public abstract class MongoSimpleTypes {
|
||||
simpleTypes.add(Pattern.class);
|
||||
simpleTypes.add(Binary.class);
|
||||
simpleTypes.add(UUID.class);
|
||||
|
||||
if (MongoClientVersion.isMongo34Driver()) {
|
||||
simpleTypes
|
||||
.add(ClassUtils.resolveClassName("org.bson.types.Decimal128", MongoSimpleTypes.class.getClassLoader()));
|
||||
}
|
||||
|
||||
MONGO_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes);
|
||||
}
|
||||
|
||||
private static final Set<Class<?>> MONGO_SIMPLE_TYPES;
|
||||
public static final SimpleTypeHolder HOLDER = new SimpleTypeHolder(MONGO_SIMPLE_TYPES, true);
|
||||
|
||||
private MongoSimpleTypes() {
|
||||
}
|
||||
private MongoSimpleTypes() {}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2011 - 2014 the original author or authors.
|
||||
* Copyright 2011-2017 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
|
||||
* 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,
|
||||
@@ -27,6 +27,7 @@ import com.mongodb.DBObject;
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <T> The class in which the results are mapped onto, accessible via an {@link Iterator}.
|
||||
*/
|
||||
public class GroupByResults<T> implements Iterable<T> {
|
||||
@@ -40,10 +41,12 @@ public class GroupByResults<T> implements Iterable<T> {
|
||||
|
||||
public GroupByResults(List<T> mappedResults, DBObject rawResults) {
|
||||
|
||||
Assert.notNull(mappedResults);
|
||||
Assert.notNull(rawResults);
|
||||
Assert.notNull(mappedResults, "List of mapped results must not be null!");
|
||||
Assert.notNull(rawResults, "Raw results must not be null!");
|
||||
|
||||
this.mappedResults = mappedResults;
|
||||
this.rawResults = rawResults;
|
||||
|
||||
parseKeys();
|
||||
parseCount();
|
||||
parseServerUsed();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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
|
||||
* 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,
|
||||
@@ -29,6 +29,7 @@ import com.mongodb.MapReduceOutput;
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <T> The class in which the results are mapped onto, accessible via an iterator.
|
||||
*/
|
||||
public class MapReduceResults<T> implements Iterable<T> {
|
||||
@@ -49,8 +50,8 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
@Deprecated
|
||||
public MapReduceResults(List<T> mappedResults, DBObject rawResults) {
|
||||
|
||||
Assert.notNull(mappedResults);
|
||||
Assert.notNull(rawResults);
|
||||
Assert.notNull(mappedResults, "List of mapped results must not be null!");
|
||||
Assert.notNull(rawResults, "Raw results must not be null!");
|
||||
|
||||
this.mappedResults = mappedResults;
|
||||
this.rawResults = rawResults;
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.mongodb.DBObject;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class Criteria implements CriteriaDefinition {
|
||||
|
||||
@@ -387,7 +388,7 @@ public class Criteria implements CriteriaDefinition {
|
||||
*/
|
||||
public Criteria regex(Pattern pattern) {
|
||||
|
||||
Assert.notNull(pattern);
|
||||
Assert.notNull(pattern, "Pattern must not be null!");
|
||||
|
||||
if (lastOperatorWasNot()) {
|
||||
return not(pattern);
|
||||
@@ -398,7 +399,9 @@ public class Criteria implements CriteriaDefinition {
|
||||
}
|
||||
|
||||
private Pattern toPattern(String regex, String options) {
|
||||
Assert.notNull(regex);
|
||||
|
||||
Assert.notNull(regex, "Regex string must not be null!");
|
||||
|
||||
return Pattern.compile(regex, options == null ? 0 : BSON.regexFlags(options));
|
||||
}
|
||||
|
||||
@@ -412,7 +415,9 @@ public class Criteria implements CriteriaDefinition {
|
||||
* @return
|
||||
*/
|
||||
public Criteria withinSphere(Circle circle) {
|
||||
Assert.notNull(circle);
|
||||
|
||||
Assert.notNull(circle, "Circle must not be null!");
|
||||
|
||||
criteria.put("$geoWithin", new GeoCommand(new Sphere(circle)));
|
||||
return this;
|
||||
}
|
||||
@@ -426,7 +431,8 @@ public class Criteria implements CriteriaDefinition {
|
||||
*/
|
||||
public Criteria within(Shape shape) {
|
||||
|
||||
Assert.notNull(shape);
|
||||
Assert.notNull(shape, "Shape must not be null!");
|
||||
|
||||
criteria.put("$geoWithin", new GeoCommand(shape));
|
||||
return this;
|
||||
}
|
||||
@@ -439,7 +445,9 @@ public class Criteria implements CriteriaDefinition {
|
||||
* @return
|
||||
*/
|
||||
public Criteria near(Point point) {
|
||||
Assert.notNull(point);
|
||||
|
||||
Assert.notNull(point, "Point must not be null!");
|
||||
|
||||
criteria.put("$near", point);
|
||||
return this;
|
||||
}
|
||||
@@ -453,7 +461,9 @@ public class Criteria implements CriteriaDefinition {
|
||||
* @return
|
||||
*/
|
||||
public Criteria nearSphere(Point point) {
|
||||
Assert.notNull(point);
|
||||
|
||||
Assert.notNull(point, "Point must not be null!");
|
||||
|
||||
criteria.put("$nearSphere", point);
|
||||
return this;
|
||||
}
|
||||
@@ -707,7 +717,7 @@ public class Criteria implements CriteriaDefinition {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@@ -770,7 +780,7 @@ public class Criteria implements CriteriaDefinition {
|
||||
return ObjectUtils.nullSafeEquals(left, right);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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
|
||||
* 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,
|
||||
@@ -49,11 +49,11 @@ public final class NearQuery {
|
||||
/**
|
||||
* Creates a new {@link NearQuery}.
|
||||
*
|
||||
* @param point
|
||||
* @param point must not be {@literal null}.
|
||||
*/
|
||||
private NearQuery(Point point, Metric metric) {
|
||||
|
||||
Assert.notNull(point);
|
||||
Assert.notNull(point, "Point must not be null!");
|
||||
|
||||
this.point = point;
|
||||
this.spherical = false;
|
||||
@@ -108,7 +108,6 @@ public final class NearQuery {
|
||||
* @return
|
||||
*/
|
||||
public static NearQuery near(Point point, Metric metric) {
|
||||
Assert.notNull(point);
|
||||
return new NearQuery(point, metric);
|
||||
}
|
||||
|
||||
@@ -185,7 +184,8 @@ public final class NearQuery {
|
||||
*/
|
||||
public NearQuery maxDistance(double maxDistance, Metric metric) {
|
||||
|
||||
Assert.notNull(metric);
|
||||
Assert.notNull(metric, "Metric must not be null!");
|
||||
|
||||
return maxDistance(new Distance(maxDistance, metric));
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public final class NearQuery {
|
||||
*/
|
||||
public NearQuery maxDistance(Distance distance) {
|
||||
|
||||
Assert.notNull(distance);
|
||||
Assert.notNull(distance, "Distance must not be null!");
|
||||
|
||||
if (distance.getMetric() != Metrics.NEUTRAL) {
|
||||
this.spherical(true);
|
||||
@@ -241,7 +241,8 @@ public final class NearQuery {
|
||||
*/
|
||||
public NearQuery minDistance(double minDistance, Metric metric) {
|
||||
|
||||
Assert.notNull(metric);
|
||||
Assert.notNull(metric, "Metric must not be null!");
|
||||
|
||||
return minDistance(new Distance(minDistance, metric));
|
||||
}
|
||||
|
||||
@@ -255,7 +256,7 @@ public final class NearQuery {
|
||||
*/
|
||||
public NearQuery minDistance(Distance distance) {
|
||||
|
||||
Assert.notNull(distance);
|
||||
Assert.notNull(distance, "Distance must not be null!");
|
||||
|
||||
if (distance.getMetric() != Metrics.NEUTRAL) {
|
||||
this.spherical(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -29,6 +29,8 @@ import org.springframework.util.Assert;
|
||||
* A value object for nodes in an expression. Allows iterating ove potentially available child {@link ExpressionNode}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||
|
||||
@@ -157,7 +159,7 @@ public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||
*/
|
||||
public ExpressionNode getChild(int index) {
|
||||
|
||||
Assert.isTrue(index >= 0);
|
||||
Assert.isTrue(index >= 0, "Index must be greater or equal to zero!");
|
||||
return from(node.getChild(index), state);
|
||||
}
|
||||
|
||||
@@ -183,7 +185,7 @@ public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||
return from(node, state);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.util.Assert;
|
||||
* Value object to abstract Ant paths.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class AntPath {
|
||||
|
||||
@@ -38,7 +39,9 @@ class AntPath {
|
||||
* @param path must not be {@literal null}.
|
||||
*/
|
||||
public AntPath(String path) {
|
||||
Assert.notNull(path);
|
||||
|
||||
Assert.notNull(path, "Path must not be null!");
|
||||
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -45,6 +45,8 @@ import com.mongodb.gridfs.GridFSInputFile;
|
||||
* @author Philipp Schneider
|
||||
* @author Thomas Darimont
|
||||
* @author Martin Baumgartner
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver {
|
||||
|
||||
@@ -72,8 +74,8 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
*/
|
||||
public GridFsTemplate(MongoDbFactory dbFactory, MongoConverter converter, String bucket) {
|
||||
|
||||
Assert.notNull(dbFactory);
|
||||
Assert.notNull(converter);
|
||||
Assert.notNull(dbFactory, "MongoDbFactory must not be null!");
|
||||
Assert.notNull(converter, "MongoConverter must not be null!");
|
||||
|
||||
this.dbFactory = dbFactory;
|
||||
this.converter = converter;
|
||||
@@ -155,7 +157,7 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
*/
|
||||
public GridFSFile store(InputStream content, String filename, String contentType, DBObject metadata) {
|
||||
|
||||
Assert.notNull(content);
|
||||
Assert.notNull(content, "InputStream must not be null!");
|
||||
|
||||
GridFSInputFile file = getGridFs().createFile(content);
|
||||
|
||||
@@ -182,7 +184,7 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
public List<GridFSDBFile> find(Query query) {
|
||||
|
||||
if (query == null) {
|
||||
return getGridFs().find((DBObject) null);
|
||||
return getGridFs().find(new BasicDBObject());
|
||||
}
|
||||
|
||||
DBObject queryObject = getMappedQuery(query.getQueryObject());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 the original author or authors.
|
||||
* Copyright 2010-2017 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.
|
||||
@@ -55,7 +55,7 @@ public interface MongoRepository<T, ID extends Serializable>
|
||||
List<T> findAll(Sort sort);
|
||||
|
||||
/**
|
||||
* Inserts the given a given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use
|
||||
* Inserts the given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use
|
||||
* the returned instance for further operations as the save operation might have changed the entity instance
|
||||
* completely. Prefer using {@link #save(Object)} instead to avoid the usage of store-specific API.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2017 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.
|
||||
@@ -53,11 +53,11 @@ public class MongoRepositoryBean<T> extends CdiRepositoryBean<T> {
|
||||
|
||||
super(qualifiers, repositoryType, beanManager, detector);
|
||||
|
||||
Assert.notNull(operations);
|
||||
Assert.notNull(operations, "MongoOperations bean must not be null!");
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.cdi.CdiRepositoryBean#create(javax.enterprise.context.spi.CreationalContext, java.lang.Class)
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -19,21 +19,15 @@ import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mongodb.config.BeanNames;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
@@ -47,8 +41,6 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
private static final String MONGO_TEMPLATE_REF = "mongo-template-ref";
|
||||
private static final String CREATE_QUERY_INDEXES = "create-query-indexes";
|
||||
|
||||
private boolean fallbackMappingContextCreated = false;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModuleName()
|
||||
@@ -81,7 +73,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
*/
|
||||
@Override
|
||||
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
||||
return Collections.<Class<? extends Annotation>> singleton(Document.class);
|
||||
return Collections.<Class<? extends Annotation>>singleton(Document.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -90,19 +82,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
*/
|
||||
@Override
|
||||
protected Collection<Class<?>> getIdentifyingTypes() {
|
||||
return Collections.<Class<?>> singleton(MongoRepository.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.RepositoryConfigurationSource)
|
||||
*/
|
||||
@Override
|
||||
public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource source) {
|
||||
|
||||
if (fallbackMappingContextCreated) {
|
||||
builder.addPropertyReference("mappingContext", BeanNames.MAPPING_CONTEXT_BEAN_NAME);
|
||||
}
|
||||
return Collections.<Class<?>>singleton(MongoRepository.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -130,23 +110,4 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
builder.addPropertyReference("mongoOperations", attributes.getString("mongoTemplateRef"));
|
||||
builder.addPropertyValue("createIndexesForQueryMethods", attributes.getBoolean("createIndexesForQueryMethods"));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource)
|
||||
*/
|
||||
@Override
|
||||
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource configurationSource) {
|
||||
|
||||
super.registerBeansForRoot(registry, configurationSource);
|
||||
|
||||
if (!registry.containsBeanDefinition(BeanNames.MAPPING_CONTEXT_BEAN_NAME)) {
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition(MongoMappingContext.class);
|
||||
definition.setRole(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
definition.setSource(configurationSource.getSource());
|
||||
|
||||
registry.registerBeanDefinition(BeanNames.MAPPING_CONTEXT_BEAN_NAME, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -42,6 +42,7 @@ import com.mongodb.DBRef;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
|
||||
@@ -56,41 +57,41 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
*/
|
||||
public ConvertingParameterAccessor(MongoWriter<?> writer, MongoParameterAccessor delegate) {
|
||||
|
||||
Assert.notNull(writer);
|
||||
Assert.notNull(delegate);
|
||||
Assert.notNull(writer, "MongoWriter must not be null!");
|
||||
Assert.notNull(delegate, "MongoParameterAccessor must not be null!");
|
||||
|
||||
this.writer = writer;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public PotentiallyConvertingIterator iterator() {
|
||||
return new ConvertingIterator(delegate.iterator());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.query.ParameterAccessor#getPageable()
|
||||
*/
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.query.ParameterAccessor#getPageable()
|
||||
*/
|
||||
public Pageable getPageable() {
|
||||
return delegate.getPageable();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.query.ParameterAccessor#getSort()
|
||||
*/
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.query.ParameterAccessor#getSort()
|
||||
*/
|
||||
public Sort getSort() {
|
||||
return delegate.getSort();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ParameterAccessor#getDynamicProjection()
|
||||
*/
|
||||
@@ -107,7 +108,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
return getConvertedValue(delegate.getBindableValue(index), null);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.MongoParameterAccessor#getDistanceRange()
|
||||
*/
|
||||
@@ -116,7 +117,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
return delegate.getDistanceRange();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.MongoParameterAccessor#getGeoNearLocation()
|
||||
*/
|
||||
@@ -143,7 +144,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
return writer.convertToMongoType(value, typeInformation == null ? null : typeInformation.getActualType());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ParameterAccessor#hasBindableNullValue()
|
||||
*/
|
||||
@@ -185,7 +186,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
return delegate.next();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.ConvertingParameterAccessor.PotentiallConvertingIterator#nextConverted()
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -15,8 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import java.util.Collections;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
@@ -30,15 +39,17 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
* {@link ExpressionEvaluatingParameterBinder} allows to evaluate, convert and bind parameters to placholders within a
|
||||
* {@link ExpressionEvaluatingParameterBinder} allows to evaluate, convert and bind parameters to placeholders within a
|
||||
* {@link String}.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @since 1.9
|
||||
*/
|
||||
class ExpressionEvaluatingParameterBinder {
|
||||
@@ -48,7 +59,7 @@ class ExpressionEvaluatingParameterBinder {
|
||||
|
||||
/**
|
||||
* Creates new {@link ExpressionEvaluatingParameterBinder}
|
||||
*
|
||||
*
|
||||
* @param expressionParser must not be {@literal null}.
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
*/
|
||||
@@ -65,7 +76,7 @@ class ExpressionEvaluatingParameterBinder {
|
||||
/**
|
||||
* Bind values provided by {@link MongoParameterAccessor} to placeholders in {@literal raw} while considering
|
||||
* potential conversions and parameter types.
|
||||
*
|
||||
*
|
||||
* @param raw can be {@literal null} or empty.
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param bindingContext must not be {@literal null}.
|
||||
@@ -82,10 +93,10 @@ class ExpressionEvaluatingParameterBinder {
|
||||
|
||||
/**
|
||||
* Replaced the parameter placeholders with the actual parameter values from the given {@link ParameterBinding}s.
|
||||
*
|
||||
*
|
||||
* @param input must not be {@literal null} or empty.
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param bindings must not be {@literal null}.
|
||||
* @param bindingContext must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private String replacePlaceholders(String input, MongoParameterAccessor accessor, BindingContext bindingContext) {
|
||||
@@ -94,47 +105,88 @@ class ExpressionEvaluatingParameterBinder {
|
||||
return input;
|
||||
}
|
||||
|
||||
boolean isCompletlyParameterizedQuery = input.matches("^\\?\\d+$");
|
||||
StringBuilder result = new StringBuilder(input);
|
||||
|
||||
for (ParameterBinding binding : bindingContext.getBindings()) {
|
||||
|
||||
String parameter = binding.getParameter();
|
||||
int idx = result.indexOf(parameter);
|
||||
|
||||
if (idx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String valueForBinding = getParameterValueForBinding(accessor, bindingContext.getParameters(), binding);
|
||||
|
||||
int start = idx;
|
||||
int end = idx + parameter.length();
|
||||
|
||||
// If the value to bind is an object literal we need to remove the quoting around the expression insertion point.
|
||||
if (valueForBinding.startsWith("{") && !isCompletlyParameterizedQuery) {
|
||||
|
||||
// Is the insertion point actually surrounded by quotes?
|
||||
char beforeStart = result.charAt(start - 1);
|
||||
char afterEnd = result.charAt(end);
|
||||
|
||||
if ((beforeStart == '\'' || beforeStart == '"') && (afterEnd == '\'' || afterEnd == '"')) {
|
||||
|
||||
// Skip preceding and following quote
|
||||
start -= 1;
|
||||
end += 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.replace(start, end, valueForBinding);
|
||||
if (input.matches("^\\?\\d+$")) {
|
||||
return getParameterValueForBinding(accessor, bindingContext.getParameters(),
|
||||
bindingContext.getBindings().iterator().next());
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
Matcher matcher = createReplacementPattern(bindingContext.getBindings()).matcher(input);
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
int parameterIndex = 0;
|
||||
while (matcher.find()) {
|
||||
|
||||
Placeholder placeholder = extractPlaceholder(parameterIndex++, matcher);
|
||||
ParameterBinding binding = bindingContext.getBindingFor(placeholder);
|
||||
String valueForBinding = getParameterValueForBinding(accessor, bindingContext.getParameters(), binding);
|
||||
|
||||
// appendReplacement does not like unescaped $ sign and others, so we need to quote that stuff first
|
||||
matcher.appendReplacement(buffer, Matcher.quoteReplacement(valueForBinding));
|
||||
if (StringUtils.hasText(placeholder.getSuffix())) {
|
||||
buffer.append(placeholder.getSuffix());
|
||||
}
|
||||
|
||||
if (placeholder.isQuoted()) {
|
||||
postProcessQuotedBinding(buffer, valueForBinding,
|
||||
!binding.isExpression() ? accessor.getBindableValue(binding.getParameterIndex()) : null,
|
||||
binding.isExpression());
|
||||
}
|
||||
}
|
||||
|
||||
matcher.appendTail(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize String binding by replacing single quoted values with double quotes which prevents potential single quotes
|
||||
* contained in replacement to interfere with the Json parsing. Also take care of complex objects by removing the
|
||||
* quotation entirely.
|
||||
*
|
||||
* @param buffer the {@link StringBuffer} to operate upon.
|
||||
* @param valueForBinding the actual binding value.
|
||||
* @param raw the raw binding value
|
||||
* @param isExpression {@literal true} if the binding value results from a SpEL expression.
|
||||
*/
|
||||
private void postProcessQuotedBinding(StringBuffer buffer, String valueForBinding, Object raw, boolean isExpression) {
|
||||
|
||||
int quotationMarkIndex = buffer.length() - valueForBinding.length() - 1;
|
||||
char quotationMark = buffer.charAt(quotationMarkIndex);
|
||||
|
||||
while (quotationMark != '\'' && quotationMark != '"') {
|
||||
|
||||
quotationMarkIndex--;
|
||||
|
||||
if (quotationMarkIndex < 0) {
|
||||
throw new IllegalArgumentException("Could not find opening quotes for quoted parameter");
|
||||
}
|
||||
|
||||
quotationMark = buffer.charAt(quotationMarkIndex);
|
||||
}
|
||||
|
||||
// remove quotation char before the complex object string
|
||||
if (valueForBinding.startsWith("{") && (raw instanceof DBObject || isExpression)) {
|
||||
|
||||
buffer.deleteCharAt(quotationMarkIndex);
|
||||
|
||||
} else {
|
||||
|
||||
if (isExpression) {
|
||||
|
||||
buffer.deleteCharAt(quotationMarkIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (quotationMark == '\'') {
|
||||
buffer.replace(quotationMarkIndex, quotationMarkIndex + 1, "\"");
|
||||
}
|
||||
|
||||
buffer.append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serialized value to be used for the given {@link ParameterBinding}.
|
||||
*
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param parameters
|
||||
* @param binding must not be {@literal null}.
|
||||
@@ -148,7 +200,12 @@ class ExpressionEvaluatingParameterBinder {
|
||||
: accessor.getBindableValue(binding.getParameterIndex());
|
||||
|
||||
if (value instanceof String && binding.isQuoted()) {
|
||||
return (String) value;
|
||||
|
||||
if (binding.isExpression() && ((String) value).startsWith("{")) {
|
||||
return (String) value;
|
||||
}
|
||||
|
||||
return binding.isExpression() ? JSON.serialize(value) : QuotedString.unquote(JSON.serialize(value));
|
||||
}
|
||||
|
||||
if (value instanceof byte[]) {
|
||||
@@ -167,7 +224,7 @@ class ExpressionEvaluatingParameterBinder {
|
||||
|
||||
/**
|
||||
* Evaluates the given {@code expressionString}.
|
||||
*
|
||||
*
|
||||
* @param expressionString must not be {@literal null} or empty.
|
||||
* @param parameters must not be {@literal null}.
|
||||
* @param parameterValues must not be {@literal null}.
|
||||
@@ -181,25 +238,88 @@ class ExpressionEvaluatingParameterBinder {
|
||||
return expression.getValue(evaluationContext, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a replacement {@link Pattern} for all {@link ParameterBinding#getParameter() binding parameters} including
|
||||
* a potentially trailing quotation mark.
|
||||
*
|
||||
* @param bindings
|
||||
* @return
|
||||
*/
|
||||
private Pattern createReplacementPattern(List<ParameterBinding> bindings) {
|
||||
|
||||
StringBuilder regex = new StringBuilder();
|
||||
|
||||
for (ParameterBinding binding : bindings) {
|
||||
|
||||
regex.append("|");
|
||||
regex.append("(" + Pattern.quote(binding.getParameter()) + ")");
|
||||
regex.append("([\\w.]*");
|
||||
regex.append("(\\W?['\"]|\\w*')?)");
|
||||
}
|
||||
|
||||
return Pattern.compile(regex.substring(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the placeholder stripping any trailing trailing quotation mark that might have resulted from the
|
||||
* {@link #createReplacementPattern(List) pattern} used.
|
||||
*
|
||||
* @param parameterIndex The actual parameter index.
|
||||
* @param matcher The actual {@link Matcher}.
|
||||
* @return
|
||||
*/
|
||||
private Placeholder extractPlaceholder(int parameterIndex, Matcher matcher) {
|
||||
|
||||
String rawPlaceholder = matcher.group(parameterIndex * 3 + 1);
|
||||
String suffix = matcher.group(parameterIndex * 3 + 2);
|
||||
|
||||
if (!StringUtils.hasText(rawPlaceholder)) {
|
||||
|
||||
rawPlaceholder = matcher.group();
|
||||
if (rawPlaceholder.matches(".*\\d$")) {
|
||||
suffix = "";
|
||||
} else {
|
||||
int index = rawPlaceholder.replaceAll("[^\\?0-9]*$", "").length() - 1;
|
||||
if (index > 0 && rawPlaceholder.length() > index) {
|
||||
suffix = rawPlaceholder.substring(index + 1);
|
||||
}
|
||||
}
|
||||
if (QuotedString.endsWithQuote(rawPlaceholder)) {
|
||||
rawPlaceholder = rawPlaceholder.substring(0,
|
||||
rawPlaceholder.length() - (StringUtils.hasText(suffix) ? suffix.length() : 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(suffix)) {
|
||||
|
||||
boolean quoted = QuotedString.endsWithQuote(suffix);
|
||||
|
||||
return Placeholder.of(parameterIndex, rawPlaceholder, quoted,
|
||||
quoted ? QuotedString.unquoteSuffix(suffix) : suffix);
|
||||
}
|
||||
return Placeholder.of(parameterIndex, rawPlaceholder, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 1.9
|
||||
*/
|
||||
static class BindingContext {
|
||||
|
||||
final MongoParameters parameters;
|
||||
final List<ParameterBinding> bindings;
|
||||
final Map<Placeholder, ParameterBinding> bindings;
|
||||
|
||||
/**
|
||||
* Creates new {@link BindingContext}.
|
||||
*
|
||||
*
|
||||
* @param parameters
|
||||
* @param bindings
|
||||
*/
|
||||
public BindingContext(MongoParameters parameters, List<ParameterBinding> bindings) {
|
||||
|
||||
this.parameters = parameters;
|
||||
this.bindings = bindings;
|
||||
this.bindings = mapBindings(bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,21 +331,113 @@ class ExpressionEvaluatingParameterBinder {
|
||||
|
||||
/**
|
||||
* Get unmodifiable list of {@link ParameterBinding}s.
|
||||
*
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public List<ParameterBinding> getBindings() {
|
||||
return Collections.unmodifiableList(bindings);
|
||||
return new ArrayList<ParameterBinding>(bindings.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the concrete {@link ParameterBinding} for a given {@literal placeholder}.
|
||||
*
|
||||
* @param placeholder must not be {@literal null}.
|
||||
* @return
|
||||
* @throws java.util.NoSuchElementException
|
||||
* @since 1.10
|
||||
*/
|
||||
ParameterBinding getBindingFor(Placeholder placeholder) {
|
||||
|
||||
if (!bindings.containsKey(placeholder)) {
|
||||
throw new NoSuchElementException(String.format("Could not to find binding for placeholder '%s'.", placeholder));
|
||||
}
|
||||
|
||||
return bindings.get(placeholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the associated {@link MongoParameters}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public MongoParameters getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static Map<Placeholder, ParameterBinding> mapBindings(List<ParameterBinding> bindings) {
|
||||
|
||||
Map<Placeholder, ParameterBinding> map = new LinkedHashMap<Placeholder, ParameterBinding>(bindings.size(), 1);
|
||||
|
||||
int parameterIndex = 0;
|
||||
for (ParameterBinding binding : bindings) {
|
||||
map.put(Placeholder.of(parameterIndex++, binding.getParameter(), binding.isQuoted(), null), binding);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates a quoted/unquoted parameter placeholder.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.9
|
||||
*/
|
||||
@Value(staticConstructor = "of")
|
||||
@EqualsAndHashCode(exclude = { "quoted", "suffix" })
|
||||
static class Placeholder {
|
||||
|
||||
private int parameterIndex;
|
||||
private final String parameter;
|
||||
private final boolean quoted;
|
||||
private final String suffix;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return quoted ? String.format("'%s'", parameter + (suffix != null ? suffix : ""))
|
||||
: parameter + (suffix != null ? suffix : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to handle quoted strings using single/double quotes.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@UtilityClass
|
||||
static class QuotedString {
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return {@literal true} if {@literal string} ends with a single/double quote.
|
||||
*/
|
||||
static boolean endsWithQuote(String string) {
|
||||
return string.endsWith("'") || string.endsWith("\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove trailing quoting from {@literal quoted}.
|
||||
*
|
||||
* @param quoted
|
||||
* @return {@literal quoted} with removed quotes.
|
||||
*/
|
||||
public static String unquoteSuffix(String quoted) {
|
||||
return quoted.substring(0, quoted.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove leading and trailing quoting from {@literal quoted}.
|
||||
*
|
||||
* @param quoted
|
||||
* @return {@literal quoted} with removed quotes.
|
||||
*/
|
||||
public static String unquote(String quoted) {
|
||||
return quoted.substring(1, quoted.length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
* Copyright 2010-2017 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.
|
||||
@@ -47,6 +47,7 @@ import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
|
||||
import org.springframework.data.repository.query.parser.Part.Type;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Custom query creator to create Mongo criterias.
|
||||
@@ -54,6 +55,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Edward Prentice
|
||||
*/
|
||||
class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
|
||||
@@ -91,7 +93,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
|
||||
super(tree, accessor);
|
||||
|
||||
Assert.notNull(context);
|
||||
Assert.notNull(context, "MappingContext must not be null!");
|
||||
|
||||
this.accessor = accessor;
|
||||
this.isGeoNearQuery = isGeoNearQuery;
|
||||
@@ -200,7 +202,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
case CONTAINING:
|
||||
return createContainingCriteria(part, property, criteria, parameters);
|
||||
case NOT_CONTAINING:
|
||||
return createContainingCriteria(part, property, criteria, parameters).not();
|
||||
return createContainingCriteria(part, property, criteria.not(), parameters);
|
||||
case REGEX:
|
||||
return criteria.regex(parameters.next().toString());
|
||||
case EXISTS:
|
||||
@@ -296,7 +298,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
criteria = criteria.not();
|
||||
}
|
||||
|
||||
return addAppropriateLikeRegexTo(criteria, part, parameters.next().toString());
|
||||
return addAppropriateLikeRegexTo(criteria, part, parameters.next());
|
||||
|
||||
case NEVER:
|
||||
// intentional no-op
|
||||
@@ -324,7 +326,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
return criteria.in(nextAsArray(parameters));
|
||||
}
|
||||
|
||||
return addAppropriateLikeRegexTo(criteria, part, parameters.next().toString());
|
||||
return addAppropriateLikeRegexTo(criteria, part, parameters.next());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,9 +337,15 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
* @param value
|
||||
* @return the criteria extended with the regex.
|
||||
*/
|
||||
private Criteria addAppropriateLikeRegexTo(Criteria criteria, Part part, String value) {
|
||||
private Criteria addAppropriateLikeRegexTo(Criteria criteria, Part part, Object value) {
|
||||
|
||||
return criteria.regex(toLikeRegex(value, part), toRegexOptions(part));
|
||||
if (value == null) {
|
||||
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Argument for creating $regex pattern for property '%s' must not be null!", part.getProperty().getSegment()));
|
||||
}
|
||||
|
||||
return criteria.regex(toLikeRegex(value.toString(), part), toRegexOptions(part));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,8 +375,10 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T nextAs(Iterator<Object> iterator, Class<T> type) {
|
||||
|
||||
Object parameter = iterator.next();
|
||||
if (parameter.getClass().isAssignableFrom(type)) {
|
||||
|
||||
if (ClassUtils.isAssignable(type, parameter.getClass())) {
|
||||
return (T) parameter;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.util.JSON;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
@@ -110,7 +112,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
try {
|
||||
|
||||
BasicQuery result = new BasicQuery(query.getQueryObject().toString(), fieldSpec);
|
||||
BasicQuery result = new BasicQuery(query.getQueryObject(), (DBObject) JSON.parse(fieldSpec));
|
||||
result.setSortObject(query.getSortObject());
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -38,10 +38,11 @@ import com.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
* Query to use a plain JSON String to create the {@link Query} to actually execute.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
@@ -59,7 +60,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
/**
|
||||
* Creates a new {@link StringBasedMongoQuery} for the given {@link MongoQueryMethod} and {@link MongoOperations}.
|
||||
*
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param mongoOperations must not be {@literal null}.
|
||||
* @param expressionParser must not be {@literal null}.
|
||||
@@ -112,10 +113,10 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
@Override
|
||||
protected Query createQuery(ConvertingParameterAccessor accessor) {
|
||||
|
||||
String queryString = parameterBinder.bind(this.query, accessor, new BindingContext(getQueryMethod()
|
||||
.getParameters(), queryParameterBindings));
|
||||
String fieldsString = parameterBinder.bind(this.fieldSpec, accessor, new BindingContext(getQueryMethod()
|
||||
.getParameters(), fieldSpecParameterBindings));
|
||||
String queryString = parameterBinder.bind(this.query, accessor,
|
||||
new BindingContext(getQueryMethod().getParameters(), queryParameterBindings));
|
||||
String fieldsString = parameterBinder.bind(this.fieldSpec, accessor,
|
||||
new BindingContext(getQueryMethod().getParameters(), fieldSpecParameterBindings));
|
||||
|
||||
Query query = new BasicQuery(queryString, fieldsString).with(accessor.getSort());
|
||||
|
||||
@@ -126,7 +127,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
return query;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isCountQuery()
|
||||
*/
|
||||
@@ -146,10 +147,10 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
/**
|
||||
* A parser that extracts the parameter bindings from a given query string.
|
||||
*
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
private static enum ParameterBindingParser {
|
||||
private enum ParameterBindingParser {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -169,7 +170,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
/**
|
||||
* Returns a list of {@link ParameterBinding}s found in the given {@code input} or an
|
||||
* {@link Collections#emptyList()}.
|
||||
*
|
||||
*
|
||||
* @param input can be {@literal null} or empty.
|
||||
* @param bindings must not be {@literal null}.
|
||||
* @return
|
||||
@@ -256,7 +257,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
} else if (value instanceof Pattern) {
|
||||
|
||||
String string = ((Pattern) value).toString().trim();
|
||||
String string = value.toString().trim();
|
||||
Matcher valueMatcher = PARSEABLE_BINDING_PATTERN.matcher(string);
|
||||
|
||||
while (valueMatcher.find()) {
|
||||
@@ -264,7 +265,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
int paramIndex = Integer.parseInt(valueMatcher.group(PARAMETER_INDEX_GROUP));
|
||||
|
||||
/*
|
||||
* The pattern is used as a direct parameter replacement, e.g. 'field': ?1,
|
||||
* The pattern is used as a direct parameter replacement, e.g. 'field': ?1,
|
||||
* therefore we treat it as not quoted to remain backwards compatible.
|
||||
*/
|
||||
boolean quoted = !string.equals(PARAMETER_PREFIX + paramIndex);
|
||||
@@ -297,8 +298,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
while (valueMatcher.find()) {
|
||||
|
||||
int paramIndex = Integer.parseInt(valueMatcher.group(PARAMETER_INDEX_GROUP));
|
||||
boolean quoted = (source.startsWith("'") && source.endsWith("'"))
|
||||
|| (source.startsWith("\"") && source.endsWith("\""));
|
||||
boolean quoted = source.startsWith("'") || source.startsWith("\"");
|
||||
|
||||
bindings.add(new ParameterBinding(paramIndex, quoted));
|
||||
}
|
||||
@@ -315,7 +315,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
/**
|
||||
* A generic parameter binding with name or position information.
|
||||
*
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
static class ParameterBinding {
|
||||
@@ -326,7 +326,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ParameterBinding} with the given {@code parameterIndex} and {@code quoted} information.
|
||||
*
|
||||
*
|
||||
* @param parameterIndex
|
||||
* @param quoted whether or not the parameter is already quoted.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -53,7 +53,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
|
||||
*/
|
||||
public IndexEnsuringQueryCreationListener(MongoOperations operations) {
|
||||
|
||||
Assert.notNull(operations);
|
||||
Assert.notNull(operations, "MongoOperations must not be null!");
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2017 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.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Support class responsible for creating {@link MongoEntityInformation} instances for a given
|
||||
* {@link MongoPersistentEntity}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
final class MongoEntityInformationSupport {
|
||||
|
||||
private MongoEntityInformationSupport() {}
|
||||
|
||||
/**
|
||||
* Factory method for creating {@link MongoEntityInformation}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param idType can be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T, ID extends Serializable> MongoEntityInformation<T, ID> entityInformationFor(
|
||||
MongoPersistentEntity<?> entity, Class<?> idType) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null!");
|
||||
|
||||
MappingMongoEntityInformation<T, ID> entityInformation = new MappingMongoEntityInformation<T, ID>(
|
||||
(MongoPersistentEntity<T>) entity, (Class<ID>) idType);
|
||||
|
||||
return ClassUtils.isAssignable(Persistable.class, entity.getType())
|
||||
? new PersistableMongoEntityInformation<T, ID>(entityInformation) : entityInformation;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
* Copyright 2010-2017 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.
|
||||
@@ -20,6 +20,7 @@ import static org.springframework.data.querydsl.QueryDslUtils.*;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Factory to create {@link MongoRepository} instances.
|
||||
@@ -49,6 +51,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MongoRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
@@ -64,7 +67,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
|
||||
*/
|
||||
public MongoRepositoryFactory(MongoOperations mongoOperations) {
|
||||
|
||||
Assert.notNull(mongoOperations);
|
||||
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
|
||||
|
||||
this.operations = mongoOperations;
|
||||
this.mappingContext = mongoOperations.getConverter().getMappingContext();
|
||||
@@ -95,7 +98,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
|
||||
return getTargetRepositoryViaReflection(information, entityInformation, operations);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider)
|
||||
*/
|
||||
@@ -123,8 +126,8 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
|
||||
String.format("Could not lookup mapping metadata for domain class %s!", domainClass.getName()));
|
||||
}
|
||||
|
||||
return new MappingMongoEntityInformation<T, ID>((MongoPersistentEntity<T>) entity,
|
||||
information != null ? (Class<ID>) information.getIdType() : null);
|
||||
return MongoEntityInformationSupport.<T, ID> entityInformationFor(entity,
|
||||
information != null ? information.getIdType() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +150,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2017 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.repository.support;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
|
||||
|
||||
/**
|
||||
* {@link MongoEntityInformation} implementation wrapping an existing {@link MongoEntityInformation} considering
|
||||
* {@link Persistable} types by delegating {@link #isNew(Object)} and {@link #getId(Object)} to the corresponding
|
||||
* {@link Persistable#isNew()} and {@link Persistable#getId()} implementations.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
class PersistableMongoEntityInformation<T, ID extends Serializable> implements MongoEntityInformation<T, ID> {
|
||||
|
||||
private final @NonNull MongoEntityInformation<T, ID> delegate;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.MongoEntityInformation#getCollectionName()
|
||||
*/
|
||||
@Override
|
||||
public String getCollectionName() {
|
||||
return delegate.getCollectionName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.MongoEntityInformation#getIdAttribute()
|
||||
*/
|
||||
@Override
|
||||
public String getIdAttribute() {
|
||||
return delegate.getIdAttribute();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.EntityInformation#isNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean isNew(T t) {
|
||||
|
||||
if (t instanceof Persistable) {
|
||||
return ((Persistable<ID>) t).isNew();
|
||||
}
|
||||
|
||||
return delegate.isNew(t);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ID getId(T t) {
|
||||
|
||||
if (t instanceof Persistable) {
|
||||
return (ID) ((Persistable<ID>) t).getId();
|
||||
}
|
||||
|
||||
return delegate.getId(t);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.PersistentEntityInformation#getIdType()
|
||||
*/
|
||||
@Override
|
||||
public Class<ID> getIdType() {
|
||||
return delegate.getIdType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.EntityMetadata#getJavaType()
|
||||
*/
|
||||
@Override
|
||||
public Class<T> getJavaType() {
|
||||
return delegate.getJavaType();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -78,7 +78,8 @@ public class QueryDslMongoRepository<T, ID extends Serializable> extends SimpleM
|
||||
|
||||
super(entityInformation, mongoOperations);
|
||||
|
||||
Assert.notNull(resolver);
|
||||
Assert.notNull(resolver, "EntityPathResolver must not be null!");
|
||||
|
||||
EntityPath<T> path = resolver.createPath(entityInformation.getJavaType());
|
||||
|
||||
this.builder = new PathBuilder<T>(path.getType(), path.getMetadata());
|
||||
@@ -122,7 +123,7 @@ public class QueryDslMongoRepository<T, ID extends Serializable> extends SimpleM
|
||||
return applySorting(createQueryFor(predicate), sort).fetchResults().getResults();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.OrderSpecifier[])
|
||||
*/
|
||||
@@ -177,7 +178,7 @@ public class QueryDslMongoRepository<T, ID extends Serializable> extends SimpleM
|
||||
return createQueryFor(predicate).fetchCount();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.mysema.query.types.Predicate)
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -27,6 +27,7 @@ import com.querydsl.mongodb.AbstractMongodbQuery;
|
||||
* Base class to create repository implementations based on Querydsl.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class QuerydslRepositorySupport {
|
||||
|
||||
@@ -40,7 +41,7 @@ public abstract class QuerydslRepositorySupport {
|
||||
*/
|
||||
public QuerydslRepositorySupport(MongoOperations operations) {
|
||||
|
||||
Assert.notNull(operations);
|
||||
Assert.notNull(operations, "MongoOperations must not be null!");
|
||||
|
||||
this.template = operations;
|
||||
this.context = operations.getConverter().getMappingContext();
|
||||
@@ -54,7 +55,9 @@ public abstract class QuerydslRepositorySupport {
|
||||
* @return
|
||||
*/
|
||||
protected <T> AbstractMongodbQuery<T, SpringDataMongodbQuery<T>> from(final EntityPath<T> path) {
|
||||
Assert.notNull(path);
|
||||
|
||||
Assert.notNull(path, "EntityPath must not be null!");
|
||||
|
||||
MongoPersistentEntity<?> entity = context.getPersistentEntity(path.getType());
|
||||
return from(path, entity.getCollection());
|
||||
}
|
||||
@@ -68,8 +71,8 @@ public abstract class QuerydslRepositorySupport {
|
||||
*/
|
||||
protected <T> AbstractMongodbQuery<T, SpringDataMongodbQuery<T>> from(final EntityPath<T> path, String collection) {
|
||||
|
||||
Assert.notNull(path);
|
||||
Assert.hasText(collection);
|
||||
Assert.notNull(path, "EntityPath must not be null!");
|
||||
Assert.hasText(collection, "Collection name must not be null or empty!");
|
||||
|
||||
return new SpringDataMongodbQuery<T>(template, path.getType(), collection);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 the original author or authors.
|
||||
* Copyright 2010-2017 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.
|
||||
@@ -59,8 +59,8 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
|
||||
*/
|
||||
public SimpleMongoRepository(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
|
||||
|
||||
Assert.notNull(mongoOperations);
|
||||
Assert.notNull(metadata);
|
||||
Assert.notNull(metadata, "MongoEntityInformation must not be null!");
|
||||
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
|
||||
|
||||
this.entityInformation = metadata;
|
||||
this.mongoOperations = mongoOperations;
|
||||
@@ -195,7 +195,7 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
|
||||
return findAll(new Query());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
|
||||
*/
|
||||
@@ -229,7 +229,7 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
|
||||
return findAll(new Query().with(sort));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.MongoRepository#insert(java.lang.Object)
|
||||
*/
|
||||
@@ -242,7 +242,7 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements MongoR
|
||||
return entity;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.MongoRepository#insert(java.lang.Iterable)
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -27,7 +27,7 @@ import com.querydsl.mongodb.AbstractMongodbQuery;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class SpringDataMongodbQuery<T> extends AbstractMongodbQuery<T, SpringDataMongodbQuery<T>> {
|
||||
public class SpringDataMongodbQuery<T> extends AbstractMongodbQuery<T, SpringDataMongodbQuery<T>> {
|
||||
|
||||
private final MongoOperations operations;
|
||||
|
||||
|
||||
@@ -26,9 +26,11 @@ 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.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
import com.querydsl.core.types.Constant;
|
||||
import com.querydsl.core.types.Path;
|
||||
import com.querydsl.core.types.PathMetadata;
|
||||
import com.querydsl.core.types.PathType;
|
||||
@@ -72,6 +74,20 @@ class SpringDataMongodbSerializer extends MongodbSerializer {
|
||||
this.mapper = new QueryMapper(converter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.querydsl.mongodb.MongodbSerializer#visit(com.querydsl.core.types.Constant, java.lang.Void)
|
||||
*/
|
||||
@Override
|
||||
public Object visit(Constant<?> expr, Void context) {
|
||||
|
||||
if (!ClassUtils.isAssignable(Enum.class, expr.getType())) {
|
||||
return super.visit(expr, context);
|
||||
}
|
||||
|
||||
return converter.convertToMongoType(expr.getConstant());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.querydsl.mongodb.MongodbSerializer#getKeyForPath(com.querydsl.core.types.Path, com.querydsl.core.types.PathMetadata)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -28,16 +28,28 @@ public class MongoClientVersion {
|
||||
|
||||
private static final boolean IS_MONGO_30 = ClassUtils.isPresent("com.mongodb.binding.SingleServerBinding",
|
||||
MongoClientVersion.class.getClassLoader());
|
||||
|
||||
private static final boolean IS_MONGO_34 = ClassUtils.isPresent("org.bson.types.Decimal128",
|
||||
MongoClientVersion.class.getClassLoader());
|
||||
|
||||
private static final boolean IS_ASYNC_CLIENT = ClassUtils.isPresent("com.mongodb.async.client.MongoClient",
|
||||
MongoClientVersion.class.getClassLoader());
|
||||
|
||||
/**
|
||||
* @return |literal true} if MongoDB Java driver version 3.0 or later is on classpath.
|
||||
* @return {@literal true} if MongoDB Java driver version 3.0 or later is on classpath.
|
||||
*/
|
||||
public static boolean isMongo3Driver() {
|
||||
return IS_MONGO_30;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if MongoDB Java driver version 3.4 or later is on classpath.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static boolean isMongo34Driver() {
|
||||
return IS_MONGO_34;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {lliteral true} if MongoDB Java driver is on classpath.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 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.
|
||||
@@ -19,8 +19,6 @@ import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -30,8 +28,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.mongodb.core.AuditablePerson;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
import org.springframework.stereotype.Repository;
|
||||
@@ -123,22 +119,20 @@ public class AuditingViaJavaConfigRepositoriesTests {
|
||||
|
||||
@Configuration
|
||||
@EnableMongoRepositories
|
||||
@EnableMongoAuditing
|
||||
static class SimpleConfigWithRepositories {
|
||||
|
||||
@Bean
|
||||
public MongoTemplate mongoTemplate() throws UnknownHostException {
|
||||
return new MongoTemplate(new SimpleMongoDbFactory(new MongoClient(), "database"));
|
||||
}
|
||||
}
|
||||
static class SimpleConfigWithRepositories extends SimpleConfig {}
|
||||
|
||||
@Configuration
|
||||
@EnableMongoAuditing
|
||||
static class SimpleConfig {
|
||||
static class SimpleConfig extends AbstractMongoConfiguration {
|
||||
|
||||
@Bean
|
||||
public MongoTemplate mongoTemplate() throws UnknownHostException {
|
||||
return new MongoTemplate(new SimpleMongoDbFactory(new MongoClient(), "database"));
|
||||
@Override
|
||||
public Mongo mongo() throws Exception {
|
||||
return new MongoClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDatabaseName() {
|
||||
return "database";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
* Copyright 2011-2016 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.
|
||||
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Ignore;
|
||||
@@ -37,6 +38,13 @@ import com.mongodb.CommandResult;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.ServerAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class MongoNamespaceReplicaSetTests {
|
||||
@@ -70,10 +78,13 @@ public class MongoNamespaceReplicaSetTests {
|
||||
|
||||
assertThat(replicaSetSeeds, is(notNullValue()));
|
||||
assertThat(replicaSetSeeds, hasSize(3));
|
||||
assertThat(
|
||||
replicaSetSeeds,
|
||||
hasItems(new ServerAddress("192.168.174.130", 27017), new ServerAddress("192.168.174.130", 27018),
|
||||
new ServerAddress("192.168.174.130", 27019)));
|
||||
|
||||
List<Integer> ports = new ArrayList<Integer>();
|
||||
for (ServerAddress replicaSetSeed : replicaSetSeeds) {
|
||||
ports.add(replicaSetSeed.getPort());
|
||||
}
|
||||
|
||||
assertThat(ports, hasItems(27017, 27018, 27019));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.mongodb.WriteConcern;
|
||||
*
|
||||
* @author Tobias Trelle
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
@@ -270,6 +271,25 @@ public class DefaultBulkOperationsIntegrationTests {
|
||||
assertThat(result.getRemovedCount(), is(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1534
|
||||
*/
|
||||
@Test
|
||||
public void insertShouldConsiderInheritance() {
|
||||
|
||||
SpecialDoc specialDoc = new SpecialDoc();
|
||||
specialDoc.id = "id-special";
|
||||
specialDoc.value = "normal-value";
|
||||
specialDoc.specialValue = "special-value";
|
||||
|
||||
createBulkOps(BulkMode.ORDERED).insert(Arrays.asList(specialDoc)).execute();
|
||||
|
||||
BaseDoc doc = operations.findOne(where("_id", specialDoc.id), BaseDoc.class, COLLECTION_NAME);
|
||||
|
||||
assertThat(doc, notNullValue());
|
||||
assertThat(doc, instanceOf(SpecialDoc.class));
|
||||
}
|
||||
|
||||
private void testUpdate(BulkMode mode, boolean multi, int expectedUpdates) {
|
||||
|
||||
BulkOperations bulkOps = createBulkOps(mode);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -17,18 +17,28 @@ package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.data.mongodb.core.ReflectiveDBCollectionInvoker.*;
|
||||
import static org.springframework.data.mongodb.core.index.PartialIndexFilter.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.core.index.Index;
|
||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.CommandResult;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
@@ -42,6 +52,9 @@ import com.mongodb.DBObject;
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
public class DefaultIndexOperationsIntegrationTests {
|
||||
|
||||
private static final Version THREE_DOT_TWO = new Version(3, 2);
|
||||
private static Version mongoVersion;
|
||||
|
||||
static final DBObject GEO_SPHERE_2D = new BasicDBObject("loaction", "2dsphere");
|
||||
|
||||
@Autowired MongoTemplate template;
|
||||
@@ -51,6 +64,7 @@ public class DefaultIndexOperationsIntegrationTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
queryMongoVersionIfNecessary();
|
||||
String collectionName = this.template.getCollectionName(DefaultIndexOperationsIntegrationTestsSample.class);
|
||||
|
||||
this.collection = this.template.getDb().getCollection(collectionName);
|
||||
@@ -59,6 +73,14 @@ public class DefaultIndexOperationsIntegrationTests {
|
||||
this.indexOps = new DefaultIndexOperations(template, collectionName);
|
||||
}
|
||||
|
||||
private void queryMongoVersionIfNecessary() {
|
||||
|
||||
if (mongoVersion == null) {
|
||||
CommandResult result = template.executeCommand("{ buildInfo: 1 }");
|
||||
mongoVersion = Version.parse(result.get("version").toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1008
|
||||
*/
|
||||
@@ -71,6 +93,78 @@ public class DefaultIndexOperationsIntegrationTests {
|
||||
assertThat(info.getIndexFields().get(0).isGeo(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1467
|
||||
*/
|
||||
@Test
|
||||
public void shouldApplyPartialFilterCorrectly() {
|
||||
|
||||
assumeThat(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_TWO), is(true));
|
||||
|
||||
IndexDefinition id = new Index().named("partial-with-criteria").on("k3y", Direction.ASC)
|
||||
.partial(of(where("q-t-y").gte(10)));
|
||||
|
||||
indexOps.ensureIndex(id);
|
||||
|
||||
IndexInfo info = findAndReturnIndexInfo(indexOps.getIndexInfo(), "partial-with-criteria");
|
||||
assertThat(info.getPartialFilterExpression(), is(equalTo("{ \"q-t-y\" : { \"$gte\" : 10}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1467
|
||||
*/
|
||||
@Test
|
||||
public void shouldApplyPartialFilterWithMappedPropertyCorrectly() {
|
||||
|
||||
assumeThat(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_TWO), is(true));
|
||||
|
||||
IndexDefinition id = new Index().named("partial-with-mapped-criteria").on("k3y", Direction.ASC)
|
||||
.partial(of(where("quantity").gte(10)));
|
||||
|
||||
indexOps.ensureIndex(id);
|
||||
|
||||
IndexInfo info = findAndReturnIndexInfo(indexOps.getIndexInfo(), "partial-with-mapped-criteria");
|
||||
assertThat(info.getPartialFilterExpression(), is(equalTo("{ \"qty\" : { \"$gte\" : 10}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1467
|
||||
*/
|
||||
@Test
|
||||
public void shouldApplyPartialDBOFilterCorrectly() {
|
||||
|
||||
assumeThat(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_TWO), is(true));
|
||||
|
||||
IndexDefinition id = new Index().named("partial-with-dbo").on("k3y", Direction.ASC)
|
||||
.partial(of(new BasicDBObject("qty", new BasicDBObject("$gte", 10))));
|
||||
|
||||
indexOps.ensureIndex(id);
|
||||
|
||||
IndexInfo info = findAndReturnIndexInfo(indexOps.getIndexInfo(), "partial-with-dbo");
|
||||
assertThat(info.getPartialFilterExpression(), is(equalTo("{ \"qty\" : { \"$gte\" : 10}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1467
|
||||
*/
|
||||
@Test
|
||||
public void shouldFavorExplicitMappingHintViaClass() {
|
||||
|
||||
assumeThat(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_TWO), is(true));
|
||||
|
||||
IndexDefinition id = new Index().named("partial-with-inheritance").on("k3y", Direction.ASC)
|
||||
.partial(of(where("age").gte(10)));
|
||||
|
||||
indexOps = new DefaultIndexOperations(template,
|
||||
this.template.getCollectionName(DefaultIndexOperationsIntegrationTestsSample.class),
|
||||
MappingToSameCollection.class);
|
||||
|
||||
indexOps.ensureIndex(id);
|
||||
|
||||
IndexInfo info = findAndReturnIndexInfo(indexOps.getIndexInfo(), "partial-with-inheritance");
|
||||
assertThat(info.getPartialFilterExpression(), is(equalTo("{ \"a_g_e\" : { \"$gte\" : 10}}")));
|
||||
}
|
||||
|
||||
private IndexInfo findAndReturnIndexInfo(DBObject keys) {
|
||||
return findAndReturnIndexInfo(indexOps.getIndexInfo(), keys);
|
||||
}
|
||||
@@ -89,5 +183,15 @@ public class DefaultIndexOperationsIntegrationTests {
|
||||
throw new AssertionError(String.format("Index with %s was not found", name));
|
||||
}
|
||||
|
||||
static class DefaultIndexOperationsIntegrationTestsSample {}
|
||||
@Document(collection = "default-index-operations-tests")
|
||||
static class DefaultIndexOperationsIntegrationTestsSample {
|
||||
|
||||
@Field("qty") Integer quantity;
|
||||
}
|
||||
|
||||
@Document(collection = "default-index-operations-tests")
|
||||
static class MappingToSameCollection extends DefaultIndexOperationsIntegrationTestsSample {
|
||||
|
||||
@Field("a_g_e") Integer age;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -190,4 +190,12 @@ public class DefaultScriptOperationsTests {
|
||||
public void scriptNamesShouldReturnEmptySetWhenNoScriptRegistered() {
|
||||
assertThat(scriptOps.getScriptNames(), is(empty()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1465
|
||||
*/
|
||||
@Test
|
||||
public void executeShouldNotQuoteStrings() {
|
||||
assertThat(scriptOps.execute(EXECUTABLE_SCRIPT, "spring-data"), is((Object) "spring-data"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -24,6 +24,10 @@ import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
import static org.springframework.data.mongodb.core.query.Update.*;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -33,6 +37,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -43,6 +48,7 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
@@ -70,13 +76,19 @@ import org.springframework.data.mongodb.core.index.IndexField;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
|
||||
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
|
||||
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -102,6 +114,7 @@ import com.mongodb.WriteResult;
|
||||
* @author Thomas Darimont
|
||||
* @author Komi Innocent
|
||||
* @author Christoph Strobl
|
||||
* @author Laszlo Csontos
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
@@ -111,27 +124,39 @@ public class MongoTemplateTests {
|
||||
.parse("2.4");
|
||||
private static final org.springframework.data.util.Version TWO_DOT_EIGHT = org.springframework.data.util.Version
|
||||
.parse("2.8");
|
||||
private static final org.springframework.data.util.Version THREE_DOT_FOUR = org.springframework.data.util.Version
|
||||
.parse("3.4");
|
||||
|
||||
@Autowired MongoTemplate template;
|
||||
@Autowired MongoDbFactory factory;
|
||||
|
||||
ConfigurableApplicationContext context;
|
||||
MongoTemplate mappingTemplate;
|
||||
org.springframework.data.util.Version mongoVersion;
|
||||
|
||||
@Rule public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Autowired
|
||||
public void setApplicationContext(ConfigurableApplicationContext context) {
|
||||
|
||||
this.context = context;
|
||||
|
||||
context.addApplicationListener(new PersonWithIdPropertyOfTypeUUIDListener());
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setMongo(Mongo mongo) throws Exception {
|
||||
|
||||
CustomConversions conversions = new CustomConversions(Arrays.asList(DateToDateTimeConverter.INSTANCE,
|
||||
DateTimeToDateConverter.INSTANCE));
|
||||
CustomConversions conversions = new CustomConversions(
|
||||
Arrays.asList(DateToDateTimeConverter.INSTANCE, DateTimeToDateConverter.INSTANCE));
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
mappingContext.setInitialEntitySet(new HashSet<Class<?>>(Arrays.asList(PersonWith_idPropertyOfTypeObjectId.class,
|
||||
PersonWith_idPropertyOfTypeString.class, PersonWithIdPropertyOfTypeObjectId.class,
|
||||
PersonWithIdPropertyOfTypeString.class, PersonWithIdPropertyOfTypeInteger.class,
|
||||
PersonWithIdPropertyOfTypeBigInteger.class, PersonWithIdPropertyOfPrimitiveInt.class,
|
||||
PersonWithIdPropertyOfTypeLong.class, PersonWithIdPropertyOfPrimitiveLong.class)));
|
||||
mappingContext.setInitialEntitySet(new HashSet<Class<?>>(
|
||||
Arrays.asList(PersonWith_idPropertyOfTypeObjectId.class, PersonWith_idPropertyOfTypeString.class,
|
||||
PersonWithIdPropertyOfTypeObjectId.class, PersonWithIdPropertyOfTypeString.class,
|
||||
PersonWithIdPropertyOfTypeInteger.class, PersonWithIdPropertyOfTypeBigInteger.class,
|
||||
PersonWithIdPropertyOfPrimitiveInt.class, PersonWithIdPropertyOfTypeLong.class,
|
||||
PersonWithIdPropertyOfPrimitiveLong.class, PersonWithIdPropertyOfTypeUUID.class)));
|
||||
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
|
||||
mappingContext.initialize();
|
||||
|
||||
@@ -145,8 +170,11 @@ public class MongoTemplateTests {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
cleanDb();
|
||||
queryMongoVersionIfNecessary();
|
||||
|
||||
this.mappingTemplate.setApplicationContext(context);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -174,6 +202,7 @@ public class MongoTemplateTests {
|
||||
template.dropCollection(PersonWithIdPropertyOfPrimitiveInt.class);
|
||||
template.dropCollection(PersonWithIdPropertyOfTypeLong.class);
|
||||
template.dropCollection(PersonWithIdPropertyOfPrimitiveLong.class);
|
||||
template.dropCollection(PersonWithIdPropertyOfTypeUUID.class);
|
||||
template.dropCollection(PersonWithVersionPropertyOfTypeInteger.class);
|
||||
template.dropCollection(TestClass.class);
|
||||
template.dropCollection(Sample.class);
|
||||
@@ -629,6 +658,22 @@ public class MongoTemplateTests {
|
||||
assertThat(p12q, notNullValue());
|
||||
assertThat(p12q.getId(), is(p12.getId()));
|
||||
checkCollectionContents(PersonWithIdPropertyOfPrimitiveLong.class, 1);
|
||||
|
||||
// DATAMONGO-1617
|
||||
// UUID id - provided
|
||||
PersonWithIdPropertyOfTypeUUID p13 = new PersonWithIdPropertyOfTypeUUID();
|
||||
p13.setFirstName("Sven_10");
|
||||
p13.setAge(22);
|
||||
// insert
|
||||
mongoTemplate.insert(p13);
|
||||
// also try save
|
||||
mongoTemplate.save(p13);
|
||||
assertThat(p13.getId(), notNullValue());
|
||||
PersonWithIdPropertyOfTypeUUID p13q = mongoTemplate.findOne(new Query(where("id").in(p13.getId())),
|
||||
PersonWithIdPropertyOfTypeUUID.class);
|
||||
assertThat(p13q, notNullValue());
|
||||
assertThat(p13q.getId(), is(p13.getId()));
|
||||
checkCollectionContents(PersonWithIdPropertyOfTypeUUID.class, 1);
|
||||
}
|
||||
|
||||
private void checkCollectionContents(Class<?> entityClass, int count) {
|
||||
@@ -1483,6 +1528,17 @@ public class MongoTemplateTests {
|
||||
template.insert(dbObject, template.determineCollectionName(PersonWithVersionPropertyOfTypeInteger.class));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1617
|
||||
public void doesNotFailOnInsertForEntityWithNonAutogeneratableId() {
|
||||
|
||||
PersonWithIdPropertyOfTypeUUID person = new PersonWithIdPropertyOfTypeUUID();
|
||||
person.setFirstName("Laszlo");
|
||||
person.setAge(33);
|
||||
|
||||
template.insert(person);
|
||||
assertThat(person.getId(), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-539
|
||||
*/
|
||||
@@ -2571,7 +2627,7 @@ public class MongoTemplateTests {
|
||||
doc.dbRefAnnotatedList = Arrays.asList( //
|
||||
sample1, //
|
||||
sample2 //
|
||||
);
|
||||
);
|
||||
template.save(doc);
|
||||
|
||||
Update update = new Update().pull("dbRefAnnotatedList", doc.dbRefAnnotatedList.get(1));
|
||||
@@ -2603,7 +2659,7 @@ public class MongoTemplateTests {
|
||||
doc.dbRefAnnotatedList = Arrays.asList( //
|
||||
sample1, //
|
||||
sample2 //
|
||||
);
|
||||
);
|
||||
template.save(doc);
|
||||
|
||||
Update update = new Update().pull("dbRefAnnotatedList.id", "2");
|
||||
@@ -2677,8 +2733,8 @@ public class MongoTemplateTests {
|
||||
@Test
|
||||
public void testUpdateShouldWorkForPathsOnInterfaceMethods() {
|
||||
|
||||
DocumentWithCollection document = new DocumentWithCollection(Arrays.<Model> asList(new ModelA("spring"),
|
||||
new ModelA("data")));
|
||||
DocumentWithCollection document = new DocumentWithCollection(
|
||||
Arrays.<Model> asList(new ModelA("spring"), new ModelA("data")));
|
||||
|
||||
template.save(document);
|
||||
|
||||
@@ -3164,6 +3220,62 @@ public class MongoTemplateTests {
|
||||
assertThat(template.findOne(query(where("id").is(wgj.id)), WithGeoJson.class).point, is(equalTo(wgj.point)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1513
|
||||
*/
|
||||
@Test
|
||||
@DirtiesContext
|
||||
public void populatesIdsAddedByEventListener() {
|
||||
|
||||
context.addApplicationListener(new AbstractMongoEventListener<Document>() {
|
||||
|
||||
@Override
|
||||
public void onBeforeSave(BeforeSaveEvent<Document> event) {
|
||||
event.getDBObject().put("_id", UUID.randomUUID().toString());
|
||||
}
|
||||
});
|
||||
|
||||
Document document = new Document();
|
||||
|
||||
template.insertAll(Arrays.asList(document));
|
||||
|
||||
assertThat(document.id, is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1517
|
||||
*/
|
||||
@Test
|
||||
public void decimal128TypeShouldBeSavedAndLoadedCorrectly()
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
|
||||
assumeThat(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_FOUR), is(true));
|
||||
assumeThat(MongoClientVersion.isMongo34Driver(), is(true));
|
||||
|
||||
Class<?> decimal128Type = ClassUtils.resolveClassName("org.bson.types.Decimal128", null);
|
||||
|
||||
WithObjectTypeProperty source = new WithObjectTypeProperty();
|
||||
source.id = "decimal128-property-value";
|
||||
source.value = decimal128Type.getConstructor(BigDecimal.class).newInstance(new BigDecimal(100));
|
||||
|
||||
template.save(source);
|
||||
|
||||
WithObjectTypeProperty loaded = template.findOne(query(where("id").is(source.id)), WithObjectTypeProperty.class);
|
||||
assertThat(loaded.getValue(), instanceOf(decimal128Type));
|
||||
}
|
||||
|
||||
static class TypeWithNumbers {
|
||||
|
||||
@Id String id;
|
||||
Integer intVal;
|
||||
Float floatVal;
|
||||
Long longVal;
|
||||
Double doubleVal;
|
||||
BigDecimal bigDeciamVal;
|
||||
BigInteger bigIntegerVal;
|
||||
Byte byteVal;
|
||||
}
|
||||
|
||||
static class DoucmentWithNamedIdField {
|
||||
|
||||
@Id String someIdKey;
|
||||
@@ -3215,11 +3327,11 @@ public class MongoTemplateTests {
|
||||
|
||||
@Id public String id;
|
||||
|
||||
@Field("db_ref_list")/** @see DATAMONGO-1058 */
|
||||
@org.springframework.data.mongodb.core.mapping.DBRef//
|
||||
@Field("db_ref_list") /** @see DATAMONGO-1058 */
|
||||
@org.springframework.data.mongodb.core.mapping.DBRef //
|
||||
public List<Sample> dbRefAnnotatedList;
|
||||
|
||||
@org.springframework.data.mongodb.core.mapping.DBRef//
|
||||
@org.springframework.data.mongodb.core.mapping.DBRef //
|
||||
public Sample dbRefProperty;
|
||||
}
|
||||
|
||||
@@ -3514,4 +3626,26 @@ public class MongoTemplateTests {
|
||||
GeoJsonPoint point;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class WithObjectTypeProperty {
|
||||
|
||||
@Id String id;
|
||||
Object value;
|
||||
}
|
||||
|
||||
static class PersonWithIdPropertyOfTypeUUIDListener
|
||||
extends AbstractMongoEventListener<PersonWithIdPropertyOfTypeUUID> {
|
||||
|
||||
@Override
|
||||
public void onBeforeConvert(BeforeConvertEvent<PersonWithIdPropertyOfTypeUUID> event) {
|
||||
|
||||
PersonWithIdPropertyOfTypeUUID person = event.getSource();
|
||||
|
||||
if (person.getId() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
person.setId(UUID.randomUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2017 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;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
public class PersonWithIdPropertyOfTypeUUID {
|
||||
|
||||
private UUID id;
|
||||
private String firstName;
|
||||
private int age;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.data.domain.Sort.Direction;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Aggregation}.
|
||||
@@ -204,6 +206,47 @@ public class AggregationUnitTests {
|
||||
assertThat(id.get("ruleType"), is((Object) "$rules.ruleType"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1585
|
||||
*/
|
||||
@Test
|
||||
public void shouldSupportSortingBySyntheticAndExposedGroupFields() {
|
||||
|
||||
DBObject agg = newAggregation( //
|
||||
group("cmsParameterId").addToSet("title").as("titles"), //
|
||||
sort(Direction.ASC, "cmsParameterId", "titles") //
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(agg, is(notNullValue()));
|
||||
|
||||
DBObject sort = ((List<DBObject>) agg.get("pipeline")).get(1);
|
||||
|
||||
assertThat(getAsDBObject(sort, "$sort"), is(JSON.parse("{ \"_id.cmsParameterId\" : 1 , \"titles\" : 1}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1585
|
||||
*/
|
||||
@Test
|
||||
public void shouldSupportSortingByProjectedFields() {
|
||||
|
||||
DBObject agg = newAggregation( //
|
||||
project("cmsParameterId") //
|
||||
.and(SystemVariable.CURRENT + ".titles").as("titles") //
|
||||
.and("field").as("alias"), //
|
||||
sort(Direction.ASC, "cmsParameterId", "titles", "alias") //
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(agg, is(notNullValue()));
|
||||
|
||||
DBObject sort = ((List<DBObject>) agg.get("pipeline")).get(1);
|
||||
|
||||
assertThat(getAsDBObject(sort, "$sort"),
|
||||
isBsonObject().containing("cmsParameterId", 1) //
|
||||
.containing("titles", 1) //
|
||||
.containing("alias", 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-924
|
||||
*/
|
||||
@@ -248,19 +291,20 @@ public class AggregationUnitTests {
|
||||
DBObject agg = newAggregation( //
|
||||
project().and("a").as("aa") //
|
||||
) //
|
||||
.withOptions(aggregationOptions) //
|
||||
.withOptions(aggregationOptions) //
|
||||
.toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(agg.toString(), is("{ \"aggregate\" : \"foo\" , " //
|
||||
+ "\"pipeline\" : [ { \"$project\" : { \"aa\" : \"$a\"}}] , " //
|
||||
+ "\"allowDiskUse\" : true , " //
|
||||
+ "\"explain\" : true , " //
|
||||
+ "\"cursor\" : { \"foo\" : 1}}" //
|
||||
));
|
||||
assertThat(agg.toString(),
|
||||
is("{ \"aggregate\" : \"foo\" , " //
|
||||
+ "\"pipeline\" : [ { \"$project\" : { \"aa\" : \"$a\"}}] , " //
|
||||
+ "\"allowDiskUse\" : true , " //
|
||||
+ "\"explain\" : true , " //
|
||||
+ "\"cursor\" : { \"foo\" : 1}}" //
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-954
|
||||
* @see DATAMONGO-954, DATAMONGO-1585
|
||||
*/
|
||||
@Test
|
||||
public void shouldSupportReferencingSystemVariables() {
|
||||
@@ -269,16 +313,16 @@ public class AggregationUnitTests {
|
||||
project("someKey") //
|
||||
.and("a").as("a1") //
|
||||
.and(Aggregation.CURRENT + ".a").as("a2") //
|
||||
, sort(Direction.DESC, "a") //
|
||||
, sort(Direction.DESC, "a1") //
|
||||
, group("someKey").first(Aggregation.ROOT).as("doc") //
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
DBObject projection0 = extractPipelineElement(agg, 0, "$project");
|
||||
assertThat(projection0, is((DBObject) new BasicDBObject("someKey", 1).append("a1", "$a")
|
||||
.append("a2", "$$CURRENT.a")));
|
||||
assertThat(projection0,
|
||||
is((DBObject) new BasicDBObject("someKey", 1).append("a1", "$a").append("a2", "$$CURRENT.a")));
|
||||
|
||||
DBObject sort = extractPipelineElement(agg, 1, "$sort");
|
||||
assertThat(sort, is((DBObject) new BasicDBObject("a", -1)));
|
||||
assertThat(sort, is((DBObject) new BasicDBObject("a1", -1)));
|
||||
|
||||
DBObject group = extractPipelineElement(agg, 2, "$group");
|
||||
assertThat(group,
|
||||
@@ -296,7 +340,7 @@ public class AggregationUnitTests {
|
||||
.and("tags").minus(10).as("tags_count")//
|
||||
, group("date")//
|
||||
.sum("tags_count").as("count")//
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
DBObject group = extractPipelineElement(agg, 1, "$group");
|
||||
assertThat(getAsDBObject(group, "count"), is(new BasicDBObjectBuilder().add("$sum", "$tags_count").get()));
|
||||
@@ -313,7 +357,7 @@ public class AggregationUnitTests {
|
||||
.andExpression("tags-10")//
|
||||
, group("date")//
|
||||
.sum("tags_count").as("count")//
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
DBObject group = extractPipelineElement(agg, 1, "$group");
|
||||
assertThat(getAsDBObject(group, "count"), is(new BasicDBObjectBuilder().add("$sum", "$tags_count").get()));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -46,11 +46,17 @@ public class ProjectionOperationUnitTests {
|
||||
static final String DIVIDE = "$divide";
|
||||
static final String PROJECT = "$project";
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullFields() {
|
||||
new ProjectionOperation(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void declaresBackReferenceCorrectly() {
|
||||
|
||||
@@ -62,6 +68,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(projectClause.get("prop"), is((Object) Fields.UNDERSCORE_ID_REF));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void alwaysUsesExplicitReference() {
|
||||
|
||||
@@ -74,6 +83,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(projectClause.get("bar"), is((Object) "$foobar"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void aliasesSimpleFieldProjection() {
|
||||
|
||||
@@ -85,6 +97,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(projectClause.get("bar"), is((Object) "$foo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void aliasesArithmeticProjection() {
|
||||
|
||||
@@ -100,6 +115,10 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(addClause.get(1), is((Object) 41));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void arithmenticProjectionOperationWithoutAlias() {
|
||||
|
||||
String fieldName = "a";
|
||||
@@ -112,6 +131,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(oper.get(ADD), is((Object) Arrays.<Object> asList("$a", 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void arithmenticProjectionOperationPlus() {
|
||||
|
||||
@@ -126,6 +148,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(oper.get(ADD), is((Object) Arrays.<Object> asList("$a", 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void arithmenticProjectionOperationMinus() {
|
||||
|
||||
@@ -140,6 +165,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(oper.get(SUBTRACT), is((Object) Arrays.<Object> asList("$a", 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void arithmenticProjectionOperationMultiply() {
|
||||
|
||||
@@ -154,6 +182,9 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(oper.get(MULTIPLY), is((Object) Arrays.<Object> asList("$a", 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void arithmenticProjectionOperationDivide() {
|
||||
|
||||
@@ -168,12 +199,18 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(oper.get(DIVIDE), is((Object) Arrays.<Object> asList("$a", 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void arithmenticProjectionOperationDivideByZeroException() {
|
||||
|
||||
new ProjectionOperation().and("a").divide(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-586
|
||||
*/
|
||||
@Test
|
||||
public void arithmenticProjectionOperationMod() {
|
||||
|
||||
@@ -273,9 +310,8 @@ public class ProjectionOperationUnitTests {
|
||||
.and("foo").as("bar"); //
|
||||
|
||||
DBObject dbObject = operation.toDBObject(Aggregation.DEFAULT_CONTEXT);
|
||||
assertThat(
|
||||
dbObject.toString(),
|
||||
is("{ \"$project\" : { \"grossSalesPrice\" : { \"$multiply\" : [ { \"$add\" : [ \"$netPrice\" , \"$surCharge\"]} , \"$taxrate\" , 2]} , \"bar\" : \"$foo\"}}"));
|
||||
assertThat(dbObject.toString(), is(
|
||||
"{ \"$project\" : { \"grossSalesPrice\" : { \"$multiply\" : [ { \"$add\" : [ \"$netPrice\" , \"$surCharge\"]} , \"$taxrate\" , 2]} , \"bar\" : \"$foo\"}}"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,10 +366,8 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(dbObject, is(notNullValue()));
|
||||
|
||||
DBObject projected = exctractOperation("$project", dbObject);
|
||||
assertThat(
|
||||
projected.get("dayOfYearPlus1Day"),
|
||||
is((Object) new BasicDBObject("$dayOfYear", Arrays.asList(new BasicDBObject("$add", Arrays.<Object> asList(
|
||||
"$date", 86400000))))));
|
||||
assertThat(projected.get("dayOfYearPlus1Day"), is((Object) new BasicDBObject("$dayOfYear",
|
||||
Arrays.asList(new BasicDBObject("$add", Arrays.<Object> asList("$date", 86400000))))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -17,7 +17,9 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -171,6 +173,44 @@ public class TypeBasedAggregationOperationContextUnitTests {
|
||||
assertThat(dbo.get("cursor"), is((Object) new BasicDBObject("foo", 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1585
|
||||
*/
|
||||
@Test
|
||||
public void rendersSortOfProjectedFieldCorrectly() {
|
||||
|
||||
TypeBasedAggregationOperationContext context = getContext(MeterData.class);
|
||||
TypedAggregation<MeterData> agg = newAggregation(MeterData.class, project().and("counterName").as("counter"), //
|
||||
sort(Direction.ASC, "counter"));
|
||||
|
||||
DBObject dbo = agg.toDbObject("meterData", context);
|
||||
DBObject sort = getPipelineElementFromAggregationAt(dbo, 1);
|
||||
|
||||
DBObject definition = (DBObject) sort.get("$sort");
|
||||
assertThat(definition.get("counter"), is(equalTo((Object) 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1586
|
||||
*/
|
||||
@Test
|
||||
public void rendersFieldAliasingProjectionCorrectly() {
|
||||
|
||||
AggregationOperationContext context = getContext(FooPerson.class);
|
||||
TypedAggregation<FooPerson> agg = newAggregation(FooPerson.class,
|
||||
project() //
|
||||
.and("name").as("person_name") //
|
||||
.and("age.value").as("age"));
|
||||
|
||||
DBObject dbo = agg.toDbObject("person", context);
|
||||
|
||||
DBObject projection = getPipelineElementFromAggregationAt(dbo, 0);
|
||||
assertThat(getAsDBObject(projection, "$project"),
|
||||
isBsonObject() //
|
||||
.containing("person_name", "$name") //
|
||||
.containing("age", "$age.value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1133
|
||||
*/
|
||||
@@ -190,14 +230,15 @@ public class TypeBasedAggregationOperationContextUnitTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1326
|
||||
* @see DATAMONGO-1326, DATAMONGO-1585
|
||||
*/
|
||||
@Test
|
||||
public void lookupShouldInheritFieldsFromInheritingAggregationOperation() {
|
||||
|
||||
TypeBasedAggregationOperationContext context = getContext(MeterData.class);
|
||||
TypedAggregation<MeterData> agg = newAggregation(MeterData.class,
|
||||
lookup("OtherCollection", "resourceId", "otherId", "lookup"), sort(Direction.ASC, "resourceId"));
|
||||
lookup("OtherCollection", "resourceId", "otherId", "lookup"), //
|
||||
sort(Direction.ASC, "resourceId", "counterName"));
|
||||
|
||||
DBObject dbo = agg.toDbObject("meterData", context);
|
||||
DBObject sort = getPipelineElementFromAggregationAt(dbo, 1);
|
||||
@@ -205,6 +246,7 @@ public class TypeBasedAggregationOperationContextUnitTests {
|
||||
DBObject definition = (DBObject) sort.get("$sort");
|
||||
|
||||
assertThat(definition.get("resourceId"), is(equalTo((Object) 1)));
|
||||
assertThat(definition.get("counter_name"), is(equalTo((Object) 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,6 +101,20 @@ public class DBObjectAccessorUnitTests {
|
||||
assertThat(nestedA.get("c"), is((Object) "c"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1471
|
||||
*/
|
||||
@Test
|
||||
public void exposesAvailabilityOfFields() {
|
||||
|
||||
DBObjectAccessor accessor = new DBObjectAccessor(new BasicDBObject("a", new BasicDBObject("c", "d")));
|
||||
MongoPersistentEntity<?> entity = context.getPersistentEntity(ProjectingType.class);
|
||||
|
||||
assertThat(accessor.hasValue(entity.getPersistentProperty("foo")), is(false));
|
||||
assertThat(accessor.hasValue(entity.getPersistentProperty("a")), is(true));
|
||||
assertThat(accessor.hasValue(entity.getPersistentProperty("name")), is(false));
|
||||
}
|
||||
|
||||
static class ProjectingType {
|
||||
|
||||
String name;
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.data.mongodb.core.convert.GeoConverters.SphereToDbObj
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
import org.springframework.data.mongodb.core.query.GeoCommand;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,7 @@ import com.mongodb.DBObject;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
public class GeoConvertersUnitTests {
|
||||
@@ -177,4 +179,32 @@ public class GeoConvertersUnitTests {
|
||||
assertThat(boxObject,
|
||||
is((Object) Arrays.asList(GeoConverters.toList(box.getFirst()), GeoConverters.toList(box.getSecond()))));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1607
|
||||
public void convertsPointCorrectlyWhenUsingNonDoubleForCoordinates() {
|
||||
|
||||
assertThat(DbObjectToPointConverter.INSTANCE.convert(new BasicDBObject().append("x", 1L).append("y", 2L)),
|
||||
is(new Point(1, 2)));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1607
|
||||
public void convertsCircleCorrectlyWhenUsingNonDoubleForCoordinates() {
|
||||
|
||||
DBObject circle = new BasicDBObject();
|
||||
circle.put("center", new BasicDBObject().append("x", 1).append("y", 2));
|
||||
circle.put("radius", 3L);
|
||||
|
||||
assertThat(DbObjectToCircleConverter.INSTANCE.convert(circle), is(new Circle(new Point(1, 2), new Distance(3))));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1607
|
||||
public void convertsSphereCorrectlyWhenUsingNonDoubleForCoordinates() {
|
||||
|
||||
DBObject sphere = new BasicDBObject();
|
||||
sphere.put("center", new BasicDBObject().append("x", 1).append("y", 2));
|
||||
sphere.put("radius", 3L);
|
||||
|
||||
assertThat(DbObjectToSphereConverter.INSTANCE.convert(sphere), is(new Sphere(new Point(1, 2), new Distance(3))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2016 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 static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.LazyLoadingException;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LazyLoadingInterceptor}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LazyLoadingInterceptorUnitTests {
|
||||
|
||||
public @Rule ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Mock MongoPersistentProperty propertyMock;
|
||||
@Mock DBRef dbrefMock;
|
||||
@Mock DbRefResolverCallback callbackMock;
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1437
|
||||
*/
|
||||
@Test
|
||||
public void shouldPreserveCauseForNonTranslatableExceptions() throws Throwable {
|
||||
|
||||
NullPointerException npe = new NullPointerException("Some Exception we did not think about.");
|
||||
when(callbackMock.resolve(propertyMock)).thenThrow(npe);
|
||||
|
||||
exception.expect(LazyLoadingException.class);
|
||||
exception.expectCause(is(equalTo(npe)));
|
||||
|
||||
new LazyLoadingInterceptor(propertyMock, dbrefMock, new NullExceptionTranslator(), callbackMock).intercept(null,
|
||||
LazyLoadingProxy.class.getMethod("getTarget"), null, null);
|
||||
}
|
||||
|
||||
static class NullExceptionTranslator implements PersistenceExceptionTranslator {
|
||||
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2066,6 +2066,37 @@ public class MappingMongoConverterUnitTests {
|
||||
assertThat(target.map.get(FooBarEnum.FOO), is("spring"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1471
|
||||
*/
|
||||
@Test
|
||||
public void readsDocumentWithPrimitiveIdButNoValue() {
|
||||
assertThat(converter.read(ClassWithIntId.class, new BasicDBObject()), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1497
|
||||
*/
|
||||
@Test
|
||||
public void readsPropertyFromNestedFieldCorrectly() {
|
||||
|
||||
DBObject source = new BasicDBObject("nested", new BasicDBObject("sample", "value"));
|
||||
TypeWithPropertyInNestedField result = converter.read(TypeWithPropertyInNestedField.class, source);
|
||||
|
||||
assertThat(result.sample, is("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1525
|
||||
*/
|
||||
@Test
|
||||
public void readsEmptyEnumSet() {
|
||||
|
||||
DBObject source = new BasicDBObject("enumSet", new BasicDBList());
|
||||
|
||||
assertThat(converter.read(ClassWithEnumProperty.class, source).enumSet, is(EnumSet.noneOf(SampleEnum.class)));
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
@@ -2412,4 +2443,8 @@ public class MappingMongoConverterUnitTests {
|
||||
throw new ConversionNotSupportedException(source, String.class, null);
|
||||
}
|
||||
}
|
||||
|
||||
static class TypeWithPropertyInNestedField {
|
||||
@Field("nested.sample") String sample;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Currency;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.geo.Box;
|
||||
@@ -27,8 +29,12 @@ import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.AtomicIntegerToIntegerConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.AtomicLongToLongConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.CurrencyToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.IntegerToAtomicIntegerConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.LongToAtomicLongConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToCurrencyConverter;
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
@@ -140,4 +146,36 @@ public class MongoConvertersUnitTests {
|
||||
public void convertsStringToCurrencyCorrectly() {
|
||||
assertThat(StringToCurrencyConverter.INSTANCE.convert("USD"), is(Currency.getInstance("USD")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1416
|
||||
*/
|
||||
@Test
|
||||
public void convertsAtomicLongToLongCorrectly() {
|
||||
assertThat(AtomicLongToLongConverter.INSTANCE.convert(new AtomicLong(100L)), is(100L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1416
|
||||
*/
|
||||
@Test
|
||||
public void convertsAtomicIntegerToIntegerCorrectly() {
|
||||
assertThat(AtomicIntegerToIntegerConverter.INSTANCE.convert(new AtomicInteger(100)), is(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1416
|
||||
*/
|
||||
@Test
|
||||
public void convertsLongToAtomicLongCorrectly() {
|
||||
assertThat(LongToAtomicLongConverter.INSTANCE.convert(100L), is(instanceOf(AtomicLong.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1416
|
||||
*/
|
||||
@Test
|
||||
public void convertsIntegerToAtomicIntegerCorrectly() {
|
||||
assertThat(IntegerToAtomicIntegerConverter.INSTANCE.convert(100), is(instanceOf(AtomicInteger.class)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2016 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.
|
||||
@@ -35,6 +35,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
@@ -54,6 +55,7 @@ import org.springframework.data.mongodb.core.mapping.TextScore;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.test.util.BasicDbListBuilder;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -68,6 +70,7 @@ import com.mongodb.QueryBuilder;
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class QueryMapperUnitTests {
|
||||
@@ -595,6 +598,28 @@ public class QueryMapperUnitTests {
|
||||
assertThat(dbo.toString(), equalTo("{ \"embedded\" : { \"$in\" : [ { \"_id\" : \"1\"} , { \"_id\" : \"2\"}]}}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1406
|
||||
*/
|
||||
@Test
|
||||
public void shouldMapQueryForNestedCustomizedPropertiesUsingConfiguredFieldNames() {
|
||||
|
||||
EmbeddedClass embeddedClass = new EmbeddedClass();
|
||||
embeddedClass.customizedField = "hello";
|
||||
|
||||
Foo foo = new Foo();
|
||||
foo.listOfItems = Arrays.asList(embeddedClass);
|
||||
|
||||
Query query = new Query(Criteria.where("listOfItems") //
|
||||
.elemMatch(new Criteria(). //
|
||||
andOperator(Criteria.where("customizedField").is(embeddedClass.customizedField))));
|
||||
|
||||
DBObject dbo = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(Foo.class));
|
||||
|
||||
assertThat(dbo, isBsonObject().containing("my_items.$elemMatch.$and",
|
||||
new BasicDbListBuilder().add(new BasicDBObject("fancy_custom_name", embeddedClass.customizedField)).get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-647
|
||||
*/
|
||||
@@ -792,8 +817,7 @@ public class QueryMapperUnitTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* <<<<<<< HEAD
|
||||
*
|
||||
*
|
||||
* @see DATAMONGO-1269
|
||||
*/
|
||||
@Test
|
||||
@@ -859,10 +883,15 @@ public class QueryMapperUnitTests {
|
||||
public class Foo {
|
||||
@Id private ObjectId id;
|
||||
EmbeddedClass embedded;
|
||||
|
||||
@Field("my_items")
|
||||
List<EmbeddedClass> listOfItems;
|
||||
}
|
||||
|
||||
public class EmbeddedClass {
|
||||
public String id;
|
||||
|
||||
@Field("fancy_custom_name") public String customizedField;
|
||||
}
|
||||
|
||||
class IdWrapper {
|
||||
|
||||
@@ -887,6 +887,50 @@ public class UpdateMapperUnitTests {
|
||||
assertThat($set.get("primIntValue"), Is.<Object> is(10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1423
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void mappingShouldConsiderCustomConvertersForEnumMapKeys() {
|
||||
|
||||
CustomConversions conversions = new CustomConversions(
|
||||
Arrays.asList(AllocationToStringConverter.INSTANCE, StringToAllocationConverter.INSTANCE));
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
MappingMongoConverter converter = new MappingMongoConverter(mock(DbRefResolver.class), mappingContext);
|
||||
converter.setCustomConversions(conversions);
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
UpdateMapper mapper = new UpdateMapper(converter);
|
||||
|
||||
Update update = new Update().set("enumAsMapKey", Collections.singletonMap(Allocation.AVAILABLE, 100));
|
||||
DBObject result = mapper.getMappedObject(update.getUpdateObject(),
|
||||
mappingContext.getPersistentEntity(ClassWithEnum.class));
|
||||
|
||||
assertThat(result, isBsonObject().containing("$set.enumAsMapKey.V", 100));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1486
|
||||
*/
|
||||
@Test
|
||||
public void mappingShouldConvertMapKeysToString() {
|
||||
|
||||
Update update = new Update().set("map", Collections.singletonMap(25, "#StarTrek50"));
|
||||
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(EntityWithObjectMap.class));
|
||||
|
||||
DBObject mapToSet = getAsDBObject(getAsDBObject(mappedUpdate, "$set"), "map");
|
||||
|
||||
for (Object key : mapToSet.keySet()) {
|
||||
assertThat(key, is(instanceOf(String.class)));
|
||||
}
|
||||
}
|
||||
|
||||
static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes {
|
||||
ListModelWrapper concreteTypeWithListAttributeOfInterfaceType;
|
||||
}
|
||||
@@ -1113,6 +1157,7 @@ public class UpdateMapperUnitTests {
|
||||
static class ClassWithEnum {
|
||||
|
||||
Allocation allocation;
|
||||
Map<Allocation, String> enumAsMapKey;
|
||||
|
||||
static enum Allocation {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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.
|
||||
@@ -29,6 +29,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
|
||||
import org.springframework.data.mongodb.core.CollectionCallback;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
|
||||
@@ -43,11 +45,15 @@ import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.test.util.BasicDbListBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
@@ -317,6 +323,66 @@ public class GeoJsonTests {
|
||||
assertThat(venues.size(), is(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1453
|
||||
*/
|
||||
@Test
|
||||
public void shouldConvertPointRepresentationCorrectlyWhenSourceCoordinatesUsesInteger() {
|
||||
|
||||
this.template.execute(template.getCollectionName(DocumentWithPropertyUsingGeoJsonType.class),
|
||||
new CollectionCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
|
||||
BasicDBObject pointRepresentation = new BasicDBObject();
|
||||
pointRepresentation.put("type", "Point");
|
||||
pointRepresentation.put("coordinates", new BasicDbListBuilder().add(0).add(0).get());
|
||||
|
||||
BasicDBObject document = new BasicDBObject();
|
||||
document.append("_id", "datamongo-1453");
|
||||
document.append("geoJsonPoint", pointRepresentation);
|
||||
|
||||
return collection.save(document);
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(template.findOne(query(where("id").is("datamongo-1453")),
|
||||
DocumentWithPropertyUsingGeoJsonType.class).geoJsonPoint, is(equalTo(new GeoJsonPoint(0D, 0D))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1453
|
||||
*/
|
||||
@Test
|
||||
public void shouldConvertLineStringRepresentationCorrectlyWhenSourceCoordinatesUsesInteger() {
|
||||
|
||||
this.template.execute(template.getCollectionName(DocumentWithPropertyUsingGeoJsonType.class),
|
||||
new CollectionCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
|
||||
BasicDBObject lineStringRepresentation = new BasicDBObject();
|
||||
lineStringRepresentation.put("type", "LineString");
|
||||
lineStringRepresentation.put("coordinates",
|
||||
new BasicDbListBuilder().add(new BasicDbListBuilder().add(0).add(0).get())
|
||||
.add(new BasicDbListBuilder().add(1).add(1).get()).get());
|
||||
|
||||
BasicDBObject document = new BasicDBObject();
|
||||
document.append("_id", "datamongo-1453");
|
||||
document.append("geoJsonLineString", lineStringRepresentation);
|
||||
|
||||
return collection.save(document);
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(
|
||||
template.findOne(query(where("id").is("datamongo-1453")),
|
||||
DocumentWithPropertyUsingGeoJsonType.class).geoJsonLineString,
|
||||
is(equalTo(new GeoJsonLineString(new Point(0D, 0D), new Point(1, 1)))));
|
||||
}
|
||||
|
||||
private void addVenues() {
|
||||
|
||||
template.insert(new Venue2DSphere("Penn Station", -73.99408, 40.75057));
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -27,7 +28,9 @@ import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -101,5 +104,7 @@ public class AuditingEventListenerUnitTests {
|
||||
static class Sample {
|
||||
|
||||
@Id String id;
|
||||
@CreatedDate Date created;
|
||||
@LastModifiedDate Date modified;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -15,63 +15,61 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.monitor;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
/**
|
||||
* This test class assumes that you are already running the MongoDB server.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Darimont
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
public class MongoMonitorIntegrationTests {
|
||||
|
||||
@Autowired Mongo mongo;
|
||||
@Autowired Mongo mongo;
|
||||
|
||||
@Test
|
||||
public void serverInfo() {
|
||||
ServerInfo serverInfo = new ServerInfo(mongo);
|
||||
serverInfo.getVersion();
|
||||
Assert.isTrue(StringUtils.hasText("1."));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnknownHostException
|
||||
* @see DATAMONGO-685
|
||||
*/
|
||||
@Test
|
||||
public void getHostNameShouldReturnServerNameReportedByMongo() throws UnknownHostException {
|
||||
|
||||
ServerInfo serverInfo = new ServerInfo(mongo);
|
||||
|
||||
String hostName = null;
|
||||
try {
|
||||
hostName = serverInfo.getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
assertThat(hostName, is(notNullValue()));
|
||||
assertThat(hostName, is("127.0.0.1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnknownHostException
|
||||
* @see DATAMONGO-685
|
||||
*/
|
||||
@Test
|
||||
public void getHostNameShouldReturnServerNameReportedByMongo() throws UnknownHostException {
|
||||
|
||||
ServerInfo serverInfo = new ServerInfo(mongo);
|
||||
|
||||
String hostName = null;
|
||||
try {
|
||||
hostName = serverInfo.getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
assertThat(hostName, is(notNullValue()));
|
||||
assertThat(hostName, is("127.0.0.1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void operationCounters() {
|
||||
OperationCounters operationCounters = new OperationCounters(mongo);
|
||||
operationCounters.getInsertCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2017 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.
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.mongodb.performance;
|
||||
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
import static org.springframework.util.Assert.*;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
@@ -47,6 +46,7 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -66,6 +66,7 @@ import com.mongodb.WriteConcern;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class PerformanceTests {
|
||||
|
||||
@@ -74,7 +75,7 @@ public class PerformanceTests {
|
||||
private static final int ITERATIONS = 50;
|
||||
private static final StopWatch watch = new StopWatch();
|
||||
private static final Collection<String> IGNORED_WRITE_CONCERNS = Arrays.asList("MAJORITY", "REPLICAS_SAFE",
|
||||
"FSYNC_SAFE", "FSYNCED", "JOURNAL_SAFE", "JOURNALED", "REPLICA_ACKNOWLEDGED");
|
||||
"FSYNC_SAFE", "FSYNCED", "JOURNAL_SAFE", "JOURNALED", "REPLICA_ACKNOWLEDGED", "W2", "W3");
|
||||
private static final int COLLECTION_SIZE = 1024 * 1024 * 256; // 256 MB
|
||||
private static final Collection<String> COLLECTION_NAMES = Arrays.asList("template", "driver", "person");
|
||||
|
||||
@@ -622,7 +623,7 @@ public class PerformanceTests {
|
||||
|
||||
private static <T> List<T> pickRandomNumerOfItemsFrom(List<T> source) {
|
||||
|
||||
isTrue(!source.isEmpty());
|
||||
Assert.isTrue(!source.isEmpty(), "Source must not be empty!");
|
||||
|
||||
Random random = new Random();
|
||||
int numberOfItems = random.nextInt(source.size());
|
||||
@@ -836,7 +837,7 @@ public class PerformanceTests {
|
||||
String.format(" %s%%", DEVIATION_FORMAT.format(getMediaDeviationFrom(referenceMedian)))) + '\n';
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@@ -895,7 +896,7 @@ public class PerformanceTests {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,9 @@ import java.util.stream.Stream;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
@@ -51,6 +53,7 @@ import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.repository.Person.Sex;
|
||||
import org.springframework.data.mongodb.repository.SampleEvaluationContextExtension.SampleSecurityContextHolder;
|
||||
@@ -65,10 +68,14 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Fırat KÜÇÜK
|
||||
* @author Edward Prentice
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
|
||||
public @Rule ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Autowired protected PersonRepository repository;
|
||||
|
||||
@Autowired MongoOperations operations;
|
||||
@@ -86,8 +93,10 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
dave = new Person("Dave", "Matthews", 42);
|
||||
oliver = new Person("Oliver August", "Matthews", 4);
|
||||
carter = new Person("Carter", "Beauford", 49);
|
||||
carter.setSkills(Arrays.asList("Drums", "percussion", "vocals"));
|
||||
Thread.sleep(10);
|
||||
boyd = new Person("Boyd", "Tinsley", 45);
|
||||
boyd.setSkills(Arrays.asList("Violin", "Electric Violin", "Viola", "Mandolin", "Vocals", "Guitar"));
|
||||
stefan = new Person("Stefan", "Lessard", 34);
|
||||
leroi = new Person("Leroi", "Moore", 41);
|
||||
|
||||
@@ -166,6 +175,18 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
assertThat(result, hasItem(boyd));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1608
|
||||
*/
|
||||
@Test
|
||||
public void findByFirstnameLikeWithNull() {
|
||||
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("property 'firstname'");
|
||||
|
||||
repository.findByFirstnameLike(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findsPagedPersons() throws Exception {
|
||||
|
||||
@@ -270,6 +291,18 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
assertThat(result, hasItem(dave));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1588
|
||||
public void findsPeopleByLocationNearUsingGeoJsonType() {
|
||||
|
||||
GeoJsonPoint point = new GeoJsonPoint(-73.99171, 40.738868);
|
||||
dave.setLocation(point);
|
||||
repository.save(dave);
|
||||
|
||||
List<Person> result = repository.findByLocationNear(point);
|
||||
assertThat(result.size(), is(1));
|
||||
assertThat(result, hasItem(dave));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findsPeopleByLocationWithinCircle() {
|
||||
Point point = new Point(-73.99171, 40.738868);
|
||||
@@ -697,6 +730,18 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||
}
|
||||
|
||||
/***
|
||||
* @see DATAMONGO-1608
|
||||
*/
|
||||
@Test
|
||||
public void findByFirstNameIgnoreCaseWithNull() {
|
||||
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("property 'firstname'");
|
||||
|
||||
repository.findByFirstnameIgnoreCase(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-770
|
||||
*/
|
||||
@@ -995,7 +1040,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
|
||||
/**
|
||||
* Ignored for now as this requires Querydsl 3.4.1 to succeed.
|
||||
*
|
||||
*
|
||||
* @see DATAMONGO-972
|
||||
*/
|
||||
@Test
|
||||
@@ -1261,4 +1306,37 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
assertThat(result.size(), is(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1425
|
||||
*/
|
||||
@Test
|
||||
public void findsPersonsByFirstnameNotContains() throws Exception {
|
||||
|
||||
List<Person> result = repository.findByFirstnameNotContains("Boyd");
|
||||
assertThat(result.size(), is((int) (repository.count() - 1)));
|
||||
assertThat(result, not(hasItem(boyd)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1425
|
||||
*/
|
||||
@Test
|
||||
public void findBySkillsContains() throws Exception {
|
||||
|
||||
List<Person> result = repository.findBySkillsContains(Arrays.asList("Drums"));
|
||||
assertThat(result.size(), is(1));
|
||||
assertThat(result, hasItem(carter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1425
|
||||
*/
|
||||
@Test
|
||||
public void findBySkillsNotContains() throws Exception {
|
||||
|
||||
List<Person> result = repository.findBySkillsNotContains(Arrays.asList("Drums"));
|
||||
assertThat(result.size(), is((int) (repository.count() - 1)));
|
||||
assertThat(result, not(hasItem(carter)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -89,8 +89,14 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
||||
*/
|
||||
List<Person> findByFirstnameLike(String firstname);
|
||||
|
||||
List<Person> findByFirstnameNotContains(String firstname);
|
||||
|
||||
List<Person> findByFirstnameLikeOrderByLastnameAsc(String firstname, Sort sort);
|
||||
|
||||
List<Person> findBySkillsContains(List<String> skills);
|
||||
|
||||
List<Person> findBySkillsNotContains(List<String> skills);
|
||||
|
||||
@Query("{'age' : { '$lt' : ?0 } }")
|
||||
List<Person> findByAgeLessThan(int age, Sort sort);
|
||||
|
||||
@@ -309,7 +315,8 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
||||
* @see DATAMONGO-745
|
||||
*/
|
||||
@Query("{lastname:?0, address.street:{$in:?1}}")
|
||||
Page<Person> findByCustomQueryLastnameAndAddressStreetInList(String lastname, List<String> streetNames, Pageable page);
|
||||
Page<Person> findByCustomQueryLastnameAndAddressStreetInList(String lastname, List<String> streetNames,
|
||||
Pageable page);
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-950
|
||||
@@ -334,19 +341,19 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
||||
*/
|
||||
@Query("{ firstname : { $in : ?0 }}")
|
||||
Stream<Person> findByCustomQueryWithStreamingCursorByFirstnames(List<String> firstnames);
|
||||
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-990
|
||||
*/
|
||||
@Query("{ firstname : ?#{[0]}}")
|
||||
List<Person> findWithSpelByFirstnameForSpELExpressionWithParameterIndexOnly(String firstname);
|
||||
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-990
|
||||
*/
|
||||
@Query("{ firstname : ?#{[0]}, email: ?#{principal.email} }")
|
||||
List<Person> findWithSpelByFirstnameAndCurrentUserWithCustomQuery(String firstname);
|
||||
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-990
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,8 @@ import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
@@ -69,8 +71,6 @@ import com.mongodb.DBObject;
|
||||
*/
|
||||
public class MongoQueryCreatorUnitTests {
|
||||
|
||||
Method findByFirstname, findByFirstnameAndFriend, findByFirstnameNotNull;
|
||||
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context;
|
||||
MongoConverter converter;
|
||||
|
||||
@@ -454,6 +454,7 @@ public class MongoQueryCreatorUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1075
|
||||
* @see DATAMONGO-1425
|
||||
*/
|
||||
@Test
|
||||
public void shouldCreateRegexWhenUsingNotContainsOnStringProperty() {
|
||||
@@ -462,14 +463,14 @@ public class MongoQueryCreatorUnitTests {
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "thew"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("username").regex(".*thew.*").not())));
|
||||
assertThat(query.getQueryObject(), is(query(where("username").not().regex(".*thew.*")).getQueryObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1139
|
||||
*/
|
||||
@Test
|
||||
public void createsNonShericalNearForDistanceWithDefaultMetric() {
|
||||
public void createsNonSphericalNearForDistanceWithDefaultMetric() {
|
||||
|
||||
Point point = new Point(1.0, 1.0);
|
||||
Distance distance = new Distance(1.0);
|
||||
@@ -668,6 +669,35 @@ public class MongoQueryCreatorUnitTests {
|
||||
assertThat(query, is(query(where("emailAddresses").in((Object) null))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1588
|
||||
*/
|
||||
@Test // DATAMONGO-1588
|
||||
public void queryShouldAcceptSubclassOfDeclaredArgument() {
|
||||
|
||||
PartTree tree = new PartTree("findByLocationNear", User.class);
|
||||
ConvertingParameterAccessor accessor = getAccessor(converter, new GeoJsonPoint(-74.044502D, 40.689247D));
|
||||
|
||||
Query query = new MongoQueryCreator(tree, accessor, context).createQuery();
|
||||
assertThat(query.getQueryObject().containsField("location"), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1588
|
||||
*/
|
||||
@Test
|
||||
public void queryShouldThrowExceptionWhenArgumentDoesNotMatchDeclaration() {
|
||||
|
||||
expection.expect(IllegalArgumentException.class);
|
||||
expection.expectMessage("Expected parameter type of " + Point.class);
|
||||
|
||||
PartTree tree = new PartTree("findByLocationNear", User.class);
|
||||
ConvertingParameterAccessor accessor = getAccessor(converter,
|
||||
new GeoJsonLineString(new Point(-74.044502D, 40.689247D), new Point(-73.997330D, 40.730824D)));
|
||||
|
||||
new MongoQueryCreator(tree, accessor, context).createQuery();
|
||||
}
|
||||
|
||||
interface PersonRepository extends Repository<Person, Long> {
|
||||
|
||||
List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);
|
||||
@@ -686,16 +716,21 @@ public class MongoQueryCreatorUnitTests {
|
||||
Address address;
|
||||
|
||||
Address2dSphere address2dSphere;
|
||||
|
||||
Point location;
|
||||
}
|
||||
|
||||
static class Address {
|
||||
|
||||
String street;
|
||||
|
||||
Point geo;
|
||||
}
|
||||
|
||||
static class Address2dSphere {
|
||||
|
||||
String street;
|
||||
|
||||
@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) Point geo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.query.IsTextQuery.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -40,6 +41,7 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.TextCriteria;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.Person;
|
||||
import org.springframework.data.mongodb.repository.Person.Sex;
|
||||
import org.springframework.data.mongodb.repository.Query;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
@@ -192,6 +194,18 @@ public class PartTreeMongoQueryUnitTests {
|
||||
assertThat(fields.get("age"), is((Object) 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1500
|
||||
*/
|
||||
@Test
|
||||
public void shouldLeaveParameterConversionToQueryMapper() {
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = deriveQueryFromMethod("findBySex", Sex.FEMALE);
|
||||
|
||||
assertThat(query.getQueryObject().get("sex"), is((Object) Sex.FEMALE));
|
||||
assertThat(query.getFieldsObject().get("firstname"), is((Object) 1));
|
||||
}
|
||||
|
||||
private org.springframework.data.mongodb.core.query.Query deriveQueryFromMethod(String method, Object... args) {
|
||||
|
||||
Class<?>[] types = new Class<?>[args.length];
|
||||
@@ -249,6 +263,9 @@ public class PartTreeMongoQueryUnitTests {
|
||||
PersonDto findPersonDtoByAge(Integer age);
|
||||
|
||||
<T> T findDynamicallyProjectedBy(Class<T> type);
|
||||
|
||||
@Query(fields = "{ 'firstname' : 1 }")
|
||||
List<Person> findBySex(Sex sex);
|
||||
}
|
||||
|
||||
interface PersonProjection {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
@@ -50,14 +51,16 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat
|
||||
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link StringBasedMongoQuery}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
@@ -84,9 +87,9 @@ public class StringBasedMongoQueryUnitTests {
|
||||
public void bindsSimplePropertyCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastname", String.class);
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Matthews");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : 'Matthews'}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
@@ -98,13 +101,13 @@ public class StringBasedMongoQueryUnitTests {
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByAddress", Address.class);
|
||||
|
||||
Address address = new Address("Foo", "0123", "Bar");
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, address);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, address);
|
||||
|
||||
DBObject dbObject = new BasicDBObject();
|
||||
converter.write(address, dbObject);
|
||||
dbObject.removeField(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
BasicDBObject queryObject = new BasicDBObject("address", dbObject);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery(queryObject);
|
||||
|
||||
@@ -117,7 +120,7 @@ public class StringBasedMongoQueryUnitTests {
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameAndAddress", String.class, Address.class);
|
||||
|
||||
Address address = new Address("Foo", "0123", "Bar");
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews", address);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Matthews", address);
|
||||
|
||||
DBObject addressDbObject = new BasicDBObject();
|
||||
converter.write(address, addressDbObject);
|
||||
@@ -126,7 +129,7 @@ public class StringBasedMongoQueryUnitTests {
|
||||
DBObject reference = new BasicDBObject("address", addressDbObject);
|
||||
reference.put("lastname", "Matthews");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is(reference));
|
||||
}
|
||||
|
||||
@@ -148,7 +151,7 @@ public class StringBasedMongoQueryUnitTests {
|
||||
public void bindsDbrefCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByHavingSizeFansNotZero");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, new Object[] {});
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is(new BasicQuery("{ fans : { $not : { $size : 0 } } }").getQueryObject()));
|
||||
@@ -178,8 +181,8 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void shouldSupportFindByParameterizedCriteriaAndFields() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, new Object[] {
|
||||
new BasicDBObject("firstname", "first").append("lastname", "last"), Collections.singletonMap("lastname", 1) });
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
new BasicDBObject("firstname", "first").append("lastname", "last"), Collections.singletonMap("lastname", 1));
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByParameterizedCriteriaAndFields", DBObject.class,
|
||||
Map.class);
|
||||
|
||||
@@ -196,7 +199,7 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void shouldSupportRespectExistingQuotingInFindByTitleBeginsWithExplicitQuoting() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, new Object[] { "fun" });
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "fun");
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByTitleBeginsWithExplicitQuoting", String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
@@ -210,7 +213,7 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void shouldParseQueryWithParametersInExpression() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, new Object[] { 1, 2, 3, 4 });
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, 1, 2, 3, 4);
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByQueryWithParametersInExpression", int.class,
|
||||
int.class, int.class, int.class);
|
||||
|
||||
@@ -227,10 +230,10 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void bindsSimplePropertyAlreadyQuotedCorrectly() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Matthews");
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : 'Matthews'}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
@@ -242,10 +245,10 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void bindsSimplePropertyAlreadyQuotedWithRegexCorrectly() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "^Mat.*");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "^Mat.*");
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : '^Mat.*'}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
@@ -258,9 +261,9 @@ public class StringBasedMongoQueryUnitTests {
|
||||
public void bindsSimplePropertyWithRegexCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastname", String.class);
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "^Mat.*");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "^Mat.*");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : '^Mat.*'}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
@@ -303,10 +306,10 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void shouldSupportExpressionsInCustomQueries() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Matthews");
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByQueryWithExpression", String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : 'Matthews'}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
@@ -318,11 +321,11 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void shouldSupportExpressionsInCustomQueriesWithNestedObject() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, true, "param1", "param2");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, true, "param1", "param2");
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByQueryWithExpressionAndNestedObject", boolean.class,
|
||||
String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{ \"id\" : { \"$exists\" : true}}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
@@ -334,11 +337,11 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Test
|
||||
public void shouldSupportExpressionsInCustomQueriesWithMultipleNestedObjects() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, true, "param1", "param2");
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, true, "param1", "param2");
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByQueryWithExpressionAndMultipleNestedObjects",
|
||||
boolean.class, String.class, String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery(
|
||||
"{ \"id\" : { \"$exists\" : true} , \"foo\" : 42 , \"bar\" : { \"$exists\" : false}}");
|
||||
|
||||
@@ -352,16 +355,252 @@ public class StringBasedMongoQueryUnitTests {
|
||||
public void shouldSupportNonQuotedBinaryDataReplacement() throws Exception {
|
||||
|
||||
byte[] binaryData = "Matthews".getBytes("UTF-8");
|
||||
ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, binaryData);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, binaryData);
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameAsBinary", byte[].class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accesor);
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : { '$binary' : '"
|
||||
+ DatatypeConverter.printBase64Binary(binaryData) + "', '$type' : " + BSON.B_GENERAL + "}}");
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void bindsPropertyReferenceMultipleTimesCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByAgeQuotedAndUnquoted", Integer.TYPE);
|
||||
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, 3);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
BasicDBList or = new BasicDBList();
|
||||
or.add(new BasicDBObject("age", 3));
|
||||
or.add(new BasicDBObject("displayAge", "3"));
|
||||
BasicDBObject queryObject = new BasicDBObject("$or", or);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery(queryObject);
|
||||
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnorePlaceholderPatternInReplacementValue() throws Exception {
|
||||
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "argWith?1andText",
|
||||
"nothing-special");
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByStringWithWildcardChar", String.class, String.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(),
|
||||
is(JSON.parse("{ \"arg0\" : \"argWith?1andText\" , \"arg1\" : \"nothing-special\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void shouldQuoteStringReplacementCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Matthews', password: 'foo");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(),
|
||||
is(not(new BasicDBObjectBuilder().add("lastname", "Matthews").add("password", "foo").get())));
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("lastname", "Matthews', password: 'foo")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void shouldQuoteStringReplacementContainingQuotesCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Matthews\", password: \"foo");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(),
|
||||
is(not(new BasicDBObjectBuilder().add("lastname", "Matthews").add("password", "foo").get())));
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("lastname", "Matthews\", password: \"foo")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void shouldQuoteStringReplacementWithQuotationsCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
"\"Dave Matthews\", password: 'foo");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(),
|
||||
is((DBObject) new BasicDBObject("lastname", "\"Dave Matthews\", password: 'foo")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void shouldQuoteComplexQueryStringCorreclty() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "{ $ne : \"calamity\" }");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("lastname", "{ $ne : \"calamity\" }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1565
|
||||
*/
|
||||
@Test
|
||||
public void shouldQuotationInQuotedComplexQueryString() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameQuoted", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
"{ $ne : \"\\\"calamity\\\"\" }");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("lastname", "{ $ne : \"\\\"calamity\\\"\" }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1575
|
||||
*/
|
||||
@Test
|
||||
public void shouldTakeBsonParameterAsIs() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByWithBsonArgument", DBObject.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
new BasicDBObject("$regex", "^calamity$"));
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("arg0", Pattern.compile("^calamity$"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1575
|
||||
*/
|
||||
@Test
|
||||
public void shouldReplaceParametersInInQuotedExpressionOfNestedQueryOperator() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameRegex", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("lastname", Pattern.compile("^(calamity)"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1603
|
||||
*/
|
||||
@Test
|
||||
public void shouldAllowReuseOfPlaceholderWithinQuery() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByReusingPlaceholdersMultipleTimes", String.class,
|
||||
String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", "calamity")
|
||||
.append("arg1", "regalia").append("arg2", "calamity")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1575
|
||||
*/
|
||||
@Test
|
||||
public void shouldAllowReuseOfQuotedPlaceholderWithinQuery() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByReusingPlaceholdersMultipleTimesWhenQuoted",
|
||||
String.class, String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", "calamity")
|
||||
.append("arg1", "regalia").append("arg2", "calamity")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1575
|
||||
*/
|
||||
@Test
|
||||
public void shouldAllowReuseOfQuotedPlaceholderWithinQueryAndIncludeSuffixCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod(
|
||||
"findByReusingPlaceholdersMultipleTimesWhenQuotedAndSomeStuffAppended", String.class, String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", "calamity")
|
||||
.append("arg1", "regalia").append("arg2", "calamitys")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1603
|
||||
public void shouldAllowQuotedParameterWithSuffixAppended() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByWhenQuotedAndSomeStuffAppended", String.class,
|
||||
String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(),
|
||||
is((DBObject) new BasicDBObject().append("arg0", "calamity").append("arg1", "regalias")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1603
|
||||
public void shouldCaptureReplacementWithComplexSuffixCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByMultiRegex", String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
|
||||
assertThat(query.getQueryObject(), is((DBObject) JSON.parse(
|
||||
"{ \"$or\" : [ { \"firstname\" : { \"$regex\" : \".*calamity.*\" , \"$options\" : \"i\"}} , { \"lastname\" : { \"$regex\" : \".*calamityxyz.*\" , \"$options\" : \"i\"}}]}")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1603
|
||||
public void shouldAllowPlaceholderReuseInQuotedValue() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameRegex", String.class, String.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
|
||||
assertThat(query.getQueryObject(),
|
||||
is((DBObject) JSON.parse("{ 'lastname' : { '$regex' : '^(calamity|John regalia|regalia)'} }")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1605
|
||||
public void findUsingSpelShouldRetainParameterType() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByUsingSpel", Object.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, 100.01D);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", 100.01D)));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1605
|
||||
public void findUsingSpelShouldRetainNullValues() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByUsingSpel", Object.class);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, new Object[] { null });
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", null)));
|
||||
}
|
||||
|
||||
private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
|
||||
|
||||
Method method = SampleRepository.class.getMethod(name, parameters);
|
||||
@@ -382,6 +621,12 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Query("{ 'lastname' : '?0' }")
|
||||
Person findByLastnameQuoted(String lastname);
|
||||
|
||||
@Query("{ 'lastname' : { '$regex' : '^(?0)'} }")
|
||||
Person findByLastnameRegex(String lastname);
|
||||
|
||||
@Query("{'$or' : [{'firstname': {'$regex': '.*?0.*', '$options': 'i'}}, {'lastname' : {'$regex': '.*?0xyz.*', '$options': 'i'}} ]}")
|
||||
Person findByMultiRegex(String arg0);
|
||||
|
||||
@Query("{ 'address' : ?0 }")
|
||||
Person findByAddress(Address address);
|
||||
|
||||
@@ -420,5 +665,32 @@ public class StringBasedMongoQueryUnitTests {
|
||||
|
||||
@Query("{'id':?#{ [0] ? { $exists :true} : [1] }, 'foo':42, 'bar': ?#{ [0] ? { $exists :false} : [1] }}")
|
||||
List<Person> findByQueryWithExpressionAndMultipleNestedObjects(boolean param0, String param1, String param2);
|
||||
|
||||
@Query(value = "{ $or : [{'age' : ?0 }, {'displayAge' : '?0'}] }")
|
||||
boolean findByAgeQuotedAndUnquoted(int age);
|
||||
|
||||
@Query("{ 'arg0' : ?0, 'arg1' : ?1 }")
|
||||
List<Person> findByStringWithWildcardChar(String arg0, String arg1);
|
||||
|
||||
@Query("{ 'arg0' : ?0 }")
|
||||
List<Person> findByWithBsonArgument(DBObject arg0);
|
||||
|
||||
@Query("{ 'arg0' : ?0, 'arg1' : ?1, 'arg2' : ?0 }")
|
||||
List<Person> findByReusingPlaceholdersMultipleTimes(String arg0, String arg1);
|
||||
|
||||
@Query("{ 'arg0' : ?0, 'arg1' : ?1, 'arg2' : '?0' }")
|
||||
List<Person> findByReusingPlaceholdersMultipleTimesWhenQuoted(String arg0, String arg1);
|
||||
|
||||
@Query("{ 'arg0' : '?0', 'arg1' : ?1, 'arg2' : '?0s' }")
|
||||
List<Person> findByReusingPlaceholdersMultipleTimesWhenQuotedAndSomeStuffAppended(String arg0, String arg1);
|
||||
|
||||
@Query("{ 'arg0' : '?0', 'arg1' : '?1s' }")
|
||||
List<Person> findByWhenQuotedAndSomeStuffAppended(String arg0, String arg1);
|
||||
|
||||
@Query("{ 'lastname' : { '$regex' : '^(?0|John ?1|?1)'} }") // use spel or some regex string this is fucking bad
|
||||
Person findByLastnameRegex(String lastname, String alternative);
|
||||
|
||||
@Query("{ arg0 : ?#{[0]} }")
|
||||
List<Person> findByUsingSpel(Object arg0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2017 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.repository.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
|
||||
/**
|
||||
* Tests for {@link PersistableMongoEntityInformation}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PersistableMappingMongoEntityInformationUnitTests {
|
||||
|
||||
@Mock MongoPersistentEntity<TypeImplementingPersistable> persistableImplementingEntityTypeInfo;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(persistableImplementingEntityTypeInfo.getType()).thenReturn(TypeImplementingPersistable.class);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1590
|
||||
public void considersPersistableIsNew() {
|
||||
|
||||
PersistableMongoEntityInformation<TypeImplementingPersistable, Long> information = new PersistableMongoEntityInformation<TypeImplementingPersistable, Long>(
|
||||
new MappingMongoEntityInformation<TypeImplementingPersistable, Long>(persistableImplementingEntityTypeInfo));
|
||||
|
||||
assertThat(information.isNew(new TypeImplementingPersistable(100L, false)), is(false));
|
||||
}
|
||||
|
||||
@Value
|
||||
static class TypeImplementingPersistable implements Persistable<Long> {
|
||||
|
||||
private static final long serialVersionUID = -1619090149320971099L;
|
||||
|
||||
Long id;
|
||||
boolean isNew;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2016 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.
|
||||
@@ -19,6 +19,8 @@ import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
@@ -26,11 +28,15 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.repository.Person.Sex;
|
||||
import org.springframework.data.mongodb.repository.QAddress;
|
||||
import org.springframework.data.mongodb.repository.QPerson;
|
||||
|
||||
@@ -172,10 +178,52 @@ public class SpringDataMongodbSerializerUnitTests {
|
||||
assertThat($in, Matchers.<Object> arrayContaining(firstId, secondId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1485
|
||||
*/
|
||||
@Test
|
||||
public void takesCustomConversionForEnumsIntoAccount() {
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
|
||||
MappingMongoConverter converter = new MappingMongoConverter(dbFactory, context);
|
||||
converter.setCustomConversions(new CustomConversions(Collections.singletonList(new SexTypeWriteConverter())));
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
this.converter = converter;
|
||||
this.serializer = new SpringDataMongodbSerializer(this.converter);
|
||||
|
||||
Object mappedPredicate = this.serializer.handle(QPerson.person.sex.eq(Sex.FEMALE));
|
||||
|
||||
assertThat(mappedPredicate, is(instanceOf(DBObject.class)));
|
||||
assertThat(((DBObject) mappedPredicate).get("sex"), is((Object) "f"));
|
||||
}
|
||||
|
||||
class Address {
|
||||
String id;
|
||||
String street;
|
||||
@Field("zip_code") String zipCode;
|
||||
@Field("bar") String[] foo;
|
||||
}
|
||||
|
||||
@WritingConverter
|
||||
public class SexTypeWriteConverter implements Converter<Sex, String> {
|
||||
|
||||
@Override
|
||||
public String convert(Sex source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (source) {
|
||||
case MALE:
|
||||
return "m";
|
||||
case FEMALE:
|
||||
return "f";
|
||||
default:
|
||||
throw new IllegalArgumentException("o_O");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ Mark Pollack; Thomas Risberg; Oliver Gierke; Costin Leau; Jon Brisbin; Thomas Da
|
||||
:toc-placement!:
|
||||
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
|
||||
|
||||
(C) 2008-2015 The original authors.
|
||||
(C) 2008-2017 The original authors.
|
||||
|
||||
NOTE: _Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically._
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
|
||||
The Spring Data MongoDB project applies core Spring concepts to the development of solutions using the MongoDB document style data store. We provide a "template" as a high-level abstraction for storing and querying documents. You will notice similarities to the JDBC support in the Spring Framework.
|
||||
|
||||
This document is the reference guide for Spring Data - Document Support. It explains Document module concepts and semantics and the syntax for various stores namespaces.
|
||||
This document is the reference guide for Spring Data - Document Support. It explains Document module concepts and semantics and the syntax for various store namespaces.
|
||||
|
||||
This section provides some basic introduction to Spring and Document database. The rest of the document refers only to Spring Data Document features and assumes the user is familiar with document databases such as MongoDB and CouchDB as well as Spring concepts.
|
||||
This section provides some basic introduction to Spring and Document databases. The rest of the document refers only to Spring Data MongoDB features and assumes the user is familiar with MongoDB and Spring concepts.
|
||||
|
||||
[[get-started:first-steps:spring]]
|
||||
== Knowing Spring
|
||||
Spring Data uses Spring framework's http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/spring-core.html[core] functionality, such as the http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/beans.html[IoC] container, http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/validation.html#core-convert[type conversion system], http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/expressions.html[expression language], http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/jmx.html[JMX integration], and portable http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/dao.html#dao-exceptions[DAO exception hierarchy]. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar for whatever IoC container you choose to use.
|
||||
Spring Data uses Spring framework's http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/spring-core.html[core] functionality, such as the http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/beans.html[IoC] container, http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/validation.html#core-convert[type conversion system], http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/expressions.html[expression language], http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/jmx.html[JMX integration], and portable http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/dao.html#dao-exceptions[DAO exception hierarchy]. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar for whatever IoC container you choose to use.
|
||||
|
||||
The core functionality of the MongoDB and CouchDB support can be used directly, with no need to invoke the IoC services of the Spring Container. This is much like `JdbcTemplate` which can be used 'standalone' without any other services of the Spring container. To leverage all the features of Spring Data document, such as the repository support, you will need to configure some parts of the library using Spring.
|
||||
The core functionality of the MongoDB support can be used directly, with no need to invoke the IoC services of the Spring Container. This is much like `JdbcTemplate` which can be used 'standalone' without any other services of the Spring container. To leverage all the features of Spring Data MongoDB, such as the repository support, you will need to configure some parts of the library using Spring.
|
||||
|
||||
To learn more about Spring, you can refer to the comprehensive (and sometimes disarming) documentation that explains in detail the Spring Framework. There are a lot of articles, blog entries and books on the matter - take a look at the Spring framework http://spring.io/docs[home page ] for more information.
|
||||
To learn more about Spring, you can refer to the comprehensive (and sometimes disarming) documentation that explains in detail the Spring Framework. There are a lot of articles, blog entries and books on the matter - take a look at the Spring framework http://spring.io/docs[home page] for more information.
|
||||
|
||||
[[get-started:first-steps:nosql]]
|
||||
== Knowing NoSQL and Document databases
|
||||
NoSQL stores have taken the storage world by storm. It is a vast domain with a plethora of solutions, terms and patterns (to make things worth even the term itself has multiple http://www.google.com/search?q=nosoql+acronym[meanings]). While some of the principles are common, it is crucial that the user is familiar to some degree with the stores supported by DATADOC. The best way to get acquainted to this solutions is to read their documentation and follow their examples - it usually doesn't take more then 5-10 minutes to go through them and if you are coming from an RDMBS-only background many times these exercises can be an eye opener.
|
||||
NoSQL stores have taken the storage world by storm. It is a vast domain with a plethora of solutions, terms and patterns (to make things worse even the term itself has multiple http://www.google.com/search?q=nosoql+acronym[meanings]). While some of the principles are common, it is crucial that the user is familiar to some degree with MongoDB. The best way to get acquainted to this solutions is to read their documentation and follow their examples - it usually doesn't take more then 5-10 minutes to go through them and if you are coming from an RDMBS-only background many times these exercises can be an eye opener.
|
||||
|
||||
The jumping off ground for learning about MongoDB is http://www.mongodb.org/[www.mongodb.org]. Here is a list of other useful resources:
|
||||
|
||||
@@ -36,7 +36,7 @@ In terms of document stores, http://www.mongodb.org/[MongoDB] at least 2.6.
|
||||
|
||||
== Additional Help Resources
|
||||
|
||||
Learning a new framework is not always straight forward. In this section, we try to provide what we think is an easy to follow guide for starting with Spring Data Document module. However, if you encounter issues or you are just looking for an advice, feel free to use one of the links below:
|
||||
Learning a new framework is not always straight forward. In this section, we try to provide what we think is an easy to follow guide for starting with Spring Data MongoDB module. However, if you encounter issues or you are just looking for an advice, feel free to use one of the links below:
|
||||
|
||||
[[get-started:help]]
|
||||
=== Support
|
||||
@@ -56,4 +56,4 @@ Professional, from-the-source support, with guaranteed response time, is availab
|
||||
[[get-started:up-to-date]]
|
||||
=== Following Development
|
||||
|
||||
For information on the Spring Data Mongo source code repository, nightly builds and snapshot artifacts please see the http://projects.spring.io/spring-data-mongodb/[Spring Data Mongo homepage]. You can help make Spring Data best serve the needs of the Spring community by interacting with developers through the Community on http://stackoverflow.com/questions/tagged/spring-data[Stackoverflow]. To follow developer activity look for the mailing list information on the Spring Data Mongo homepage. If you encounter a bug or want to suggest an improvement, please create a ticket on the Spring Data issue https://jira.spring.io/browse/DATAMONGO[tracker]. To stay up to date with the latest news and announcements in the Spring eco system, subscribe to the Spring Community http://spring.io[Portal]. Lastly, you can follow the SpringSource Data http://spring.io/blog[blog ]or the project team on Twitter (http://twitter.com/SpringData[SpringData]).
|
||||
For information on the Spring Data Mongo source code repository, nightly builds and snapshot artifacts please see the http://projects.spring.io/spring-data-mongodb/[Spring Data Mongo homepage]. You can help make Spring Data best serve the needs of the Spring community by interacting with developers through the Community on http://stackoverflow.com/questions/tagged/spring-data[Stackoverflow]. To follow developer activity look for the mailing list information on the Spring Data Mongo homepage. If you encounter a bug or want to suggest an improvement, please create a ticket on the Spring Data issue https://jira.spring.io/browse/DATAMONGO[tracker]. To stay up to date with the latest news and announcements in the Spring eco system, subscribe to the Spring Community http://spring.io[Portal]. Lastly, you can follow the Spring http://spring.io/blog[blog ]or the project team on Twitter (http://twitter.com/SpringData[SpringData]).
|
||||
|
||||
@@ -157,7 +157,7 @@ Finally, you need to configure your project to use MongoDB and also configure th
|
||||
[[mongodb_cross-store-application]]
|
||||
== Writing the Cross Store Application
|
||||
|
||||
We are assuming that you have a working JPA application so we will only cover the additional steps needed to persist part of your Entity in your Mongo database. First you need to identify the field you want persisted. It should be a domain class and follow the general rules for the Mongo mapping support covered in previous chapters. The field you want persisted in MongoDB should be annotated using the `@RelatedDocument` annotation. That is really all you need to do!. The cross-store aspects take care of the rest. This includes marking the field with `@Transient` so it won't be persisted using JPA, keeping track of any changes made to the field value and writing them to the database on successful transaction completion, loading the document from MongoDB the first time the value is used in your application. Here is an example of a simple Entity that has a field annotated with `@RelatedEntity`.
|
||||
We are assuming that you have a working JPA application so we will only cover the additional steps needed to persist part of your Entity in your Mongo database. First you need to identify the field you want persisted. It should be a domain class and follow the general rules for the Mongo mapping support covered in previous chapters. The field you want persisted in MongoDB should be annotated using the `@RelatedDocument` annotation. That is really all you need to do!. The cross-store aspects take care of the rest. This includes marking the field with `@Transient` so it won't be persisted using JPA, keeping track of any changes made to the field value and writing them to the database on successful transaction completion, loading the document from MongoDB the first time the value is used in your application. Here is an example of a simple Entity that has a field annotated with `@RelatedDocument`.
|
||||
|
||||
.Example of Entity with @RelatedDocument
|
||||
====
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
== Document Structure
|
||||
|
||||
This part of the reference documentation explains the core functionality offered by Spring Data Document.
|
||||
This part of the reference documentation explains the core functionality offered by Spring Data MongoDB.
|
||||
|
||||
<<mongo.core>> introduces the MongoDB module feature set.
|
||||
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
[[mapping-chapter]]
|
||||
= Mapping
|
||||
|
||||
Rich mapping support is provided by the `MongoMappingConverter`. `MongoMappingConverter` has a rich metadata model that provides a full feature set of functionality to map domain objects to MongoDB documents.The mapping metadata model is populated using annotations on your domain objects. However, the infrastructure is not limited to using annotations as the only source of metadata information. The `MongoMappingConverter` also allows you to map objects to documents without providing any additional metadata, by following a set of conventions.
|
||||
Rich mapping support is provided by the `MappingMongoConverter`. `MappingMongoConverter` has a rich metadata model that provides a full feature set of functionality to map domain objects to MongoDB documents.The mapping metadata model is populated using annotations on your domain objects. However, the infrastructure is not limited to using annotations as the only source of metadata information. The `MappingMongoConverter` also allows you to map objects to documents without providing any additional metadata, by following a set of conventions.
|
||||
|
||||
In this section we will describe the features of the `MongoMappingConverter`. How to use conventions for mapping objects to documents and how to override those conventions with annotation based mapping metadata.
|
||||
In this section we will describe the features of the `MappingMongoConverter`. How to use conventions for mapping objects to documents and how to override those conventions with annotation based mapping metadata.
|
||||
|
||||
NOTE: `SimpleMongoConverter` has been deprecated in Spring Data MongoDB M3 as all of its functionality has been subsumed into `MappingMongoConverter`.
|
||||
|
||||
[[mapping-conventions]]
|
||||
== Convention based Mapping
|
||||
|
||||
`MongoMappingConverter` has a few conventions for mapping objects to documents when no additional mapping metadata is provided. The conventions are:
|
||||
`MappingMongoConverter` has a few conventions for mapping objects to documents when no additional mapping metadata is provided. The conventions are:
|
||||
|
||||
* The short Java class name is mapped to the collection name in the following manner. The class '`com.bigbank.SavingsAccount`' maps to '`savingsAccount`' collection name.
|
||||
* The short Java class name is mapped to the collection name in the following manner. The class `com.bigbank.SavingsAccount` maps to `savingsAccount` collection name.
|
||||
* All nested objects are stored as nested objects in the document and *not* as DBRefs
|
||||
* The converter will use any Spring Converters registered with it to override the default mapping of object properties to document field/values.
|
||||
* The fields of an object are used to convert to and from fields in the document. Public JavaBean properties are not used.
|
||||
* You can have a single non-zero argument constructor whose constructor argument names match top level field names of document, that constructor will be used. Otherwise the zero arg constructor will be used. if there is more than one non-zero argument constructor an exception will be thrown.
|
||||
|
||||
[[mapping.conventions.id-field]]
|
||||
=== How the '_id' field is handled in the mapping layer
|
||||
=== How the `_id` field is handled in the mapping layer
|
||||
|
||||
MongoDB requires that you have an '_id' field for all documents. If you don't provide one the driver will assign a ObjectId with a generated value. The "_id" field can be of any type the, other than arrays, so long as it is unique. The driver naturally supports all primitive types and Dates. When using the `MongoMappingConverter` there are certain rules that govern how properties from the Java class is mapped to this '_id' field.
|
||||
MongoDB requires that you have an `_id` field for all documents. If you don't provide one the driver will assign a ObjectId with a generated value. The "_id" field can be of any type the, other than arrays, so long as it is unique. The driver naturally supports all primitive types and Dates. When using the `MappingMongoConverter` there are certain rules that govern how properties from the Java class is mapped to this `_id` field.
|
||||
|
||||
The following outlines what field will be mapped to the '_id' document field:
|
||||
The following outlines what field will be mapped to the `_id` document field:
|
||||
|
||||
* A field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the '_id' field.
|
||||
* A field without an annotation but named 'id' will be mapped to the '_id' field.
|
||||
* The default field name for identifiers is '_id' and can be customized via the `@Field` annotation.
|
||||
* A field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the `_id` field.
|
||||
* A field without an annotation but named `id` will be mapped to the `_id` field.
|
||||
* The default field name for identifiers is `_id` and can be customized via the `@Field` annotation.
|
||||
|
||||
[cols="1,2", options="header"]
|
||||
.Examples for the translation of '_id'-field definitions
|
||||
.Examples for the translation of `_id` field definitions
|
||||
|===
|
||||
| Field definition
|
||||
| Resulting Id-Fieldname in MongoDB
|
||||
@@ -41,30 +41,218 @@ The following outlines what field will be mapped to the '_id' document field:
|
||||
| `@Field` `String` id
|
||||
| `_id`
|
||||
|
||||
| `@Field('x')` `String` id
|
||||
| `@Field("x")` `String` id
|
||||
| `x`
|
||||
|
||||
| `@Id` `String` x
|
||||
| `_id`
|
||||
|
||||
| `@Field('x')` `@Id` `String` x
|
||||
| `@Field("x")` `@Id` `String` x
|
||||
| `_id`
|
||||
|===
|
||||
|
||||
The following outlines what type conversion, if any, will be done on the property mapped to the _id document field.
|
||||
|
||||
* If a field named 'id' is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value for 'id' in your application, the conversion to an ObjectId is detected to the MongoDBdriver. If the specified 'id' value cannot be converted to an ObjectId, then the value will be stored as is in the document's _id field.
|
||||
* If a field named ' id' id field is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document's _id field.
|
||||
* If no field named 'id' is present in the Java class then an implicit '_id' file will be generated by the driver but not mapped to a property or field of the Java class.
|
||||
* If a field named `id` is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value for `id` in your application, the conversion to an ObjectId is detected to the MongoDBdriver. If the specified `id` value cannot be converted to an ObjectId, then the value will be stored as is in the document's _id field.
|
||||
* If a field named `id` id field is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document's _id field.
|
||||
* If no field named `id` is present in the Java class then an implicit `_id` file will be generated by the driver but not mapped to a property or field of the Java class.
|
||||
|
||||
When querying and updating `MongoTemplate` will use the converter to handle conversions of the `Query` and `Update` objects that correspond to the above rules for saving documents so field names and types used in your queries will be able to match what is in your domain classes.
|
||||
|
||||
[[mapping-conversion]]
|
||||
== Data mapping and type conversion
|
||||
|
||||
This section explain how types are mapped to a MongoDB representation and vice versa. Spring Data MongoDB supports all types that can be represented as BSON, MongoDB's internal document format.
|
||||
In addition to these types, Spring Data MongoDB provides a set of built-in converters to map additional types. You can provide your own converters to adjust type conversion, see <<mapping-explicit-converters>> for further details.
|
||||
|
||||
[cols="3,1,6", options="header"]
|
||||
.Type
|
||||
|===
|
||||
| Type
|
||||
| Type conversion
|
||||
| Sample
|
||||
|
||||
| `String`
|
||||
| native
|
||||
| `{"firstname" : "Dave"}`
|
||||
|
||||
| `double`, `Double`, `float`, `Float`
|
||||
| native
|
||||
| `{"weight" : 42.5}`
|
||||
|
||||
| `int`, `Integer`, `short`, `Short`
|
||||
| native +
|
||||
32-bit integer
|
||||
| `{"height" : 42}`
|
||||
|
||||
| `long`, `Long`
|
||||
| native +
|
||||
64-bit integer
|
||||
| `{"height" : 42}`
|
||||
|
||||
| `Date`, `Timestamp`
|
||||
| native
|
||||
| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}`
|
||||
|
||||
| `byte[]`
|
||||
| native
|
||||
| `{"bin" : { "$binary" : "AQIDBA==", "$type" : "00" }}`
|
||||
|
||||
| `java.util.UUID` (Legacy UUID)
|
||||
| native
|
||||
| `{"uuid" : { "$binary" : "MEaf1CFQ6lSphaa3b9AtlA==", "$type" : "03" }}`
|
||||
|
||||
| `Date`
|
||||
| native
|
||||
| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}`
|
||||
|
||||
| `ObjectId`
|
||||
| native
|
||||
| `{"_id" : ObjectId("5707a2690364aba3136ab870")}`
|
||||
|
||||
| Array, `List`, `BasicDBList`
|
||||
| native
|
||||
| `{"cookies" : [ … ]}`
|
||||
|
||||
| `boolean`, `Boolean`
|
||||
| native
|
||||
| `{"active" : true}`
|
||||
|
||||
| `null`
|
||||
| native
|
||||
| `{"value" : null}`
|
||||
|
||||
| `DBObject`
|
||||
| native
|
||||
| `{"value" : { … }}`
|
||||
|
||||
| `Decimal128`
|
||||
| native
|
||||
| `{"value" : NumberDecimal(…)}`
|
||||
|
||||
| `AtomicInteger` +
|
||||
calling `get()` before the actual conversion
|
||||
| converter +
|
||||
32-bit integer
|
||||
| `{"value" : "741" }`
|
||||
|
||||
| `AtomicLong` +
|
||||
calling `get()` before the actual conversion
|
||||
| converter +
|
||||
64-bit integer
|
||||
| `{"value" : "741" }`
|
||||
|
||||
| `BigInteger`
|
||||
| converter +
|
||||
`String`
|
||||
| `{"value" : "741" }`
|
||||
|
||||
| `BigDecimal`
|
||||
| converter +
|
||||
`String`
|
||||
| `{"value" : "741.99" }`
|
||||
|
||||
| `URL`
|
||||
| converter
|
||||
| `{"website" : "http://projects.spring.io/spring-data-mongodb/" }`
|
||||
|
||||
| `Locale`
|
||||
| converter
|
||||
| `{"locale : "en_US" }`
|
||||
|
||||
| `char`, `Character`
|
||||
| converter
|
||||
| `{"char" : "a" }`
|
||||
|
||||
| `NamedMongoScript`
|
||||
| converter +
|
||||
`Code`
|
||||
| `{"_id" : "script name", value: (some javascript code)`}
|
||||
|
||||
| `java.util.Currency`
|
||||
| converter
|
||||
| `{"currencyCode" : "EUR"}`
|
||||
|
||||
| `LocalDate` +
|
||||
(Joda, Java 8, JSR310-BackPort)
|
||||
| converter
|
||||
| `{"date" : ISODate("2019-11-12T00:00:00.000Z")}`
|
||||
|
||||
| `LocalDateTime`, `LocalTime`, `Instant` +
|
||||
(Joda, Java 8, JSR310-BackPort)
|
||||
| converter
|
||||
| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}`
|
||||
|
||||
| `DateTime` (Joda)
|
||||
| converter
|
||||
| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}`
|
||||
|
||||
| `DateMidnight` (Joda)
|
||||
| converter
|
||||
| `{"date" : ISODate("2019-11-12T00:00:00.000Z")}`
|
||||
|
||||
| `ZoneId` (Java 8, JSR310-BackPort)
|
||||
| converter
|
||||
| `{"zoneId" : "ECT - Europe/Paris"}`
|
||||
|
||||
| `Box`
|
||||
| converter
|
||||
| `{"box" : { "first" : { "x" : 1.0 , "y" : 2.0} , "second" : { "x" : 3.0 , "y" : 4.0}}`
|
||||
|
||||
| `Polygon`
|
||||
| converter
|
||||
| `{"polygon" : { "points" : [ { "x" : 1.0 , "y" : 2.0} , { "x" : 3.0 , "y" : 4.0} , { "x" : 4.0 , "y" : 5.0}]}}`
|
||||
|
||||
| `Circle`
|
||||
| converter
|
||||
| `{"circle" : { "center" : { "x" : 1.0 , "y" : 2.0} , "radius" : 3.0 , "metric" : "NEUTRAL"}}`
|
||||
|
||||
| `Point`
|
||||
| converter
|
||||
| `{"point" : { "x" : 1.0 , "y" : 2.0}}`
|
||||
|
||||
| `GeoJsonPoint`
|
||||
| converter
|
||||
| `{"point" : { "type" : "Point" , "coordinates" : [3.0 , 4.0] }}`
|
||||
|
||||
| `GeoJsonMultiPoint`
|
||||
| converter
|
||||
| `{"geoJsonLineString" : {"type":"MultiPoint", "coordinates": [ [ 0 , 0 ], [ 0 , 1 ], [ 1 , 1 ] ] }}`
|
||||
|
||||
| `Sphere`
|
||||
| converter
|
||||
| `{"sphere" : { "center" : { "x" : 1.0 , "y" : 2.0} , "radius" : 3.0 , "metric" : "NEUTRAL"}}`
|
||||
|
||||
| `GeoJsonPolygon`
|
||||
| converter
|
||||
| `{"polygon" : { "type" : "Polygon", "coordinates" : [[ [ 0 , 0 ], [ 3 , 6 ], [ 6 , 1 ], [ 0 , 0 ] ]] }}`
|
||||
|
||||
| `GeoJsonMultiPolygon`
|
||||
| converter
|
||||
| `{"geoJsonMultiPolygon" : { "type" : "MultiPolygon", "coordinates" : [
|
||||
[ [ [ -73.958 , 40.8003 ] , [ -73.9498 , 40.7968 ] ] ],
|
||||
[ [ [ -73.973 , 40.7648 ] , [ -73.9588 , 40.8003 ] ] ]
|
||||
] }}`
|
||||
|
||||
| `GeoJsonLineString`
|
||||
| converter
|
||||
| `{ "geoJsonLineString" : { "type" : "LineString", "coordinates" : [ [ 40 , 5 ], [ 41 , 6 ] ] }}`
|
||||
|
||||
| `GeoJsonMultiLineString`
|
||||
| converter
|
||||
| `{"geoJsonLineString" : { "type" : "MultiLineString", coordinates: [
|
||||
[ [ -73.97162 , 40.78205 ], [ -73.96374 , 40.77715 ] ],
|
||||
[ [ -73.97880 , 40.77247 ], [ -73.97036 , 40.76811 ] ]
|
||||
] }}`
|
||||
|===
|
||||
|
||||
|
||||
[[mapping-configuration]]
|
||||
== Mapping Configuration
|
||||
|
||||
Unless explicitly configured, an instance of `MongoMappingConverter` is created by default when creating a `MongoTemplate`. You can create your own instance of the `MappingMongoConverter` so as to tell it where to scan the classpath at startup your domain classes in order to extract metadata and construct indexes. Also, by creating your own instance you can register Spring converters to use for mapping specific classes to and from the database.
|
||||
Unless explicitly configured, an instance of `MappingMongoConverter` is created by default when creating a `MongoTemplate`. You can create your own instance of the `MappingMongoConverter` so as to tell it where to scan the classpath at startup your domain classes in order to extract metadata and construct indexes. Also, by creating your own instance you can register Spring converters to use for mapping specific classes to and from the database.
|
||||
|
||||
You can configure the `MongoMappingConverter` as well as `com.mongodb.Mongo` and MongoTemplate either using Java or XML based metadata. Here is an example using Spring's Java based configuration
|
||||
You can configure the `MappingMongoConverter` as well as `com.mongodb.Mongo` and MongoTemplate either using Java or XML based metadata. Here is an example using Spring's Java based configuration
|
||||
|
||||
.@Configuration class to configure MongoDB mapping support
|
||||
====
|
||||
@@ -108,11 +296,11 @@ public class GeoSpatialAppConfig extends AbstractMongoConfiguration {
|
||||
----
|
||||
====
|
||||
|
||||
`AbstractMongoConfiguration` requires you to implement methods that define a `com.mongodb.Mongo` as well as provide a database name. `AbstractMongoConfiguration` also has a method you can override named '`getMappingBasePackage`' which tells the converter where to scan for classes annotated with the `@org.springframework.data.mongodb.core.mapping.Document` annotation.
|
||||
`AbstractMongoConfiguration` requires you to implement methods that define a `com.mongodb.Mongo` as well as provide a database name. `AbstractMongoConfiguration` also has a method you can override named `getMappingBasePackage(…)` which tells the converter where to scan for classes annotated with the `@Document` annotation.
|
||||
|
||||
You can add additional converters to the converter by overriding the method afterMappingMongoConverterCreation. Also shown in the above example is a `LoggingEventListener` which logs `MongoMappingEvent`s that are posted onto Spring's `ApplicationContextEvent` infrastructure.
|
||||
You can add additional converters to the converter by overriding the method afterMappingMongoConverterCreation. Also shown in the above example is a `LoggingEventListener` which logs `MongoMappingEvent` s that are posted onto Spring's `ApplicationContextEvent` infrastructure.
|
||||
|
||||
NOTE: AbstractMongoConfiguration will create a MongoTemplate instance and registered with the container under the name 'mongoTemplate'.
|
||||
NOTE: AbstractMongoConfiguration will create a MongoTemplate instance and registered with the container under the name `mongoTemplate`.
|
||||
|
||||
You can also override the method `UserCredentials getUserCredentials()` to provide the username and password information to connect to the database.
|
||||
|
||||
@@ -165,7 +353,7 @@ The `base-package` property tells it where to scan for classes annotated with th
|
||||
[[mapping-usage]]
|
||||
== Metadata based Mapping
|
||||
|
||||
To take full advantage of the object mapping functionality inside the Spring Data/MongoDB support, you should annotate your mapped objects with the `@org.springframework.data.mongodb.core.mapping.Document` annotation. Although it is not necessary for the mapping framework to have this annotation (your POJOs will be mapped correctly, even without any annotations), it allows the classpath scanner to find and pre-process your domain objects to extract the necessary metadata. If you don't use this annotation, your application will take a slight performance hit the first time you store a domain object because the mapping framework needs to build up its internal metadata model so it knows about the properties of your domain object and how to persist them.
|
||||
To take full advantage of the object mapping functionality inside the Spring Data/MongoDB support, you should annotate your mapped objects with the `@Document` annotation. Although it is not necessary for the mapping framework to have this annotation (your POJOs will be mapped correctly, even without any annotations), it allows the classpath scanner to find and pre-process your domain objects to extract the necessary metadata. If you don't use this annotation, your application will take a slight performance hit the first time you store a domain object because the mapping framework needs to build up its internal metadata model so it knows about the properties of your domain object and how to persist them.
|
||||
|
||||
.Example domain object
|
||||
====
|
||||
@@ -271,7 +459,7 @@ public class Person<T extends Address> {
|
||||
return ssn;
|
||||
}
|
||||
|
||||
// other getters/setters ommitted
|
||||
// other getters/setters omitted
|
||||
----
|
||||
|
||||
[[mapping-custom-object-construction]]
|
||||
@@ -281,7 +469,7 @@ The mapping subsystem allows the customization of the object construction by ann
|
||||
|
||||
* If a parameter is annotated with the `@Value` annotation, the given expression is evaluated and the result is used as the parameter value.
|
||||
* If the Java type has a property whose name matches the given field of the input document, then it's property information is used to select the appropriate constructor parameter to pass the input field value to. This works only if the parameter name information is present in the java `.class` files which can be achieved by compiling the source with debug information or using the new `-parameters` command-line switch for javac in Java 8.
|
||||
* Otherwise an `MappingException` will be thrown indicating that the given constructor parameter could not be bound.
|
||||
* Otherwise a `MappingException` will be thrown indicating that the given constructor parameter could not be bound.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@@ -313,7 +501,7 @@ Additional examples for using the `@PersistenceConstructor` annotation can be fo
|
||||
[[mapping-usage-indexes.compound-index]]
|
||||
=== Compound Indexes
|
||||
|
||||
Compound indexes are also supported. They are defined at the class level, rather than on indidividual properties.
|
||||
Compound indexes are also supported. They are defined at the class level, rather than on individual properties.
|
||||
|
||||
NOTE: Compound indexes are very important to improve the performance of queries that involve criteria on multiple fields
|
||||
|
||||
@@ -346,7 +534,7 @@ public class Person {
|
||||
|
||||
NOTE: The text index feature is disabled by default for mongodb v.2.4.
|
||||
|
||||
Creating a text index allows to accumulate several fields into a searchable full text index. It is only possible to have one text index per collection so all fields marked with `@TextIndexed` are combined into this index. Properties can be weighted to influence document score for ranking results. The default language for the text index is english, to change the default language set `@Document(language="spanish")` to any language you want. Using a property called `language` or `@Language` allows to define a language override on a per document base.
|
||||
Creating a text index allows accumulating several fields into a searchable full text index. It is only possible to have one text index per collection so all fields marked with `@TextIndexed` are combined into this index. Properties can be weighted to influence document score for ranking results. The default language for the text index is english, to change the default language set `@Document(language="spanish")` to any language you want. Using a property called `language` or `@Language` allows to define a language override on a per document base.
|
||||
|
||||
.Example Text Index Usage
|
||||
====
|
||||
@@ -401,7 +589,7 @@ public class Person {
|
||||
----
|
||||
====
|
||||
|
||||
There's no need to use something like `@OneToMany` because the mapping framework sees that you're wanting a one-to-many relationship because there is a List of objects. When the object is stored in MongoDB, there will be a list of DBRefs rather than the `Account` objects themselves.
|
||||
There's no need to use something like `@OneToMany` because the mapping framework sees that you want a one-to-many relationship because there is a List of objects. When the object is stored in MongoDB, there will be a list of DBRefs rather than the `Account` objects themselves.
|
||||
|
||||
IMPORTANT: The mapping framework does not handle cascading saves. If you change an `Account` object that is referenced by a `Person` object, you must save the Account object separately. Calling `save` on the `Person` object will not automatically save the `Account` objects in the property `accounts`.
|
||||
|
||||
@@ -415,7 +603,7 @@ Simply declaring these beans in your Spring ApplicationContext will cause them t
|
||||
[[mapping-explicit-converters]]
|
||||
=== Overriding Mapping with explicit Converters
|
||||
|
||||
When storing and querying your objects it is convenient to have a `MongoConverter` instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the `MongoConverter`'s do most of the work but allow you to selectively handle the conversion for a particular type or to optimize performance.
|
||||
When storing and querying your objects it is convenient to have a `MongoConverter` instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the `MongoConverter` s do most of the work but allow you to selectively handle the conversion for a particular type or to optimize performance.
|
||||
|
||||
To selectively handle the conversion yourself, register one or more one or more `org.springframework.core.convert.converter.Converter` instances with the MongoConverter.
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ This section covers additional things to keep in mind when using the 3.0 driver.
|
||||
|
||||
* `IndexOperations.resetIndexCache()` is no longer supported.
|
||||
* Any `MapReduceOptions.extraOption` is silently ignored.
|
||||
* `WriteResult` does not longer hold error informations but throws an Exception.
|
||||
* `WriteResult` does not longer hold error information but throws an Exception.
|
||||
* `MongoOperations.executeInSession(…)` no longer calls `requestStart` / `requestDone`.
|
||||
* Index name generation has become a driver internal operations, still we use the 2.x schema to generate names.
|
||||
* Some Exception messages differ between the generation 2 and 3 servers as well as between _MMap.v1_ and _WiredTiger_ storage engine.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user