Compare commits
23 Commits
1.2.1.RELE
...
1.2.2.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b29930b512 | ||
|
|
d671fb13ae | ||
|
|
b0a10d19c3 | ||
|
|
d8ef7e1472 | ||
|
|
b9a25eabae | ||
|
|
e92e5c737f | ||
|
|
6e46fb12cb | ||
|
|
031d446a1c | ||
|
|
e6bab1ce60 | ||
|
|
2fffe0a5c4 | ||
|
|
2493de5f91 | ||
|
|
bd11bab076 | ||
|
|
b667984563 | ||
|
|
7ef167ed96 | ||
|
|
303a057d86 | ||
|
|
607072c0d3 | ||
|
|
11e9c562b3 | ||
|
|
220b211faa | ||
|
|
c0c51fcc29 | ||
|
|
ed9eddf10e | ||
|
|
e23d73d55e | ||
|
|
9627fbaebf | ||
|
|
ef93d4db0b |
@@ -73,7 +73,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
@@ -102,7 +102,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
@@ -124,7 +124,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
@@ -135,9 +135,9 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
@@ -150,12 +150,12 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
@@ -182,11 +182,11 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
@@ -237,7 +237,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
@@ -251,12 +251,12 @@
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
|
||||
11
pom.xml
11
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<version>1.2.2.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -29,7 +29,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>1.5.1.RELEASE</springdata.commons>
|
||||
<springdata.commons>1.5.2.BUILD-SNAPSHOT</springdata.commons>
|
||||
<mongo>2.10.1</mongo>
|
||||
</properties>
|
||||
|
||||
@@ -89,4 +89,11 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-snapshot</id>
|
||||
<url>http://repo.springsource.org/libs-snapshot-local</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<version>1.2.2.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<version>1.2.2.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<version>1.2.2.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ An example log entry might look like:
|
||||
{
|
||||
"_id" : ObjectId("4d89341a8ef397e06940d5cd"),
|
||||
"applicationId" : "my.application",
|
||||
"name" : "org.springframework.data.mongodb.log4j.AppenderTest",
|
||||
"name" : "org.springframework.data.mongodb.log4j.MongoLog4jAppenderIntegrationTests",
|
||||
"level" : "DEBUG",
|
||||
"timestamp" : ISODate("2011-03-23T16:53:46.778Z"),
|
||||
"properties" : {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<version>1.2.2.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* Copyright 2011-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.
|
||||
* 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,
|
||||
@@ -13,63 +13,65 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.log4j;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Calendar;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.Mongo;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.MDC;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class AppenderTest {
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
private static final String NAME = AppenderTest.class.getName();
|
||||
private Logger log = Logger.getLogger(NAME);
|
||||
private Mongo mongo;
|
||||
private DB db;
|
||||
private String collection;
|
||||
/**
|
||||
* Integration tests for {@link MongoLog4jAppender}.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MongoLog4jAppenderIntegrationTests {
|
||||
|
||||
static final String NAME = MongoLog4jAppenderIntegrationTests.class.getName();
|
||||
|
||||
Logger log = Logger.getLogger(NAME);
|
||||
Mongo mongo;
|
||||
DB db;
|
||||
String collection;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
try {
|
||||
mongo = new Mongo("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();
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
public void setUp() throws Exception {
|
||||
|
||||
mongo = new Mongo("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();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogging() {
|
||||
|
||||
log.debug("DEBUG message");
|
||||
log.info("INFO message");
|
||||
log.warn("WARN message");
|
||||
log.error("ERROR message");
|
||||
|
||||
DBCursor msgs = db.getCollection(collection).find();
|
||||
assertThat(msgs.count(), is(4));
|
||||
|
||||
assertThat(msgs.count(), is(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperties() {
|
||||
|
||||
MDC.put("property", "one");
|
||||
log.debug("DEBUG message");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,11 +10,4 @@ log4j.appender.stdout.collectionPattern = %X{year}%X{month}
|
||||
log4j.appender.stdout.applicationId = my.application
|
||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE
|
||||
|
||||
log4j.category.org.apache.activemq=ERROR
|
||||
log4j.category.org.springframework.batch=DEBUG
|
||||
log4j.category.org.springframework.data.document.mongodb=DEBUG
|
||||
log4j.category.org.springframework.transaction=INFO
|
||||
|
||||
log4j.category.org.hibernate.SQL=DEBUG
|
||||
# for debugging datasource initialization
|
||||
# log4j.category.test.jdbc=DEBUG
|
||||
log4j.category.org.springframework.data.mongodb=DEBUG
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<version>1.2.2.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -134,7 +134,6 @@ public abstract class AbstractMongoConfiguration {
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
||||
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
|
||||
mappingContext.initialize();
|
||||
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
|
||||
indexHelperBuilder.addConstructorArgReference(ctxRef);
|
||||
indexHelperBuilder.addConstructorArgReference(dbFactoryRef);
|
||||
indexHelperBuilder.addDependsOn(ctxRef);
|
||||
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
|
||||
INDEX_HELPER));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-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.
|
||||
@@ -31,6 +31,7 @@ import com.mongodb.ServerAddress;
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
@@ -43,6 +44,11 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
||||
@Override
|
||||
public void setAsText(String replicaSetString) {
|
||||
|
||||
if (!StringUtils.hasText(replicaSetString)) {
|
||||
setValue(null);
|
||||
return;
|
||||
}
|
||||
|
||||
String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString);
|
||||
Set<ServerAddress> serverAddresses = new HashSet<ServerAddress>(replicaSetStringArray.length);
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -24,6 +26,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoOptions;
|
||||
@@ -36,6 +39,7 @@ import com.mongodb.WriteConcern;
|
||||
* @author Thomas Risberg
|
||||
* @author Graeme Rocher
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, DisposableBean,
|
||||
@@ -57,11 +61,38 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
}
|
||||
|
||||
public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
|
||||
this.replicaSetSeeds = Arrays.asList(replicaSetSeeds);
|
||||
this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
|
||||
*
|
||||
* @param replicaPair
|
||||
*/
|
||||
@Deprecated
|
||||
public void setReplicaPair(ServerAddress[] replicaPair) {
|
||||
this.replicaPair = Arrays.asList(replicaPair);
|
||||
this.replicaPair = filterNonNullElementsAsList(replicaPair);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param elements the elements to filter <T>
|
||||
* @return a new unmodifiable {@link List#} from the given elements without nulls
|
||||
*/
|
||||
private <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||
|
||||
if (elements == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> candidateElements = new ArrayList<T>();
|
||||
|
||||
for (T element : elements) {
|
||||
if (element != null) {
|
||||
candidateElements.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(candidateElements);
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
@@ -126,15 +157,15 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
mongoOptions = new MongoOptions();
|
||||
}
|
||||
|
||||
if (replicaPair != null) {
|
||||
if (!isNullOrEmpty(replicaPair)) {
|
||||
if (replicaPair.size() < 2) {
|
||||
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
|
||||
}
|
||||
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
|
||||
} else if (replicaSetSeeds != null) {
|
||||
} else if (!isNullOrEmpty(replicaSetSeeds)) {
|
||||
mongo = new Mongo(replicaSetSeeds, mongoOptions);
|
||||
} else {
|
||||
String mongoHost = host != null ? host : defaultOptions.getHost();
|
||||
String mongoHost = StringUtils.hasText(host) ? host : defaultOptions.getHost();
|
||||
mongo = port != null ? new Mongo(new ServerAddress(mongoHost, port), mongoOptions) : new Mongo(mongoHost,
|
||||
mongoOptions);
|
||||
}
|
||||
@@ -146,6 +177,10 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
this.mongo = mongo;
|
||||
}
|
||||
|
||||
private boolean isNullOrEmpty(Collection<?> elements) {
|
||||
return elements == null || elements.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
|
||||
@@ -247,7 +247,7 @@ public interface MongoOperations {
|
||||
* Query for a list of objects of type T from the collection used by the entity class.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
|
||||
* to map objects since the test for class type is done in the client and not on the server.
|
||||
@@ -261,7 +261,7 @@ public interface MongoOperations {
|
||||
* Query for a list of objects of type T from the specified collection.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
|
||||
* to map objects since the test for class type is done in the client and not on the server.
|
||||
@@ -382,7 +382,7 @@ public interface MongoOperations {
|
||||
* specified type.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
@@ -399,7 +399,7 @@ public interface MongoOperations {
|
||||
* type.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
@@ -417,7 +417,7 @@ public interface MongoOperations {
|
||||
* Map the results of an ad-hoc query on the collection for the entity class to a List of the specified type.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
@@ -433,7 +433,7 @@ public interface MongoOperations {
|
||||
* Map the results of an ad-hoc query on the specified collection to a List of the specified type.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
@@ -501,7 +501,7 @@ public interface MongoOperations {
|
||||
* type. The first document that matches the query is returned and also removed from the collection in the database.
|
||||
* <p/>
|
||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
@@ -555,7 +555,7 @@ public interface MongoOperations {
|
||||
* Insert the object into the specified collection.
|
||||
* <p/>
|
||||
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* Insert is used to initially store the object into the database. To update an existing object use the save method.
|
||||
*
|
||||
@@ -593,7 +593,7 @@ public interface MongoOperations {
|
||||
* object is not already present, that is an 'upsert'.
|
||||
* <p/>
|
||||
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
||||
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
||||
@@ -610,7 +610,7 @@ public interface MongoOperations {
|
||||
* is an 'upsert'.
|
||||
* <p/>
|
||||
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
||||
* configured otherwise, an instance of SimpleMongoConverter will be used.
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
||||
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
|
||||
@@ -734,4 +734,4 @@ public interface MongoOperations {
|
||||
* @return
|
||||
*/
|
||||
MongoConverter getConverter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +797,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
@@ -810,7 +809,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
writer.write(objectToSave, dbDoc);
|
||||
} else {
|
||||
try {
|
||||
objectToSave = (T) JSON.parse((String) objectToSave);
|
||||
dbDoc = (DBObject) JSON.parse((String) objectToSave);
|
||||
} catch (JSONParseException e) {
|
||||
throw new MappingException("Could not parse given String to save into a JSON document!", e);
|
||||
}
|
||||
@@ -1307,8 +1306,8 @@ 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}. Unless configured
|
||||
* otherwise, an instance of SimpleMongoConverter will be used. The query document is specified as a standard DBObject
|
||||
* and so is the fields specification. Can be overridden by subclasses.
|
||||
* otherwise, an instance of MappingMongoConverter will be used. The query document is specified as a standard
|
||||
* DBObject and so is the fields specification. Can be overridden by subclasses.
|
||||
*
|
||||
* @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
|
||||
@@ -1409,19 +1408,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
DBObject updateObj = update.getUpdateObject();
|
||||
for (String key : updateObj.keySet()) {
|
||||
updateObj.put(key, mongoConverter.convertToMongoType(updateObj.get(key)));
|
||||
}
|
||||
|
||||
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), entity);
|
||||
DBObject mappedQuery = mapper.getMappedObject(query, entity);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("findAndModify using query: " + mappedQuery + " fields: " + fields + " sort: " + sort
|
||||
+ " for class: " + entityClass + " and update: " + updateObj + " in collection: " + collectionName);
|
||||
+ " for class: " + entityClass + " and update: " + mappedUpdate + " in collection: " + collectionName);
|
||||
}
|
||||
|
||||
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, updateObj, options),
|
||||
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
|
||||
new ReadDbObjectCallback<T>(readerToUse, entityClass), collectionName);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,11 @@ package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@@ -63,6 +65,7 @@ public class CustomConversions {
|
||||
private final Set<ConvertiblePair> writingPairs;
|
||||
private final Set<Class<?>> customSimpleTypes;
|
||||
private final SimpleTypeHolder simpleTypeHolder;
|
||||
private final Map<Class<?>, HashMap<Class<?>, CacheValue>> cache;
|
||||
|
||||
private final List<Object> converters;
|
||||
|
||||
@@ -85,6 +88,7 @@ public class CustomConversions {
|
||||
this.readingPairs = new HashSet<ConvertiblePair>();
|
||||
this.writingPairs = new HashSet<ConvertiblePair>();
|
||||
this.customSimpleTypes = new HashSet<Class<?>>();
|
||||
this.cache = new HashMap<Class<?>, HashMap<Class<?>, CacheValue>>();
|
||||
|
||||
this.converters = new ArrayList<Object>();
|
||||
this.converters.add(CustomToStringConverter.INSTANCE);
|
||||
@@ -268,9 +272,11 @@ public class CustomConversions {
|
||||
* @return
|
||||
*/
|
||||
public boolean hasCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
|
||||
|
||||
Assert.notNull(source);
|
||||
Assert.notNull(expectedTargetType);
|
||||
return getCustomTarget(source, expectedTargetType, readingPairs) != null;
|
||||
|
||||
return getCustomReadTarget(source, expectedTargetType) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,8 +305,32 @@ public class CustomConversions {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Class<?> getCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
|
||||
|
||||
Class<?> type = expectedTargetType == null ? PlaceholderType.class : expectedTargetType;
|
||||
|
||||
Map<Class<?>, CacheValue> map;
|
||||
CacheValue toReturn;
|
||||
|
||||
if ((map = cache.get(source)) == null || (toReturn = map.get(type)) == null) {
|
||||
|
||||
Class<?> target = getCustomTarget(source, type, readingPairs);
|
||||
|
||||
if (cache.get(source) == null) {
|
||||
cache.put(source, new HashMap<Class<?>, CacheValue>());
|
||||
}
|
||||
|
||||
Map<Class<?>, CacheValue> value = cache.get(source);
|
||||
toReturn = target == null ? CacheValue.NULL : new CacheValue(target);
|
||||
value.put(type, toReturn);
|
||||
}
|
||||
|
||||
return toReturn.clazz;
|
||||
}
|
||||
|
||||
@WritingConverter
|
||||
private enum CustomToStringConverter implements GenericConverter {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
@@ -313,4 +343,30 @@ public class CustomConversions {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder type to allow registering not-found values in the converter cache.
|
||||
*
|
||||
* @author Patryk Wasik
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class PlaceholderType {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to safely store {@literal null} values in the type cache.
|
||||
*
|
||||
* @author Patryk Wasik
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class CacheValue {
|
||||
|
||||
public static final CacheValue NULL = new CacheValue(null);
|
||||
private final Class<?> clazz;
|
||||
|
||||
public CacheValue(Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,10 +238,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
||||
|
||||
boolean isConstructorProperty = entity.isConstructorArgument(prop);
|
||||
boolean hasValueForProperty = dbo.containsField(prop.getFieldName());
|
||||
|
||||
if (!hasValueForProperty || isConstructorProperty) {
|
||||
if (!dbo.containsField(prop.getFieldName()) || entity.isConstructorArgument(prop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
@@ -41,6 +42,7 @@ import com.mongodb.DBRef;
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public class QueryMapper {
|
||||
|
||||
@@ -83,11 +85,22 @@ public class QueryMapper {
|
||||
|
||||
for (String key : query.keySet()) {
|
||||
|
||||
MongoPersistentProperty targetProperty = getTargetProperty(key, entity);
|
||||
String newKey = determineKey(key, entity);
|
||||
Object value = query.get(key);
|
||||
if (Keyword.isKeyword(key)) {
|
||||
result.putAll(getMappedKeyword(new Keyword(query, key), entity));
|
||||
continue;
|
||||
}
|
||||
|
||||
result.put(newKey, getMappedValue(value, targetProperty, newKey));
|
||||
Field field = entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext);
|
||||
|
||||
Object rawValue = query.get(key);
|
||||
String newKey = field.getMappedKey();
|
||||
|
||||
if (Keyword.isKeyword(rawValue) && !field.isIdField()) {
|
||||
Keyword keyword = new Keyword((DBObject) rawValue);
|
||||
result.put(newKey, getMappedKeyword(field, keyword));
|
||||
} else {
|
||||
result.put(newKey, getMappedValue(field, query.get(key)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -103,13 +116,14 @@ public class QueryMapper {
|
||||
private DBObject getMappedKeyword(Keyword query, MongoPersistentEntity<?> entity) {
|
||||
|
||||
// $or/$nor
|
||||
if (query.key.matches(N_OR_PATTERN)) {
|
||||
if (query.key.matches(N_OR_PATTERN) || query.value instanceof Iterable) {
|
||||
|
||||
Iterable<?> conditions = (Iterable<?>) query.value;
|
||||
BasicDBList newConditions = new BasicDBList();
|
||||
|
||||
for (Object condition : conditions) {
|
||||
newConditions.add(getMappedObject((DBObject) condition, entity));
|
||||
newConditions.add(condition instanceof DBObject ? getMappedObject((DBObject) condition, entity)
|
||||
: convertSimpleOrDBObject(condition, entity));
|
||||
}
|
||||
|
||||
return new BasicDBObject(query.key, newConditions);
|
||||
@@ -121,38 +135,34 @@ public class QueryMapper {
|
||||
/**
|
||||
* Returns the mapped keyword considered defining a criteria for the given property.
|
||||
*
|
||||
* @param keyword
|
||||
* @param property
|
||||
* @param keyword
|
||||
* @return
|
||||
*/
|
||||
public DBObject getMappedKeyword(Keyword keyword, MongoPersistentProperty property) {
|
||||
private DBObject getMappedKeyword(Field property, Keyword keyword) {
|
||||
|
||||
if (property.isAssociation()) {
|
||||
convertAssociation(keyword.value, property);
|
||||
}
|
||||
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
|
||||
Object value = needsAssociationConversion ? convertAssociation(keyword.value, property.getProperty())
|
||||
: getMappedValue(property.with(keyword.key), keyword.value);
|
||||
|
||||
return new BasicDBObject(keyword.key, getMappedValue(keyword.value, property, keyword.key));
|
||||
return new BasicDBObject(keyword.key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapped value for the given source object assuming it's a value for the given
|
||||
* {@link MongoPersistentProperty}.
|
||||
*
|
||||
* @param source the source object to be mapped
|
||||
* @param value the source object to be mapped
|
||||
* @param property the property the value is a value for
|
||||
* @param newKey the key the value will be bound to eventually
|
||||
* @return
|
||||
*/
|
||||
private Object getMappedValue(Object source, MongoPersistentProperty property, String newKey) {
|
||||
private Object getMappedValue(Field documentField, Object value) {
|
||||
|
||||
if (property == null) {
|
||||
return convertSimpleOrDBObject(source, null);
|
||||
}
|
||||
if (documentField.isIdField()) {
|
||||
|
||||
if (property.isIdProperty() || "_id".equals(newKey)) {
|
||||
|
||||
if (source instanceof DBObject) {
|
||||
DBObject valueDbo = (DBObject) source;
|
||||
if (value instanceof DBObject) {
|
||||
DBObject valueDbo = (DBObject) value;
|
||||
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
|
||||
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
|
||||
List<Object> ids = new ArrayList<Object>();
|
||||
@@ -163,67 +173,25 @@ public class QueryMapper {
|
||||
} else if (valueDbo.containsField("$ne")) {
|
||||
valueDbo.put("$ne", convertId(valueDbo.get("$ne")));
|
||||
} else {
|
||||
return getMappedObject((DBObject) source, null);
|
||||
return getMappedObject((DBObject) value, null);
|
||||
}
|
||||
|
||||
return valueDbo;
|
||||
|
||||
} else {
|
||||
return convertId(source);
|
||||
return convertId(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (property.isAssociation()) {
|
||||
return Keyword.isKeyword(source) ? getMappedKeyword(new Keyword(source), property) : convertAssociation(source,
|
||||
property);
|
||||
if (Keyword.isKeyword(value)) {
|
||||
return getMappedKeyword(new Keyword((DBObject) value), null);
|
||||
}
|
||||
|
||||
return convertSimpleOrDBObject(source, mappingContext.getPersistentEntity(property));
|
||||
}
|
||||
|
||||
private MongoPersistentProperty getTargetProperty(String key, MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (isIdKey(key, entity)) {
|
||||
return entity.getIdProperty();
|
||||
if (documentField.isAssociation()) {
|
||||
return convertAssociation(value, documentField.getProperty());
|
||||
}
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(key, entity);
|
||||
return path == null ? null : path.getLeafProperty();
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<MongoPersistentProperty> getPath(String key, MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
PropertyPath path = PropertyPath.from(key, entity.getTypeInformation());
|
||||
return mappingContext.getPersistentPropertyPath(path);
|
||||
} catch (PropertyReferenceException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translated key assuming the given one is a propert (path) reference.
|
||||
*
|
||||
* @param key the source key
|
||||
* @param entity the base entity
|
||||
* @return the translated key
|
||||
*/
|
||||
private String determineKey(String key, MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (entity == null) {
|
||||
return key;
|
||||
}
|
||||
|
||||
if (!entity.hasIdProperty() && DEFAULT_ID_NAMES.contains(key)) {
|
||||
return "_id";
|
||||
}
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(key, entity);
|
||||
return path == null ? key : path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE);
|
||||
return convertSimpleOrDBObject(value, documentField.getPropertyEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +215,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given source assuming it's actually an association to anoter object.
|
||||
* Converts the given source assuming it's actually an association to another object.
|
||||
*
|
||||
* @param source
|
||||
* @param property
|
||||
@@ -267,31 +235,19 @@ public class QueryMapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (property.isMap()) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
DBObject dbObject = (DBObject) source;
|
||||
for (String key : dbObject.keySet()) {
|
||||
Object o = dbObject.get(key);
|
||||
result.put(key, o instanceof DBRef ? o : converter.toDBRef(o, property));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return source == null || source instanceof DBRef ? source : converter.toDBRef(source, property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given key will be considered an id key.
|
||||
*
|
||||
* @param key
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
private boolean isIdKey(String key, MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (entity == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if (idProperty != null) {
|
||||
return idProperty.getName().equals(key) || idProperty.getFieldName().equals(key);
|
||||
}
|
||||
|
||||
return DEFAULT_ID_NAMES.contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given raw id value into either {@link ObjectId} or {@link String}.
|
||||
*
|
||||
@@ -319,16 +275,27 @@ public class QueryMapper {
|
||||
String key;
|
||||
Object value;
|
||||
|
||||
Keyword(Object source) {
|
||||
public Keyword(DBObject source, String key) {
|
||||
this.key = key;
|
||||
this.value = source.get(key);
|
||||
}
|
||||
|
||||
Assert.isInstanceOf(DBObject.class, source);
|
||||
public Keyword(DBObject dbObject) {
|
||||
|
||||
DBObject value = (DBObject) source;
|
||||
Set<String> keys = dbObject.keySet();
|
||||
Assert.isTrue(keys.size() == 1, "Can only use a single value DBObject!");
|
||||
|
||||
Assert.isTrue(value.keySet().size() == 1, "Keyword must have a single key only!");
|
||||
this.key = keys.iterator().next();
|
||||
this.value = dbObject.get(key);
|
||||
}
|
||||
|
||||
this.key = value.keySet().iterator().next();
|
||||
this.value = value.get(key);
|
||||
/**
|
||||
* Returns whether the current keyword is the {@code $exists} keyword.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExists() {
|
||||
return "$exists".equalsIgnoreCase(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +305,11 @@ public class QueryMapper {
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
static boolean isKeyword(Object value) {
|
||||
public static boolean isKeyword(Object value) {
|
||||
|
||||
if (value instanceof String) {
|
||||
return ((String) value).startsWith("$");
|
||||
}
|
||||
|
||||
if (!(value instanceof DBObject)) {
|
||||
return false;
|
||||
@@ -348,4 +319,192 @@ public class QueryMapper {
|
||||
return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to represent a field and its meta-information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class Field {
|
||||
|
||||
private static final String ID_KEY = "_id";
|
||||
|
||||
protected final String name;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Field} without meta-information but the given name.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
*/
|
||||
public Field(String name) {
|
||||
|
||||
Assert.hasText(name, "Name must not be null!");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Field} with the given name.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public Field with(String name) {
|
||||
return new Field(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current field is the id field.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isIdField() {
|
||||
return ID_KEY.equals(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link MongoPersistentProperty} backing the field.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public MongoPersistentProperty getProperty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MongoPersistentEntity} that field is conatined in.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public MongoPersistentEntity<?> getPropertyEntity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the field represents an association.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAssociation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key to be used in the mapped document eventually.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getMappedKey() {
|
||||
return isIdField() ? ID_KEY : name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of {@link Field} to be backed with mapping metadata.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class MetadataBackedField extends Field {
|
||||
|
||||
private final MongoPersistentEntity<?> entity;
|
||||
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||
private final MongoPersistentProperty property;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MetadataBackedField} with the given name, {@link MongoPersistentEntity} and
|
||||
* {@link MappingContext}.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public MetadataBackedField(String name, MongoPersistentEntity<?> entity,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context) {
|
||||
|
||||
super(name);
|
||||
|
||||
Assert.notNull(entity, "MongoPersistentEntity must not be null!");
|
||||
|
||||
this.entity = entity;
|
||||
this.mappingContext = context;
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(name);
|
||||
this.property = path == null ? null : path.getLeafProperty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#with(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public MetadataBackedField with(String name) {
|
||||
return new MetadataBackedField(name, entity, mappingContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#isIdKey()
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdField() {
|
||||
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if (idProperty != null) {
|
||||
return idProperty.getName().equals(name) || idProperty.getFieldName().equals(name);
|
||||
}
|
||||
|
||||
return DEFAULT_ID_NAMES.contains(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#getProperty()
|
||||
*/
|
||||
@Override
|
||||
public MongoPersistentProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#getEntity()
|
||||
*/
|
||||
@Override
|
||||
public MongoPersistentEntity<?> getPropertyEntity() {
|
||||
MongoPersistentProperty property = getProperty();
|
||||
return property == null ? null : mappingContext.getPersistentEntity(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#isAssociation()
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
|
||||
MongoPersistentProperty property = getProperty();
|
||||
return property == null ? false : property.isAssociation();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#getTargetKey()
|
||||
*/
|
||||
@Override
|
||||
public String getMappedKey() {
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(name);
|
||||
return path == null ? name : path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE);
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<MongoPersistentProperty> getPath(String name) {
|
||||
|
||||
try {
|
||||
PropertyPath path = PropertyPath.from(name, entity.getTypeInformation());
|
||||
return mappingContext.getPersistentPropertyPath(path);
|
||||
} catch (PropertyReferenceException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2010-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.
|
||||
@@ -18,14 +18,15 @@ package org.springframework.data.mongodb.core.query;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
public class Field {
|
||||
|
||||
private Map<String, Integer> criteria = new HashMap<String, Integer>();
|
||||
|
||||
private Map<String, Object> slices = new HashMap<String, Object>();
|
||||
private final Map<String, Integer> criteria = new HashMap<String, Integer>();
|
||||
private final Map<String, Object> slices = new HashMap<String, Object>();
|
||||
|
||||
public Field include(String key) {
|
||||
criteria.put(key, Integer.valueOf(1));
|
||||
@@ -50,11 +51,54 @@ public class Field {
|
||||
public DBObject getFieldsObject() {
|
||||
DBObject dbo = new BasicDBObject();
|
||||
for (String k : criteria.keySet()) {
|
||||
dbo.put(k, (criteria.get(k)));
|
||||
dbo.put(k, criteria.get(k));
|
||||
}
|
||||
for (String k : slices.keySet()) {
|
||||
dbo.put(k, new BasicDBObject("$slice", (slices.get(k))));
|
||||
dbo.put(k, new BasicDBObject("$slice", slices.get(k)));
|
||||
}
|
||||
return dbo;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(object instanceof Field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Field that = (Field) object;
|
||||
|
||||
if (!this.criteria.equals(that.criteria)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.slices.equals(that.slices)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(this.criteria);
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(this.slices);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,22 +217,23 @@ public class Update {
|
||||
return dbo;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void addMultiFieldOperation(String operator, String key, Object value) {
|
||||
|
||||
Object existingValue = this.modifierOps.get(operator);
|
||||
LinkedHashMap<String, Object> keyValueMap;
|
||||
DBObject keyValueMap;
|
||||
|
||||
if (existingValue == null) {
|
||||
keyValueMap = new LinkedHashMap<String, Object>();
|
||||
keyValueMap = new BasicDBObject();
|
||||
this.modifierOps.put(operator, keyValueMap);
|
||||
} else {
|
||||
if (existingValue instanceof LinkedHashMap) {
|
||||
keyValueMap = (LinkedHashMap<String, Object>) existingValue;
|
||||
if (existingValue instanceof BasicDBObject) {
|
||||
keyValueMap = (BasicDBObject) existingValue;
|
||||
} else {
|
||||
throw new InvalidDataAccessApiUsageException("Modifier Operations should be a LinkedHashMap but was "
|
||||
+ existingValue.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
keyValueMap.put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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,19 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.monitor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import org.springframework.jmx.export.annotation.ManagedMetric;
|
||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.jmx.support.MetricType;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
/**
|
||||
* Expose basic server information via JMX
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@ManagedResource(description = "Server Information")
|
||||
public class ServerInfo extends AbstractMonitor {
|
||||
@@ -36,9 +37,20 @@ public class ServerInfo extends AbstractMonitor {
|
||||
this.mongo = mongo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the used server reported by mongo.
|
||||
*
|
||||
* @return the reported hostname can also be an IP address.
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
@ManagedOperation(description = "Server host name")
|
||||
public String getHostName() throws UnknownHostException {
|
||||
return InetAddress.getLocalHost().getHostName();
|
||||
|
||||
/*
|
||||
* UnknownHostException is not necessary anymore, but clients could have
|
||||
* called this method in a try..catch(UnknownHostException) already
|
||||
*/
|
||||
return getServerStatus().getServerUsed().getHost();
|
||||
}
|
||||
|
||||
@ManagedMetric(displayName = "Uptime Estimate")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2012 the original author or authors.
|
||||
* Copyright 2010-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.
|
||||
@@ -268,15 +268,16 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
private String toLikeRegex(String source, Type type) {
|
||||
|
||||
switch (type) {
|
||||
case STARTING_WITH:
|
||||
source = source + "*";
|
||||
break;
|
||||
case ENDING_WITH:
|
||||
source = "*" + source;
|
||||
break;
|
||||
case CONTAINING:
|
||||
source = "*" + source + "*";
|
||||
break;
|
||||
case STARTING_WITH:
|
||||
source = "^" + source;
|
||||
break;
|
||||
case ENDING_WITH:
|
||||
source = source + "$";
|
||||
break;
|
||||
case CONTAINING:
|
||||
source = "*" + source + "*";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return source.replaceAll("\\*", ".*");
|
||||
|
||||
@@ -19,8 +19,13 @@ import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
@@ -63,6 +68,17 @@ public class AbstractMongoConfigurationUnitTests {
|
||||
assertScanningDisabled(" ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lifecycleCallbacksAreInvokedInAppropriateOrder() {
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SampleMongoConfiguration.class);
|
||||
MongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);
|
||||
BasicMongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(Entity.class);
|
||||
StandardEvaluationContext spElContext = (StandardEvaluationContext) ReflectionTestUtils.getField(entity, "context");
|
||||
|
||||
assertThat(spElContext.getBeanResolver(), is(notNullValue()));
|
||||
}
|
||||
|
||||
private static void assertScanningDisabled(final String value) throws ClassNotFoundException {
|
||||
|
||||
AbstractMongoConfiguration configuration = new SampleMongoConfiguration() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
@@ -31,6 +31,7 @@ import com.mongodb.ServerAddress;
|
||||
* Unit tests for {@link ServerAddressPropertyEditor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class ServerAddressPropertyEditorUnitTests {
|
||||
|
||||
@@ -70,6 +71,16 @@ public class ServerAddressPropertyEditorUnitTests {
|
||||
assertSingleAddressOfLocalhost(editor.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-693
|
||||
*/
|
||||
@Test
|
||||
public void interpretEmptyStringAsNull() {
|
||||
|
||||
editor.setAsText("");
|
||||
assertNull(editor.getValue());
|
||||
}
|
||||
|
||||
private static void assertSingleAddressOfLocalhost(Object result) throws UnknownHostException {
|
||||
|
||||
assertThat(result, is(instanceOf(ServerAddress[].class)));
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.mongodb.WriteConcern;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class StringToWriteConcernConverterUnitTest {
|
||||
public class StringToWriteConcernConverterUnitTests {
|
||||
|
||||
StringToWriteConcernConverter converter = new StringToWriteConcernConverter();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
@@ -21,17 +21,21 @@ import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.data.mongodb.config.ServerAddressPropertyEditor;
|
||||
import org.springframework.data.mongodb.config.WriteConcernPropertyEditor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MongoFactoryBean}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class MongoFactoryBeanIntegrationTest {
|
||||
public class MongoFactoryBeanIntegrationTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-408
|
||||
@@ -49,4 +53,22 @@ public class MongoFactoryBeanIntegrationTest {
|
||||
MongoFactoryBean bean = factory.getBean("&factory", MongoFactoryBean.class);
|
||||
assertThat(ReflectionTestUtils.getField(bean, "writeConcern"), is((Object) WriteConcern.SAFE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-693
|
||||
*/
|
||||
@Test
|
||||
public void createMongoInstanceWithHostAndEmptyReplicaSets() {
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition(MongoFactoryBean.class);
|
||||
definition.getPropertyValues().addPropertyValue("host", "localhost");
|
||||
definition.getPropertyValues().addPropertyValue("replicaPair", "");
|
||||
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
factory.registerCustomEditor(ServerAddress.class, ServerAddressPropertyEditor.class);
|
||||
factory.registerBeanDefinition("factory", definition);
|
||||
|
||||
Mongo mongo = factory.getBean(Mongo.class);
|
||||
assertNotNull(mongo);
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ import org.springframework.data.mongodb.core.index.Index;
|
||||
import org.springframework.data.mongodb.core.index.Index.Duplicates;
|
||||
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.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
@@ -87,20 +88,18 @@ import com.mongodb.WriteResult;
|
||||
* @author Thomas Risberg
|
||||
* @author Amol Nayak
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
public class MongoTemplateTests {
|
||||
|
||||
@Autowired
|
||||
MongoTemplate template;
|
||||
@Autowired
|
||||
MongoDbFactory factory;
|
||||
@Autowired MongoTemplate template;
|
||||
@Autowired MongoDbFactory factory;
|
||||
|
||||
MongoTemplate mappingTemplate;
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
@Rule public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Autowired
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -150,6 +149,8 @@ public class MongoTemplateTests {
|
||||
template.dropCollection(TestClass.class);
|
||||
template.dropCollection(Sample.class);
|
||||
template.dropCollection(MyPerson.class);
|
||||
template.dropCollection(TypeWithFieldAnnotation.class);
|
||||
template.dropCollection(TypeWithDate.class);
|
||||
template.dropCollection("collection");
|
||||
template.dropCollection("personX");
|
||||
}
|
||||
@@ -772,8 +773,7 @@ public class MongoTemplateTests {
|
||||
Query q3 = new Query(Criteria.where("age").in(l1, l2));
|
||||
template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
|
||||
Assert.fail("Should have trown an InvalidDocumentStoreApiUsageException");
|
||||
} catch (InvalidMongoDbApiUsageException e) {
|
||||
}
|
||||
} catch (InvalidMongoDbApiUsageException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1597,6 +1597,77 @@ public class MongoTemplateTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-679
|
||||
*/
|
||||
@Test
|
||||
public void savesJsonStringCorrectly() {
|
||||
|
||||
DBObject dbObject = new BasicDBObject().append("first", "first").append("second", "second");
|
||||
|
||||
template.save(dbObject.toString(), "collection");
|
||||
|
||||
List<DBObject> result = template.findAll(DBObject.class, "collection");
|
||||
assertThat(result.size(), is(1));
|
||||
assertThat(result.get(0).containsField("first"), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-675
|
||||
*/
|
||||
@Test
|
||||
public void updateConsidersMappingAnnotations() {
|
||||
|
||||
TypeWithFieldAnnotation entity = new TypeWithFieldAnnotation();
|
||||
entity.emailAddress = "old";
|
||||
|
||||
template.save(entity);
|
||||
|
||||
Query query = query(where("_id").is(entity.id));
|
||||
Update update = Update.update("emailAddress", "new");
|
||||
|
||||
FindAndModifyOptions options = new FindAndModifyOptions().returnNew(true);
|
||||
TypeWithFieldAnnotation result = template.findAndModify(query, update, options, TypeWithFieldAnnotation.class);
|
||||
assertThat(result.emailAddress, is("new"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-671
|
||||
*/
|
||||
@Test
|
||||
public void findsEntityByDateReference() {
|
||||
|
||||
TypeWithDate entity = new TypeWithDate();
|
||||
entity.date = new Date(System.currentTimeMillis() - 10);
|
||||
template.save(entity);
|
||||
|
||||
Query query = query(where("date").lt(new Date()));
|
||||
List<TypeWithDate> result = template.find(query, TypeWithDate.class);
|
||||
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result.get(0).date, is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-540
|
||||
*/
|
||||
@Test
|
||||
public void findOneAfterUpsertForNonExistingObjectReturnsTheInsertedObject() {
|
||||
|
||||
String idValue = "4711";
|
||||
Query query = new Query(Criteria.where("id").is(idValue));
|
||||
|
||||
String fieldValue = "bubu";
|
||||
Update update = Update.update("field", fieldValue);
|
||||
|
||||
template.upsert(query, update, Sample.class);
|
||||
Sample result = template.findOne(query, Sample.class);
|
||||
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result.field, is(fieldValue));
|
||||
assertThat(result.id, is(idValue));
|
||||
}
|
||||
|
||||
static class MyId {
|
||||
|
||||
String first;
|
||||
@@ -1605,14 +1676,12 @@ public class MongoTemplateTests {
|
||||
|
||||
static class TypeWithMyId {
|
||||
|
||||
@Id
|
||||
MyId id;
|
||||
@Id MyId id;
|
||||
}
|
||||
|
||||
public static class Sample {
|
||||
|
||||
@Id
|
||||
String id;
|
||||
@Id String id;
|
||||
String field;
|
||||
}
|
||||
|
||||
@@ -1669,8 +1738,19 @@ public class MongoTemplateTests {
|
||||
|
||||
static class VersionedPerson {
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
@Version Long version;
|
||||
String id, firstname, lastname;
|
||||
}
|
||||
|
||||
static class TypeWithFieldAnnotation {
|
||||
|
||||
@Id ObjectId id;
|
||||
@Field("email") String emailAddress;
|
||||
}
|
||||
|
||||
static class TypeWithDate {
|
||||
|
||||
@Id String id;
|
||||
Date date;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
public class SomeEnumTest {
|
||||
|
||||
public enum StringEnum {
|
||||
ONE, TWO, FIVE;
|
||||
}
|
||||
|
||||
public enum NumberEnum {
|
||||
ONE(1), TWO(2), FIVE(5);
|
||||
|
||||
private int value;
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
NumberEnum(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private StringEnum stringEnum;
|
||||
|
||||
private NumberEnum numberEnum;
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
public StringEnum getStringEnum() {
|
||||
return stringEnum;
|
||||
}
|
||||
|
||||
public void setStringEnum(StringEnum stringEnum) {
|
||||
this.stringEnum = stringEnum;
|
||||
}
|
||||
|
||||
public NumberEnum getNumberEnum() {
|
||||
return numberEnum;
|
||||
}
|
||||
|
||||
public void setNumberEnum(NumberEnum numberEnum) {
|
||||
this.numberEnum = numberEnum;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,7 +45,6 @@ import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
@@ -88,7 +87,7 @@ public class MappingMongoConverterUnitTests {
|
||||
|
||||
mappingContext = new MongoMappingContext();
|
||||
mappingContext.setApplicationContext(context);
|
||||
mappingContext.onApplicationEvent(new ContextRefreshedEvent(context));
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
converter = new MappingMongoConverter(factory, mappingContext);
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.Before;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.DBObjectUtils;
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -53,6 +55,7 @@ import com.mongodb.QueryBuilder;
|
||||
* Unit tests for {@link QueryMapper}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class QueryMapperUnitTests {
|
||||
@@ -61,8 +64,7 @@ public class QueryMapperUnitTests {
|
||||
MongoMappingContext context;
|
||||
MappingMongoConverter converter;
|
||||
|
||||
@Mock
|
||||
MongoDbFactory factory;
|
||||
@Mock MongoDbFactory factory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -332,7 +334,11 @@ public class QueryMapperUnitTests {
|
||||
DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class));
|
||||
|
||||
DBObject reference = DBObjectUtils.getAsDBObject(result, "reference");
|
||||
assertThat(reference.containsField("$in"), is(true));
|
||||
|
||||
BasicDBList inClause = getAsDBList(reference, "$in");
|
||||
assertThat(inClause, hasSize(2));
|
||||
assertThat(inClause.get(0), is(instanceOf(com.mongodb.DBRef.class)));
|
||||
assertThat(inClause.get(1), is(instanceOf(com.mongodb.DBRef.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,6 +369,75 @@ public class QueryMapperUnitTests {
|
||||
assertThat(object.containsField("_id"), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-677
|
||||
*/
|
||||
@Test
|
||||
public void handleMapWithDBRefCorrectly() {
|
||||
|
||||
DBObject mapDbObject = new BasicDBObject();
|
||||
mapDbObject.put("test", new com.mongodb.DBRef(null, "test", "test"));
|
||||
DBObject dbObject = new BasicDBObject();
|
||||
dbObject.put("mapWithDBRef", mapDbObject);
|
||||
|
||||
DBObject mapped = mapper.getMappedObject(dbObject, context.getPersistentEntity(WithMapDBRef.class));
|
||||
|
||||
assertThat(mapped.containsField("mapWithDBRef"), is(true));
|
||||
assertThat(mapped.get("mapWithDBRef"), instanceOf(BasicDBObject.class));
|
||||
assertThat(((BasicDBObject) mapped.get("mapWithDBRef")).containsField("test"), is(true));
|
||||
assertThat(((BasicDBObject) mapped.get("mapWithDBRef")).get("test"), instanceOf(com.mongodb.DBRef.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertsUnderscoreIdValueWithoutMetadata() {
|
||||
|
||||
DBObject dbObject = new BasicDBObject().append("_id", new ObjectId().toString());
|
||||
|
||||
DBObject mapped = mapper.getMappedObject(dbObject, null);
|
||||
assertThat(mapped.containsField("_id"), is(true));
|
||||
assertThat(mapped.get("_id"), is(instanceOf(ObjectId.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-705
|
||||
*/
|
||||
@Test
|
||||
public void convertsDBRefWithExistsQuery() {
|
||||
|
||||
Query query = query(where("reference").exists(false));
|
||||
|
||||
BasicMongoPersistentEntity<?> entity = context.getPersistentEntity(WithDBRef.class);
|
||||
DBObject mappedObject = mapper.getMappedObject(query.getQueryObject(), entity);
|
||||
|
||||
DBObject reference = getAsDBObject(mappedObject, "reference");
|
||||
assertThat(reference.containsField("$exists"), is(true));
|
||||
assertThat(reference.get("$exists"), is((Object) false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-706
|
||||
*/
|
||||
@Test
|
||||
public void convertsNestedDBRefsCorrectly() {
|
||||
|
||||
Reference reference = new Reference();
|
||||
reference.id = 5L;
|
||||
|
||||
Query query = query(where("someString").is("foo").andOperator(where("reference").in(reference)));
|
||||
|
||||
BasicMongoPersistentEntity<?> entity = context.getPersistentEntity(WithDBRef.class);
|
||||
DBObject mappedObject = mapper.getMappedObject(query.getQueryObject(), entity);
|
||||
|
||||
assertThat(mappedObject.get("someString"), is((Object) "foo"));
|
||||
|
||||
BasicDBList andClause = getAsDBList(mappedObject, "$and");
|
||||
assertThat(andClause, hasSize(1));
|
||||
|
||||
BasicDBList inClause = getAsDBList(getAsDBObject(getAsDBObject(andClause, 0), "reference"), "$in");
|
||||
assertThat(inClause, hasSize(1));
|
||||
assertThat(inClause.get(0), is(instanceOf(com.mongodb.DBRef.class)));
|
||||
}
|
||||
|
||||
class IdWrapper {
|
||||
Object id;
|
||||
}
|
||||
@@ -375,14 +450,12 @@ public class QueryMapperUnitTests {
|
||||
|
||||
class Sample {
|
||||
|
||||
@Id
|
||||
private String foo;
|
||||
@Id private String foo;
|
||||
}
|
||||
|
||||
class BigIntegerId {
|
||||
|
||||
@Id
|
||||
private BigInteger id;
|
||||
@Id private BigInteger id;
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
@@ -396,14 +469,13 @@ public class QueryMapperUnitTests {
|
||||
|
||||
class CustomizedField {
|
||||
|
||||
@Field("foo")
|
||||
CustomizedField field;
|
||||
@Field("foo") CustomizedField field;
|
||||
}
|
||||
|
||||
class WithDBRef {
|
||||
|
||||
@DBRef
|
||||
Reference reference;
|
||||
String someString;
|
||||
@DBRef Reference reference;
|
||||
}
|
||||
|
||||
class Reference {
|
||||
@@ -415,4 +487,9 @@ public class QueryMapperUnitTests {
|
||||
|
||||
WithDBRef withDbRef;
|
||||
}
|
||||
|
||||
class WithMapDBRef {
|
||||
|
||||
@DBRef Map<String, Sample> mapWithDBRef;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* Copyright 2011-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.
|
||||
* 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,
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
@@ -37,14 +36,15 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.MongoCollectionUtils;
|
||||
import org.springframework.data.mongodb.core.CollectionCallback;
|
||||
import org.springframework.data.mongodb.core.MongoDbUtils;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Order;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
@@ -53,7 +53,8 @@ import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingTests {
|
||||
|
||||
@@ -78,7 +79,7 @@ public class MappingTests {
|
||||
ApplicationContext applicationContext;
|
||||
Mongo mongo;
|
||||
MongoTemplate template;
|
||||
MongoMappingContext mappingContext;
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -89,7 +90,7 @@ public class MappingTests {
|
||||
}
|
||||
applicationContext = new ClassPathXmlApplicationContext("/mapping.xml");
|
||||
template = applicationContext.getBean(MongoTemplate.class);
|
||||
mappingContext = (MongoMappingContext) ReflectionTestUtils.getField(template, "mappingContext");
|
||||
mappingContext = template.getConverter().getMappingContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -464,7 +465,7 @@ public class MappingTests {
|
||||
template.insert(p4);
|
||||
|
||||
Query q = query(where("id").in("1", "2"));
|
||||
q.sort().on("id", Order.ASCENDING);
|
||||
q.with(new Sort(Direction.ASC, "id"));
|
||||
List<PersonPojoStringId> people = template.find(q, PersonPojoStringId.class);
|
||||
assertEquals(2, people.size());
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.data.mongodb.core.mapping;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -29,9 +28,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
@@ -69,17 +66,6 @@ public class MongoMappingContextUnitTests {
|
||||
assertThat(context.getPersistentEntity(DBRef.class), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void populatesAbstractMappingContextsApplicationCorrectly() {
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
context.setApplicationContext(applicationContext);
|
||||
|
||||
Field field = ReflectionUtils.findField(AbstractMappingContext.class, "applicationContext");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
assertThat(ReflectionUtils.getField(field, context), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-638
|
||||
*/
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class ValidatingMongoEventListenerTest {
|
||||
public class ValidatingMongoEventListenerTests {
|
||||
|
||||
@Autowired
|
||||
MongoTemplate mongoTemplate;
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.query;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Field}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class FieldUnitTests {
|
||||
|
||||
@Test
|
||||
public void sameObjectSetupCreatesEqualField() {
|
||||
|
||||
Field left = new Field().include("foo");
|
||||
Field right = new Field().include("foo");
|
||||
|
||||
assertThat(left, is(right));
|
||||
assertThat(right, is(left));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void differentObjectSetupCreatesEqualField() {
|
||||
|
||||
Field left = new Field().include("foo");
|
||||
Field right = new Field().include("bar");
|
||||
|
||||
assertThat(left, is(not(right)));
|
||||
assertThat(right, is(not(left)));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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,28 +15,32 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.monitor;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
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.data.mongodb.monitor.OperationCounters;
|
||||
import org.springframework.data.mongodb.monitor.ServerInfo;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This test class assumes that you are already running the MongoDB server.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
public class MongoMonitorIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
Mongo mongo;
|
||||
@Autowired Mongo mongo;
|
||||
|
||||
@Test
|
||||
public void serverInfo() {
|
||||
@@ -45,9 +49,29 @@ public class MongoMonitorIntegrationTests {
|
||||
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"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void operationCounters() {
|
||||
OperationCounters operationCounters = new OperationCounters(mongo);
|
||||
operationCounters.getInsertCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,16 @@ 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 java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -35,12 +39,15 @@ import org.springframework.core.Constants;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
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;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -60,29 +67,40 @@ import com.mongodb.WriteConcern;
|
||||
public class PerformanceTests {
|
||||
|
||||
private static final String DATABASE_NAME = "performance";
|
||||
private static final int NUMBER_OF_PERSONS = 30000;
|
||||
private static final int NUMBER_OF_PERSONS = 300;
|
||||
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", "JOURNAL_SAFE");
|
||||
"FSYNC_SAFE", "FSYNCED", "JOURNAL_SAFE", "JOURNALED", "REPLICA_ACKNOWLEDGED");
|
||||
private static final int COLLECTION_SIZE = 1024 * 1024 * 256; // 256 MB
|
||||
private static final Collection<String> COLLECTION_NAMES = Arrays.asList("template", "driver", "person");
|
||||
|
||||
Mongo mongo;
|
||||
MongoTemplate operations;
|
||||
PersonRepository repository;
|
||||
MongoConverter converter;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
this.mongo = new Mongo();
|
||||
this.operations = new MongoTemplate(new SimpleMongoDbFactory(this.mongo, DATABASE_NAME));
|
||||
|
||||
SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(this.mongo, DATABASE_NAME);
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
context.setInitialEntitySet(Collections.singleton(Person.class));
|
||||
context.afterPropertiesSet();
|
||||
|
||||
this.converter = new MappingMongoConverter(mongoDbFactory, context);
|
||||
this.operations = new MongoTemplate(new SimpleMongoDbFactory(this.mongo, DATABASE_NAME), converter);
|
||||
|
||||
MongoRepositoryFactoryBean<PersonRepository, Person, ObjectId> factory = new MongoRepositoryFactoryBean<PersonRepository, Person, ObjectId>();
|
||||
factory.setMongoOperations(operations);
|
||||
factory.setRepositoryInterface(PersonRepository.class);
|
||||
factory.afterPropertiesSet();
|
||||
|
||||
repository = factory.getObject();
|
||||
this.repository = factory.getObject();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,69 +108,137 @@ public class PerformanceTests {
|
||||
executeWithWriteConcerns(new WriteConcernCallback() {
|
||||
public void doWithWriteConcern(String constantName, WriteConcern concern) {
|
||||
writeHeadline("WriteConcern: " + constantName);
|
||||
writingObjectsUsingPlainDriver("Writing %s objects using plain driver");
|
||||
writingObjectsUsingMongoTemplate("Writing %s objects using template");
|
||||
writingObjectsUsingRepositories("Writing %s objects using repository");
|
||||
System.out.println(String.format("Writing %s objects using plain driver took %sms", NUMBER_OF_PERSONS,
|
||||
writingObjectsUsingPlainDriver(NUMBER_OF_PERSONS)));
|
||||
System.out.println(String.format("Writing %s objects using template took %sms", NUMBER_OF_PERSONS,
|
||||
writingObjectsUsingMongoTemplate(NUMBER_OF_PERSONS)));
|
||||
System.out.println(String.format("Writing %s objects using repository took %sms", NUMBER_OF_PERSONS,
|
||||
writingObjectsUsingRepositories(NUMBER_OF_PERSONS)));
|
||||
writeFooter();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeAndRead() {
|
||||
public void plainConversion() throws InterruptedException {
|
||||
|
||||
Statistics statistics = new Statistics("Plain conversion of " + NUMBER_OF_PERSONS * 100
|
||||
+ " persons - After %s iterations");
|
||||
|
||||
List<DBObject> dbObjects = getPersonDBObjects(NUMBER_OF_PERSONS * 100);
|
||||
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
statistics.registerTime(Api.DIRECT, Mode.READ, convertDirectly(dbObjects));
|
||||
statistics.registerTime(Api.CONVERTER, Mode.READ, convertUsingConverter(dbObjects));
|
||||
}
|
||||
|
||||
statistics.printResults(ITERATIONS);
|
||||
}
|
||||
|
||||
private long convertDirectly(final List<DBObject> dbObjects) {
|
||||
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
|
||||
@Override
|
||||
public List<Person> doInWatch() {
|
||||
|
||||
List<Person> persons = new ArrayList<PerformanceTests.Person>();
|
||||
|
||||
for (DBObject dbObject : dbObjects) {
|
||||
persons.add(Person.from(dbObject));
|
||||
}
|
||||
|
||||
return persons;
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private long convertUsingConverter(final List<DBObject> dbObjects) {
|
||||
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
|
||||
@Override
|
||||
public List<Person> doInWatch() {
|
||||
|
||||
List<Person> persons = new ArrayList<PerformanceTests.Person>();
|
||||
|
||||
for (DBObject dbObject : dbObjects) {
|
||||
persons.add(converter.read(Person.class, dbObject));
|
||||
}
|
||||
|
||||
return persons;
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeAndRead() throws Exception {
|
||||
|
||||
mongo.setWriteConcern(WriteConcern.SAFE);
|
||||
|
||||
for (int i = 3; i > 0; i--) {
|
||||
readsAndWrites(NUMBER_OF_PERSONS, ITERATIONS);
|
||||
}
|
||||
|
||||
private void readsAndWrites(int numberOfPersons, int iterations) {
|
||||
|
||||
Statistics statistics = new Statistics("Reading " + numberOfPersons + " - After %s iterations");
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
|
||||
setupCollections();
|
||||
|
||||
writeHeadline("Plain driver");
|
||||
writingObjectsUsingPlainDriver("Writing %s objects using plain driver");
|
||||
readingUsingPlainDriver("Reading all objects using plain driver");
|
||||
queryUsingPlainDriver("Executing query using plain driver");
|
||||
writeFooter();
|
||||
statistics.registerTime(Api.DRIVER, Mode.WRITE, writingObjectsUsingPlainDriver(numberOfPersons));
|
||||
statistics.registerTime(Api.TEMPLATE, Mode.WRITE, writingObjectsUsingMongoTemplate(numberOfPersons));
|
||||
statistics.registerTime(Api.REPOSITORY, Mode.WRITE, writingObjectsUsingRepositories(numberOfPersons));
|
||||
|
||||
writeHeadline("Template");
|
||||
writingObjectsUsingMongoTemplate("Writing %s objects using template");
|
||||
readingUsingTemplate("Reading all objects using template");
|
||||
queryUsingTemplate("Executing query using template");
|
||||
writeFooter();
|
||||
statistics.registerTime(Api.DRIVER, Mode.READ, readingUsingPlainDriver());
|
||||
statistics.registerTime(Api.TEMPLATE, Mode.READ, readingUsingTemplate());
|
||||
statistics.registerTime(Api.REPOSITORY, Mode.READ, readingUsingRepository());
|
||||
|
||||
writeHeadline("Repositories");
|
||||
writingObjectsUsingRepositories("Writing %s objects using repository");
|
||||
readingUsingRepository("Reading all objects using repository");
|
||||
queryUsingRepository("Executing query using repository");
|
||||
writeFooter();
|
||||
statistics.registerTime(Api.DRIVER, Mode.QUERY, queryUsingPlainDriver());
|
||||
statistics.registerTime(Api.TEMPLATE, Mode.QUERY, queryUsingTemplate());
|
||||
statistics.registerTime(Api.REPOSITORY, Mode.QUERY, queryUsingRepository());
|
||||
|
||||
writeFooter();
|
||||
if (i > 0 && i % (iterations / 10) == 0) {
|
||||
statistics.printResults(i);
|
||||
}
|
||||
}
|
||||
|
||||
statistics.printResults(iterations);
|
||||
}
|
||||
|
||||
private void writeHeadline(String headline) {
|
||||
System.out.println(headline);
|
||||
System.out.println("---------------------------------".substring(0, headline.length()));
|
||||
System.out.println(createUnderline(headline));
|
||||
}
|
||||
|
||||
private void writeFooter() {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private void queryUsingTemplate(String template) {
|
||||
executeWatchedWithTimeAndResultSize(template, new WatchCallback<List<Person>>() {
|
||||
private long queryUsingTemplate() {
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
public List<Person> doInWatch() {
|
||||
Query query = query(where("addresses.zipCode").regex(".*1.*"));
|
||||
return operations.find(query, Person.class, "template");
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void queryUsingRepository(String template) {
|
||||
executeWatchedWithTimeAndResultSize(template, new WatchCallback<List<Person>>() {
|
||||
private long queryUsingRepository() {
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
public List<Person> doInWatch() {
|
||||
return repository.findByAddressesZipCodeContaining("1");
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void executeWithWriteConcerns(WriteConcernCallback callback) {
|
||||
@@ -181,7 +267,7 @@ public class PerformanceTests {
|
||||
for (String collectionName : COLLECTION_NAMES) {
|
||||
DBCollection collection = db.getCollection(collectionName);
|
||||
collection.drop();
|
||||
db.command(getCreateCollectionCommand(collectionName));
|
||||
collection.getDB().command(getCreateCollectionCommand(collectionName));
|
||||
collection.ensureIndex(new BasicDBObject("firstname", -1));
|
||||
collection.ensureIndex(new BasicDBObject("lastname", -1));
|
||||
}
|
||||
@@ -195,38 +281,42 @@ public class PerformanceTests {
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
private void writingObjectsUsingPlainDriver(String template) {
|
||||
private long writingObjectsUsingPlainDriver(int numberOfPersons) {
|
||||
|
||||
final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
||||
final List<DBObject> persons = getPersonDBObjects();
|
||||
final List<Person> persons = getPersonObjects(numberOfPersons);
|
||||
|
||||
executeWatchedWithTime(template, new WatchCallback<Void>() {
|
||||
executeWatched(new WatchCallback<Void>() {
|
||||
public Void doInWatch() {
|
||||
for (DBObject person : persons) {
|
||||
collection.save(person);
|
||||
for (Person person : persons) {
|
||||
collection.save(person.toDBObject());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void writingObjectsUsingRepositories(String template) {
|
||||
private long writingObjectsUsingRepositories(int numberOfPersons) {
|
||||
|
||||
final List<Person> persons = getPersonObjects();
|
||||
final List<Person> persons = getPersonObjects(numberOfPersons);
|
||||
|
||||
executeWatchedWithTime(template, new WatchCallback<Void>() {
|
||||
executeWatched(new WatchCallback<Void>() {
|
||||
public Void doInWatch() {
|
||||
repository.save(persons);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void writingObjectsUsingMongoTemplate(String template) {
|
||||
private long writingObjectsUsingMongoTemplate(int numberOfPersons) {
|
||||
|
||||
final List<Person> persons = getPersonObjects();
|
||||
final List<Person> persons = getPersonObjects(numberOfPersons);
|
||||
|
||||
executeWatchedWithTime(template, new WatchCallback<Void>() {
|
||||
executeWatched(new WatchCallback<Void>() {
|
||||
public Void doInWatch() {
|
||||
for (Person person : persons) {
|
||||
operations.save(person, "template");
|
||||
@@ -234,82 +324,95 @@ public class PerformanceTests {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void readingUsingPlainDriver(String template) {
|
||||
private long readingUsingPlainDriver() {
|
||||
|
||||
final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
||||
|
||||
executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback<List<Person>>() {
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
public List<Person> doInWatch() {
|
||||
return toPersons(collection.find());
|
||||
return toPersons(mongo.getDB(DATABASE_NAME).getCollection("driver").find());
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void readingUsingTemplate(String template) {
|
||||
executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback<List<Person>>() {
|
||||
private long readingUsingTemplate() {
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
public List<Person> doInWatch() {
|
||||
return operations.findAll(Person.class, "template");
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void readingUsingRepository(String template) {
|
||||
executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback<List<Person>>() {
|
||||
private long readingUsingRepository() {
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
public List<Person> doInWatch() {
|
||||
return repository.findAll();
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private void queryUsingPlainDriver(String template) {
|
||||
private long queryUsingPlainDriver() {
|
||||
|
||||
final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
||||
|
||||
executeWatchedWithTimeAndResultSize(template, new WatchCallback<List<Person>>() {
|
||||
executeWatched(new WatchCallback<List<Person>>() {
|
||||
public List<Person> doInWatch() {
|
||||
|
||||
DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
||||
|
||||
DBObject regex = new BasicDBObject("$regex", Pattern.compile(".*1.*"));
|
||||
DBObject query = new BasicDBObject("addresses.zipCode", regex);
|
||||
return toPersons(collection.find(query));
|
||||
}
|
||||
});
|
||||
|
||||
return watch.getLastTaskTimeMillis();
|
||||
}
|
||||
|
||||
private List<DBObject> getPersonDBObjects() {
|
||||
private List<Person> getPersonObjects(int numberOfPersons) {
|
||||
|
||||
List<DBObject> result = new ArrayList<DBObject>(NUMBER_OF_PERSONS);
|
||||
List<Person> result = new ArrayList<Person>();
|
||||
|
||||
for (Person person : getPersonObjects()) {
|
||||
result.add(person.toDBObject());
|
||||
}
|
||||
for (int i = 0; i < numberOfPersons; i++) {
|
||||
|
||||
return result;
|
||||
}
|
||||
List<Address> addresses = new ArrayList<Address>();
|
||||
|
||||
private List<Person> getPersonObjects() {
|
||||
for (int a = 0; a < 5; a++) {
|
||||
addresses.add(new Address("zip" + a, "city" + a));
|
||||
}
|
||||
|
||||
List<Person> result = new ArrayList<Person>(NUMBER_OF_PERSONS);
|
||||
Person person = new Person("Firstname" + i, "Lastname" + i, addresses);
|
||||
|
||||
watch.start("Created " + NUMBER_OF_PERSONS + " Persons");
|
||||
for (int o = 0; o < 10; o++) {
|
||||
person.orders.add(new Order(LineItem.generate()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_PERSONS; i++) {
|
||||
|
||||
Address address = new Address("zip" + i, "city" + i);
|
||||
Person person = new Person("Firstname" + i, "Lastname" + i, Arrays.asList(address));
|
||||
person.orders.add(new Order(LineItem.generate()));
|
||||
person.orders.add(new Order(LineItem.generate()));
|
||||
result.add(person);
|
||||
}
|
||||
|
||||
watch.stop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private <T> T executeWatched(String template, WatchCallback<T> callback) {
|
||||
private List<DBObject> getPersonDBObjects(int numberOfPersons) {
|
||||
|
||||
watch.start(String.format(template, NUMBER_OF_PERSONS));
|
||||
List<DBObject> dbObjects = new ArrayList<DBObject>(numberOfPersons);
|
||||
|
||||
for (Person person : getPersonObjects(numberOfPersons)) {
|
||||
dbObjects.add(person.toDBObject());
|
||||
}
|
||||
|
||||
return dbObjects;
|
||||
}
|
||||
|
||||
private <T> T executeWatched(WatchCallback<T> callback) {
|
||||
|
||||
watch.start();
|
||||
|
||||
try {
|
||||
return callback.doInWatch();
|
||||
@@ -318,28 +421,6 @@ public class PerformanceTests {
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void executeWatchedWithTime(String template, WatchCallback<?> callback) {
|
||||
executeWatched(template, callback);
|
||||
printStatistics(null);
|
||||
}
|
||||
|
||||
private <T> void executeWatchedWithTimeAndResultSize(String template, WatchCallback<List<T>> callback) {
|
||||
printStatistics(executeWatched(template, callback));
|
||||
}
|
||||
|
||||
private void printStatistics(Collection<?> result) {
|
||||
|
||||
long time = watch.getLastTaskTimeMillis();
|
||||
StringBuilder builder = new StringBuilder(watch.getLastTaskName());
|
||||
|
||||
if (result != null) {
|
||||
builder.append(" returned ").append(result.size()).append(" results and");
|
||||
}
|
||||
|
||||
builder.append(" took ").append(time).append(" milliseconds");
|
||||
System.out.println(builder);
|
||||
}
|
||||
|
||||
private static List<Person> toPersons(DBCursor cursor) {
|
||||
|
||||
List<Person> persons = new ArrayList<Person>();
|
||||
@@ -354,10 +435,9 @@ public class PerformanceTests {
|
||||
static class Person {
|
||||
|
||||
ObjectId id;
|
||||
@Indexed
|
||||
final String firstname, lastname;
|
||||
final List<Address> addresses;
|
||||
final Set<Order> orders;
|
||||
String firstname, lastname;
|
||||
List<Address> addresses;
|
||||
Set<Order> orders;
|
||||
|
||||
public Person(String firstname, String lastname, List<Address> addresses) {
|
||||
this.firstname = firstname;
|
||||
@@ -579,11 +659,253 @@ public class PerformanceTests {
|
||||
DBObject toDBObject();
|
||||
}
|
||||
|
||||
private static List<DBObject> writeAll(Collection<? extends Convertible> convertibles) {
|
||||
List<DBObject> result = new ArrayList<DBObject>();
|
||||
private static BasicDBList writeAll(Collection<? extends Convertible> convertibles) {
|
||||
BasicDBList result = new BasicDBList();
|
||||
for (Convertible convertible : convertibles) {
|
||||
result.add(convertible.toDBObject());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum Api {
|
||||
DRIVER, TEMPLATE, REPOSITORY, DIRECT, CONVERTER;
|
||||
}
|
||||
|
||||
static enum Mode {
|
||||
WRITE, READ, QUERY;
|
||||
}
|
||||
|
||||
private static class Statistics {
|
||||
|
||||
private final String headline;
|
||||
private final Map<Mode, ModeTimes> times;
|
||||
|
||||
public Statistics(String headline) {
|
||||
|
||||
this.headline = headline;
|
||||
this.times = new HashMap<Mode, ModeTimes>();
|
||||
|
||||
for (Mode mode : Mode.values()) {
|
||||
times.put(mode, new ModeTimes(mode));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerTime(Api api, Mode mode, double time) {
|
||||
times.get(mode).add(api, time);
|
||||
}
|
||||
|
||||
public void printResults(int iterations) {
|
||||
|
||||
String title = String.format(headline, iterations);
|
||||
|
||||
System.out.println(title);
|
||||
System.out.println(createUnderline(title));
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Mode mode : Mode.values()) {
|
||||
String print = times.get(mode).print();
|
||||
if (!print.isEmpty()) {
|
||||
builder.append(print).append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(builder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder builder = new StringBuilder(times.size());
|
||||
|
||||
for (ModeTimes times : this.times.values()) {
|
||||
builder.append(times.toString());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static String createUnderline(String input) {
|
||||
|
||||
StringBuilder builder = new StringBuilder(input.length());
|
||||
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
builder.append("-");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
static class ApiTimes {
|
||||
|
||||
private static final String TIME_TEMPLATE = "%s %s time -\tAverage: %sms%s,%sMedian: %sms%s";
|
||||
|
||||
private static final DecimalFormat TIME_FORMAT;
|
||||
private static final DecimalFormat DEVIATION_FORMAT;
|
||||
|
||||
static {
|
||||
|
||||
TIME_FORMAT = new DecimalFormat("0.00");
|
||||
|
||||
DEVIATION_FORMAT = new DecimalFormat("0.00");
|
||||
DEVIATION_FORMAT.setPositivePrefix("+");
|
||||
}
|
||||
|
||||
private final Api api;
|
||||
private final Mode mode;
|
||||
private final List<Double> times;
|
||||
|
||||
public ApiTimes(Api api, Mode mode) {
|
||||
this.api = api;
|
||||
this.mode = mode;
|
||||
this.times = new ArrayList<Double>();
|
||||
}
|
||||
|
||||
public void add(double time) {
|
||||
this.times.add(time);
|
||||
}
|
||||
|
||||
public boolean hasTimes() {
|
||||
return !times.isEmpty();
|
||||
}
|
||||
|
||||
public double getAverage() {
|
||||
|
||||
double result = 0;
|
||||
|
||||
for (Double time : times) {
|
||||
result += time;
|
||||
}
|
||||
|
||||
return result == 0.0 ? 0.0 : result / times.size();
|
||||
}
|
||||
|
||||
public double getMedian() {
|
||||
|
||||
if (times.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
ArrayList<Double> list = new ArrayList<Double>(times);
|
||||
Collections.sort(list);
|
||||
|
||||
int size = list.size();
|
||||
|
||||
if (size % 2 == 0) {
|
||||
return (list.get(size / 2 - 1) + list.get(size / 2)) / 2;
|
||||
} else {
|
||||
return list.get(size / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private double getDeviationFrom(double otherAverage) {
|
||||
|
||||
double average = getAverage();
|
||||
return average * 100 / otherAverage - 100;
|
||||
}
|
||||
|
||||
private double getMediaDeviationFrom(double otherMedian) {
|
||||
double median = getMedian();
|
||||
return median * 100 / otherMedian - 100;
|
||||
}
|
||||
|
||||
public String print() {
|
||||
|
||||
if (times.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return basicPrint("", "\t\t", "") + '\n';
|
||||
}
|
||||
|
||||
private String basicPrint(String extension, String middle, String foo) {
|
||||
return String.format(TIME_TEMPLATE, api, mode, TIME_FORMAT.format(getAverage()), extension, middle,
|
||||
TIME_FORMAT.format(getMedian()), foo);
|
||||
}
|
||||
|
||||
public String print(double referenceAverage, double referenceMedian) {
|
||||
|
||||
if (times.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return basicPrint(String.format(" %s%%", DEVIATION_FORMAT.format(getDeviationFrom(referenceAverage))), "\t",
|
||||
String.format(" %s%%", DEVIATION_FORMAT.format(getMediaDeviationFrom(referenceMedian)))) + '\n';
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return times.isEmpty() ? "" : String.format("%s, %s: %s", api, mode,
|
||||
StringUtils.collectionToCommaDelimitedString(times)) + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static class ModeTimes {
|
||||
|
||||
private final Map<Api, ApiTimes> times;
|
||||
|
||||
public ModeTimes(Mode mode) {
|
||||
|
||||
this.times = new HashMap<Api, ApiTimes>();
|
||||
|
||||
for (Api api : Api.values()) {
|
||||
this.times.put(api, new ApiTimes(api, mode));
|
||||
}
|
||||
}
|
||||
|
||||
public void add(Api api, double time) {
|
||||
times.get(api).add(time);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
public String print() {
|
||||
|
||||
if (times.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Double previousTime = null;
|
||||
Double previousMedian = null;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (Api api : Api.values()) {
|
||||
|
||||
ApiTimes apiTimes = times.get(api);
|
||||
|
||||
if (!apiTimes.hasTimes()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (previousTime == null) {
|
||||
builder.append(apiTimes.print());
|
||||
previousTime = apiTimes.getAverage();
|
||||
previousMedian = apiTimes.getMedian();
|
||||
} else {
|
||||
builder.append(apiTimes.print(previousTime, previousMedian));
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder builder = new StringBuilder(times.size());
|
||||
|
||||
for (ApiTimes times : this.times.values()) {
|
||||
builder.append(times.toString());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,11 +53,9 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
protected PersonRepository repository;
|
||||
@Autowired protected PersonRepository repository;
|
||||
|
||||
@Autowired
|
||||
MongoOperations operations;
|
||||
@Autowired MongoOperations operations;
|
||||
|
||||
Person dave, oliver, carter, boyd, stefan, leroi, alicia;
|
||||
QPerson person;
|
||||
@@ -546,4 +544,26 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result, hasItem(dave));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-701
|
||||
*/
|
||||
@Test
|
||||
public void executesDerivedStartsWithQueryCorrectly() {
|
||||
|
||||
List<Person> result = repository.findByLastnameStartsWith("Matt");
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result, hasItems(dave, oliver));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-701
|
||||
*/
|
||||
@Test
|
||||
public void executesDerivedEndsWithQueryCorrectly() {
|
||||
|
||||
List<Person> result = repository.findByLastnameEndsWith("thews");
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result, hasItems(dave, oliver));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
||||
*/
|
||||
List<Person> findByLastname(String lastname);
|
||||
|
||||
List<Person> findByLastnameStartsWith(String prefix);
|
||||
|
||||
List<Person> findByLastnameEndsWith(String postfix);
|
||||
|
||||
/**
|
||||
* Returns all {@link Person}s with the given lastname ordered by their firstname.
|
||||
*
|
||||
|
||||
@@ -263,7 +263,7 @@ public class MongoQueryCreatorUnitTests {
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Matt"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("foo").regex("Matt.*"))));
|
||||
assertThat(query, is(query(where("foo").regex("^Matt"))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +276,7 @@ public class MongoQueryCreatorUnitTests {
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "ews"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("foo").regex(".*ews"))));
|
||||
assertThat(query, is(query(where("foo").regex("ews$"))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
<mongo:db-factory />
|
||||
<mongo:db-factory dbname="validation" />
|
||||
|
||||
<mongo:mapping-converter base-package="org.springframework.data.mongodb.core" />
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<xi:include href="introduction/why-sd-doc.xml"/>
|
||||
<xi:include href="introduction/requirements.xml"/>
|
||||
<xi:include href="introduction/getting-started.xml"/>
|
||||
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/1.4.0.RELEASE/src/docbkx/repositories.xml">
|
||||
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/1.5.2.RELEASE/src/docbkx/repositories.xml">
|
||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repositories.xml" />
|
||||
</xi:include>
|
||||
</part>
|
||||
@@ -72,10 +72,10 @@
|
||||
<part id="appendix">
|
||||
<title>Appendix</title>
|
||||
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.4.0.RELEASE/src/docbkx/repository-namespace-reference.xml">
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.5.2.RELEASE/src/docbkx/repository-namespace-reference.xml">
|
||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml" />
|
||||
</xi:include>
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.4.0.RELEASE/src/docbkx/repository-query-keywords-reference.xml">
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.5.2.RELEASE/src/docbkx/repository-query-keywords-reference.xml">
|
||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml" />
|
||||
</xi:include>
|
||||
</part>
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 1.2.2.GA (2013-07-19)
|
||||
----------------------------------------
|
||||
** Bug
|
||||
* [DATAMONGO-663] - org.springframework.data.mongodb.core.query.Field needs an equals method
|
||||
* [DATAMONGO-677] - QueryMapper does not handled correctly Map with DBRef value
|
||||
* [DATAMONGO-679] - MongoTemplate.doSave(…) passed a JSON String doesn't save it.
|
||||
* [DATAMONGO-683] - QueryMapper does not handle default _id when no MappingMetadata is present
|
||||
* [DATAMONGO-685] - JMX ServerInfo bean may return wrong info
|
||||
* [DATAMONGO-693] - MongoFactoryBean should create a mongo instance with host/port if replicaset is null or empty
|
||||
* [DATAMONGO-704] - Remove references to SimpleMongoConverter from JavaDoc.
|
||||
* [DATAMONGO-705] - QueryMapper doesn't handles exists query with DBRef field
|
||||
* [DATAMONGO-706] - QueryMapper does not transform DBRefs in nested keywords correctly
|
||||
* [DATAMONGO-717] - Application context is not properly distributed to persistent entities
|
||||
|
||||
** Improvement
|
||||
* [DATAMONGO-682] - Remove performance hotspots
|
||||
* [DATAMONGO-701] - Improve performance of indexed starts-with queries
|
||||
|
||||
** Task
|
||||
* [DATAMONGO-658] - Minor formatting changes to README.md
|
||||
* [DATAMONGO-678] - Performance improvements in CustomConversions
|
||||
* [DATAMONGO-714] - Add latest formatter to project sources
|
||||
* [DATAMONGO-723] - Clean up test cases
|
||||
* [DATAMONGO-727] - Release 1.2.2
|
||||
|
||||
Changes in version 1.2.1.GA (2013-04-17)
|
||||
----------------------------------------
|
||||
** Bug
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Document 1.2.1
|
||||
Spring Data Document 1.2.2
|
||||
Copyright (c) [2010-2013] SpringSource, a division of VMware, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SPRING DATA MongoDB 1.2.1.GA
|
||||
SPRING DATA MongoDB 1.2.2.GA
|
||||
----------------------------
|
||||
|
||||
Spring Data MongoDB is released under the terms of the Apache Software License Version 2.0 (see license.txt).
|
||||
|
||||
Reference in New Issue
Block a user