Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1202d2cbc2 | ||
|
|
0edf6c06ed | ||
|
|
0afd137e7d | ||
|
|
bc3f44197b | ||
|
|
28bd631579 | ||
|
|
5396df9af4 | ||
|
|
2b864e9744 | ||
|
|
5accbbdac5 | ||
|
|
11d9f04fd1 | ||
|
|
67b91e446e | ||
|
|
1124841e17 | ||
|
|
10ccbf131d | ||
|
|
b29930b512 | ||
|
|
d671fb13ae | ||
|
|
b0a10d19c3 | ||
|
|
d8ef7e1472 | ||
|
|
b9a25eabae | ||
|
|
e92e5c737f | ||
|
|
6e46fb12cb | ||
|
|
031d446a1c | ||
|
|
e6bab1ce60 | ||
|
|
2fffe0a5c4 | ||
|
|
2493de5f91 | ||
|
|
bd11bab076 | ||
|
|
b667984563 | ||
|
|
7ef167ed96 | ||
|
|
303a057d86 | ||
|
|
607072c0d3 | ||
|
|
11e9c562b3 | ||
|
|
220b211faa | ||
|
|
c0c51fcc29 | ||
|
|
ed9eddf10e | ||
|
|
e23d73d55e | ||
|
|
9627fbaebf | ||
|
|
ef93d4db0b | ||
|
|
928b5a7742 | ||
|
|
118a52a8d6 | ||
|
|
b47e8ca3da | ||
|
|
8527d6eb43 | ||
|
|
d645c778c3 | ||
|
|
5c47f1ae9e | ||
|
|
9f324bac19 | ||
|
|
186caba1ac | ||
|
|
2ebb7e801d | ||
|
|
a932f3474e | ||
|
|
e992456532 | ||
|
|
7b34c5cac4 | ||
|
|
16baf00f5e | ||
|
|
61a2c56a27 | ||
|
|
e62437b64a | ||
|
|
e9a7e887be | ||
|
|
b91a66f6f9 | ||
|
|
a047e54e5a | ||
|
|
8197ff57c8 | ||
|
|
a2136719e1 | ||
|
|
7bcf142c8d | ||
|
|
d50d03a80e | ||
|
|
ba894a4511 |
133
README.md
133
README.md
@@ -29,19 +29,13 @@ For those in a hurry:
|
|||||||
|
|
||||||
* Download the jar through Maven:
|
* Download the jar through Maven:
|
||||||
|
|
||||||
<dependency>
|
```xml
|
||||||
<groupId>org.springframework.data</groupId>
|
<dependency>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
</dependency>
|
<version>1.2.3.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
<repository>
|
|
||||||
<id>spring-maven-snapshot</id>
|
|
||||||
<snapshots><enabled>true</enabled></snapshots>
|
|
||||||
<name>Springframework Maven SNAPSHOT Repository</name>
|
|
||||||
<url>http://maven.springframework.org/snapshot</url>
|
|
||||||
</repository>
|
|
||||||
|
|
||||||
### MongoTemplate
|
### MongoTemplate
|
||||||
MongoTemplate is the central support class for Mongo database operations. It provides
|
MongoTemplate is the central support class for Mongo database operations. It provides
|
||||||
@@ -54,93 +48,98 @@ Future plans are to support optional logging and/or exception throwing based on
|
|||||||
|
|
||||||
### Easy Data Repository generation
|
### Easy Data Repository generation
|
||||||
|
|
||||||
To simplify the creation of Data Repositories a generic Repository interface and default implementation is provided. Furthermore, Spring will automatically create a Repository implementation for you that adds implementations of finder methods you specify on an interface.
|
To simplify the creation of data repositories a generic `Repository` interface and default implementation is provided. Furthermore, Spring will automatically create a Repository implementation for you that adds implementations of finder methods you specify on an interface.
|
||||||
|
|
||||||
The Repository interface is
|
The Repository interface is
|
||||||
|
|
||||||
public interface Repository<T, ID extends Serializable> {
|
```java
|
||||||
|
public interface Repository<T, ID extends Serializable> {
|
||||||
|
|
||||||
T save(T entity);
|
T save(T entity);
|
||||||
|
|
||||||
List<T> save(Iterable<? extends T> entities);
|
List<T> save(Iterable<? extends T> entities);
|
||||||
|
|
||||||
T findById(ID id);
|
T findById(ID id);
|
||||||
|
|
||||||
boolean exists(ID id);
|
boolean exists(ID id);
|
||||||
|
|
||||||
List<T> findAll();
|
List<T> findAll();
|
||||||
|
|
||||||
Long count();
|
Long count();
|
||||||
|
|
||||||
void delete(T entity);
|
void delete(T entity);
|
||||||
|
|
||||||
void delete(Iterable<? extends T> entities);
|
void delete(Iterable<? extends T> entities);
|
||||||
|
|
||||||
void deleteAll();
|
void deleteAll();
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
The MongoRepository extends Repository and will in future add more Mongo specific methods.
|
The `MongoRepository` extends `Repository` and will in future add more Mongo specific methods.
|
||||||
|
|
||||||
public interface MongoRepository<T, ID extends Serializable> extends
|
```java
|
||||||
Repository<T, ID> {
|
public interface MongoRepository<T, ID extends Serializable> extends Repository<T, ID> {
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
SimpleMongoRepository is the out of the box implementation of the MongoRepository you can use for basid CRUD operations.
|
`SimpleMongoRepository` is the out of the box implementation of the `MongoRepository` you can use for basid CRUD operations.
|
||||||
|
|
||||||
To go beyond basic CRUD, extend the MongoRepository interface and supply your own finder methods that follow simple naming conventions such that they can be easily converted into queries.
|
To go beyond basic CRUD, extend the `MongoRepository` interface and supply your own finder methods that follow simple naming conventions such that they can be easily converted into queries.
|
||||||
|
|
||||||
For example, given a Person class with first and last name properties, a PersonRepository interface that can query for Person by last name and when the first name matches a regular expression is shown below
|
For example, given a `Person` class with first and last name properties, a `PersonRepository` interface that can query for `Person` by last name and when the first name matches a regular expression is shown below
|
||||||
|
|
||||||
public interface PersonRepository extends MongoRepository<Person, Long> {
|
```java
|
||||||
|
public interface PersonRepository extends MongoRepository<Person, Long> {
|
||||||
|
|
||||||
List<Person> findByLastname(String lastname);
|
List<Person> findByLastname(String lastname);
|
||||||
|
|
||||||
List<Person> findByFirstnameLike(String firstname);
|
List<Person> findByFirstnameLike(String firstname);
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You can have Spring automatically generate the implemention as shown below
|
You can have Spring automatically create a proxy for the interface as shown below:
|
||||||
|
|
||||||
<bean id="template" class="org.springframework.data.document.mongodb.MongoTemplate">
|
```xml
|
||||||
<constructor-arg>
|
<bean id="template" class="org.springframework.data.document.mongodb.MongoTemplate">
|
||||||
<bean class="com.mongodb.Mongo">
|
<constructor-arg>
|
||||||
<constructor-arg value="localhost" />
|
<bean class="com.mongodb.Mongo">
|
||||||
<constructor-arg value="27017" />
|
<constructor-arg value="localhost" />
|
||||||
</bean>
|
<constructor-arg value="27017" />
|
||||||
</constructor-arg>
|
</bean>
|
||||||
<constructor-arg value="database" />
|
</constructor-arg>
|
||||||
<property name="defaultCollectionName" value="springdata" />
|
<constructor-arg value="database" />
|
||||||
</bean>
|
<property name="defaultCollectionName" value="springdata" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean class="org.springframework.data.document.mongodb.repository.MongoRepositoryFactoryBean">
|
<mongo:repositories base-package="com.acme.repository" />
|
||||||
<property name="template" ref="template" />
|
```
|
||||||
<property name="repositoryInterface" value="org.springframework.data.document.mongodb.repository.PersonRepository" />
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
This will register an object in the container named PersonRepository. You can use it as shown below
|
This will find the repository interface and register a proxy object in the container. You can use it as shown below:
|
||||||
|
|
||||||
@Service
|
``java
|
||||||
public class MyService {
|
@Service
|
||||||
|
public class MyService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
PersonRepository repository;
|
private final PersonRepository repository;
|
||||||
|
|
||||||
|
public void doWork() {
|
||||||
|
|
||||||
public void doWork() {
|
repository.deleteAll();
|
||||||
|
|
||||||
repository.deleteAll();
|
Person person = new Person();
|
||||||
|
person.setFirstname("Oliver");
|
||||||
|
person.setLastname("Gierke");
|
||||||
|
person = repository.save(person);
|
||||||
|
|
||||||
Person person = new Person();
|
List<Person> lastNameResults = repository.findByLastname("Gierke");
|
||||||
person.setFirstname("Oliver");
|
|
||||||
person.setLastname("Gierke");
|
|
||||||
person = repository.save(person);
|
|
||||||
|
|
||||||
List<Person> lastNameResults = repository.findByLastname("Gierke");
|
List<Person> firstNameResults = repository.findByFirstnameLike("Oli*");
|
||||||
|
|
||||||
List<Person> firstNameResults = repository.findByFirstnameLike("Oli*");
|
}
|
||||||
|
}
|
||||||
}
|
```
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Contributing to Spring Data
|
Contributing to Spring Data
|
||||||
|
|||||||
@@ -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_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.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.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.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_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"/>
|
<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.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.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.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.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_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" 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_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.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.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.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.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"/>
|
<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.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.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_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.insert_new_line_after_annotation_on_field" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
<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.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.alignment_for_union_type_in_multicatch" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
<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_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_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_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_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_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_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.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.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_after_assignment_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_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_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.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.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.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_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_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_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_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"/>
|
<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.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_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_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_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_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"/>
|
<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.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.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.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_header" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" 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.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.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.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_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"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
|||||||
16
pom.xml
16
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>1.2.0.RELEASE</version>
|
<version>1.2.5.BUILD-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Spring Data MongoDB</name>
|
<name>Spring Data MongoDB</name>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data.build</groupId>
|
<groupId>org.springframework.data.build</groupId>
|
||||||
<artifactId>spring-data-parent</artifactId>
|
<artifactId>spring-data-parent</artifactId>
|
||||||
<version>1.0.0.RELEASE</version>
|
<version>1.0.5.RELEASE</version>
|
||||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -26,11 +26,10 @@
|
|||||||
<module>spring-data-mongodb-distribution</module>
|
<module>spring-data-mongodb-distribution</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.type>multi</project.type>
|
<project.type>multi</project.type>
|
||||||
<dist.name>spring-data-mongodb</dist.name>
|
<dist.id>spring-data-mongodb</dist.id>
|
||||||
<springdata.commons>1.5.0.RELEASE</springdata.commons>
|
<springdata.commons>1.5.3.RELEASE</springdata.commons>
|
||||||
<mongo>2.10.1</mongo>
|
<mongo>2.10.1</mongo>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -90,4 +89,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spring-libs-release</id>
|
||||||
|
<url>http://repo.springsource.org/libs-release</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>1.2.0.RELEASE</version>
|
<version>1.2.5.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
<version>1.2.0.RELEASE</version>
|
<version>1.2.5.BUILD-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,6 +34,10 @@ import com.mongodb.DBCollection;
|
|||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
import com.mongodb.MongoException;
|
import com.mongodb.MongoException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||||
|
|
||||||
private static final String ENTITY_CLASS = "_entity_class";
|
private static final String ENTITY_CLASS = "_entity_class";
|
||||||
@@ -58,6 +62,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
|||||||
this.entityManagerFactory = entityManagerFactory;
|
this.entityManagerFactory = entityManagerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentState(java.lang.Class, java.lang.Object, org.springframework.data.crossstore.ChangeSet)
|
||||||
|
*/
|
||||||
public void getPersistentState(Class<? extends ChangeSetBacked> entityClass, Object id, final ChangeSet changeSet)
|
public void getPersistentState(Class<? extends ChangeSetBacked> entityClass, Object id, final ChangeSet changeSet)
|
||||||
throws DataAccessException, NotFoundException {
|
throws DataAccessException, NotFoundException {
|
||||||
|
|
||||||
@@ -100,6 +108,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
||||||
|
*/
|
||||||
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
||||||
log.debug("getPersistentId called on " + entity);
|
log.debug("getPersistentId called on " + entity);
|
||||||
if (entityManagerFactory == null) {
|
if (entityManagerFactory == null) {
|
||||||
@@ -109,6 +121,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.crossstore.ChangeSetPersister#persistState(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
||||||
|
*/
|
||||||
public Object persistState(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
public Object persistState(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
log.debug("Flush: changeset was null, nothing to flush.");
|
log.debug("Flush: changeset was null, nothing to flush.");
|
||||||
@@ -169,8 +185,13 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
|||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collection the given entity type shall be persisted to.
|
||||||
|
*
|
||||||
|
* @param entityClass must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private String getCollectionNameForEntity(Class<? extends ChangeSetBacked> entityClass) {
|
private String getCollectionNameForEntity(Class<? extends ChangeSetBacked> entityClass) {
|
||||||
return ClassUtils.getQualifiedName(entityClass);
|
return mongoTemplate.getCollectionName(entityClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Infrastructure for Spring Data's MongoDB cross store support.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.crossstore;
|
||||||
|
|
||||||
@@ -36,9 +36,14 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.transaction.support.TransactionCallback;
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import com.mongodb.DBCollection;
|
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for MongoDB cross-store persistence (mainly {@link MongoChangeSetPersister}).
|
||||||
|
*
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration("classpath:/META-INF/spring/applicationContext.xml")
|
@ContextConfiguration("classpath:/META-INF/spring/applicationContext.xml")
|
||||||
public class CrossStoreMongoTests {
|
public class CrossStoreMongoTests {
|
||||||
@@ -58,7 +63,7 @@ public class CrossStoreMongoTests {
|
|||||||
|
|
||||||
txTemplate = new TransactionTemplate(transactionManager);
|
txTemplate = new TransactionTemplate(transactionManager);
|
||||||
|
|
||||||
clearData(Person.class.getName());
|
clearData(Person.class);
|
||||||
|
|
||||||
Address address = new Address(12, "MAin St.", "Boston", "MA", "02101");
|
Address address = new Address(12, "MAin St.", "Boston", "MA", "02101");
|
||||||
|
|
||||||
@@ -91,11 +96,10 @@ public class CrossStoreMongoTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearData(String collectionName) {
|
private void clearData(Class<?> domainType) {
|
||||||
DBCollection col = this.mongoTemplate.getCollection(collectionName);
|
|
||||||
if (col != null) {
|
String collectionName = mongoTemplate.getCollectionName(domainType);
|
||||||
this.mongoTemplate.dropCollection(collectionName);
|
mongoTemplate.dropCollection(collectionName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -183,7 +187,7 @@ public class CrossStoreMongoTests {
|
|||||||
|
|
||||||
boolean weFound3 = false;
|
boolean weFound3 = false;
|
||||||
|
|
||||||
for (DBObject dbo : this.mongoTemplate.getCollection(Person.class.getName()).find()) {
|
for (DBObject dbo : this.mongoTemplate.getCollection(mongoTemplate.getCollectionName(Person.class)).find()) {
|
||||||
Assert.assertTrue(!dbo.get("_entity_id").equals(2L));
|
Assert.assertTrue(!dbo.get("_entity_id").equals(2L));
|
||||||
if (dbo.get("_entity_id").equals(3L)) {
|
if (dbo.get("_entity_id").equals(3L)) {
|
||||||
weFound3 = true;
|
weFound3 = true;
|
||||||
|
|||||||
@@ -13,13 +13,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>1.2.0.RELEASE</version>
|
<version>1.2.5.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.root>${basedir}/..</project.root>
|
<project.root>${basedir}/..</project.root>
|
||||||
<dist.id>spring-data-mongodb</dist.id>
|
|
||||||
<dist.key>SDMONGO</dist.key>
|
<dist.key>SDMONGO</dist.key>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ An example log entry might look like:
|
|||||||
{
|
{
|
||||||
"_id" : ObjectId("4d89341a8ef397e06940d5cd"),
|
"_id" : ObjectId("4d89341a8ef397e06940d5cd"),
|
||||||
"applicationId" : "my.application",
|
"applicationId" : "my.application",
|
||||||
"name" : "org.springframework.data.mongodb.log4j.AppenderTest",
|
"name" : "org.springframework.data.mongodb.log4j.MongoLog4jAppenderIntegrationTests",
|
||||||
"level" : "DEBUG",
|
"level" : "DEBUG",
|
||||||
"timestamp" : ISODate("2011-03-23T16:53:46.778Z"),
|
"timestamp" : ISODate("2011-03-23T16:53:46.778Z"),
|
||||||
"properties" : {
|
"properties" : {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>1.2.0.RELEASE</version>
|
<version>1.2.5.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.data.mongodb.log4j;
|
package org.springframework.data.mongodb.log4j;
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
@@ -21,188 +20,207 @@ import java.util.Arrays;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.mongodb.BasicDBList;
|
|
||||||
import com.mongodb.BasicDBObject;
|
|
||||||
import com.mongodb.DB;
|
|
||||||
import com.mongodb.Mongo;
|
|
||||||
import com.mongodb.WriteConcern;
|
|
||||||
import org.apache.log4j.AppenderSkeleton;
|
import org.apache.log4j.AppenderSkeleton;
|
||||||
import org.apache.log4j.Level;
|
import org.apache.log4j.Level;
|
||||||
import org.apache.log4j.MDC;
|
import org.apache.log4j.MDC;
|
||||||
import org.apache.log4j.PatternLayout;
|
import org.apache.log4j.PatternLayout;
|
||||||
import org.apache.log4j.spi.LoggingEvent;
|
import org.apache.log4j.spi.LoggingEvent;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.WriteConcern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
* Log4j appender writing log entries into a MongoDB instance.
|
||||||
|
*
|
||||||
|
* @author Jon Brisbin
|
||||||
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
public class MongoLog4jAppender extends AppenderSkeleton {
|
public class MongoLog4jAppender extends AppenderSkeleton {
|
||||||
|
|
||||||
public static final String LEVEL = "level";
|
public static final String LEVEL = "level";
|
||||||
public static final String NAME = "name";
|
public static final String NAME = "name";
|
||||||
public static final String APP_ID = "applicationId";
|
public static final String APP_ID = "applicationId";
|
||||||
public static final String TIMESTAMP = "timestamp";
|
public static final String TIMESTAMP = "timestamp";
|
||||||
public static final String PROPERTIES = "properties";
|
public static final String PROPERTIES = "properties";
|
||||||
public static final String TRACEBACK = "traceback";
|
public static final String TRACEBACK = "traceback";
|
||||||
public static final String MESSAGE = "message";
|
public static final String MESSAGE = "message";
|
||||||
public static final String YEAR = "year";
|
public static final String YEAR = "year";
|
||||||
public static final String MONTH = "month";
|
public static final String MONTH = "month";
|
||||||
public static final String DAY = "day";
|
public static final String DAY = "day";
|
||||||
public static final String HOUR = "hour";
|
public static final String HOUR = "hour";
|
||||||
|
|
||||||
protected String host = "localhost";
|
protected String host = "localhost";
|
||||||
protected int port = 27017;
|
protected int port = 27017;
|
||||||
protected String database = "logs";
|
protected String database = "logs";
|
||||||
protected String collectionPattern = "%c";
|
protected String collectionPattern = "%c";
|
||||||
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
|
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
|
||||||
protected String applicationId = System.getProperty("APPLICATION_ID", null);
|
protected String applicationId = System.getProperty("APPLICATION_ID", null);
|
||||||
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE;
|
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE;
|
||||||
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL;
|
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL;
|
||||||
protected Mongo mongo;
|
protected Mongo mongo;
|
||||||
protected DB db;
|
protected DB db;
|
||||||
|
|
||||||
public MongoLog4jAppender() {
|
public MongoLog4jAppender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MongoLog4jAppender(boolean isActive) {
|
public MongoLog4jAppender(boolean isActive) {
|
||||||
super(isActive);
|
super(isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHost(String host) {
|
public void setHost(String host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPort(int port) {
|
public void setPort(int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDatabase() {
|
public String getDatabase() {
|
||||||
return database;
|
return database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDatabase(String database) {
|
public void setDatabase(String database) {
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCollectionPattern() {
|
public String getCollectionPattern() {
|
||||||
return collectionPattern;
|
return collectionPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCollectionPattern(String collectionPattern) {
|
public void setCollectionPattern(String collectionPattern) {
|
||||||
this.collectionPattern = collectionPattern;
|
this.collectionPattern = collectionPattern;
|
||||||
this.collectionLayout = new PatternLayout(collectionPattern);
|
this.collectionLayout = new PatternLayout(collectionPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getApplicationId() {
|
public String getApplicationId() {
|
||||||
return applicationId;
|
return applicationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApplicationId(String applicationId) {
|
public void setApplicationId(String applicationId) {
|
||||||
this.applicationId = applicationId;
|
this.applicationId = applicationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWarnOrHigherWriteConcern(String wc) {
|
public void setWarnOrHigherWriteConcern(String wc) {
|
||||||
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
|
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWarnOrHigherWriteConcern() {
|
public String getWarnOrHigherWriteConcern() {
|
||||||
return warnOrHigherWriteConcern.toString();
|
return warnOrHigherWriteConcern.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInfoOrLowerWriteConcern() {
|
public String getInfoOrLowerWriteConcern() {
|
||||||
return infoOrLowerWriteConcern.toString();
|
return infoOrLowerWriteConcern.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInfoOrLowerWriteConcern(String wc) {
|
public void setInfoOrLowerWriteConcern(String wc) {
|
||||||
this.infoOrLowerWriteConcern = WriteConcern.valueOf(wc);
|
this.infoOrLowerWriteConcern = WriteConcern.valueOf(wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void connectToMongo() throws UnknownHostException {
|
protected void connectToMongo() throws UnknownHostException {
|
||||||
this.mongo = new Mongo(host, port);
|
this.mongo = new Mongo(host, port);
|
||||||
this.db = mongo.getDB(database);
|
this.db = mongo.getDB(database);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
/*
|
||||||
@Override
|
* (non-Javadoc)
|
||||||
protected void append(final LoggingEvent event) {
|
* @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
|
||||||
if (null == db) {
|
*/
|
||||||
try {
|
@Override
|
||||||
connectToMongo();
|
@SuppressWarnings({ "unchecked" })
|
||||||
} catch (UnknownHostException e) {
|
protected void append(final LoggingEvent event) {
|
||||||
throw new RuntimeException(e.getMessage(), e);
|
if (null == db) {
|
||||||
}
|
try {
|
||||||
}
|
connectToMongo();
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BasicDBObject dbo = new BasicDBObject();
|
BasicDBObject dbo = new BasicDBObject();
|
||||||
if (null != applicationId) {
|
if (null != applicationId) {
|
||||||
dbo.put(APP_ID, applicationId);
|
dbo.put(APP_ID, applicationId);
|
||||||
MDC.put(APP_ID, applicationId);
|
MDC.put(APP_ID, applicationId);
|
||||||
}
|
}
|
||||||
dbo.put(NAME, event.getLogger().getName());
|
dbo.put(NAME, event.getLogger().getName());
|
||||||
dbo.put(LEVEL, event.getLevel().toString());
|
dbo.put(LEVEL, event.getLevel().toString());
|
||||||
Calendar tstamp = Calendar.getInstance();
|
Calendar tstamp = Calendar.getInstance();
|
||||||
tstamp.setTimeInMillis(event.getTimeStamp());
|
tstamp.setTimeInMillis(event.getTimeStamp());
|
||||||
dbo.put(TIMESTAMP, tstamp.getTime());
|
dbo.put(TIMESTAMP, tstamp.getTime());
|
||||||
|
|
||||||
// Copy properties into document
|
// Copy properties into document
|
||||||
Map<Object, Object> props = event.getProperties();
|
Map<Object, Object> props = event.getProperties();
|
||||||
if (null != props && props.size() > 0) {
|
if (null != props && props.size() > 0) {
|
||||||
BasicDBObject propsDbo = new BasicDBObject();
|
BasicDBObject propsDbo = new BasicDBObject();
|
||||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||||
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());
|
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());
|
||||||
}
|
}
|
||||||
dbo.put(PROPERTIES, propsDbo);
|
dbo.put(PROPERTIES, propsDbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy traceback info (if there is any) into the document
|
// Copy traceback info (if there is any) into the document
|
||||||
String[] traceback = event.getThrowableStrRep();
|
String[] traceback = event.getThrowableStrRep();
|
||||||
if (null != traceback && traceback.length > 0) {
|
if (null != traceback && traceback.length > 0) {
|
||||||
BasicDBList tbDbo = new BasicDBList();
|
BasicDBList tbDbo = new BasicDBList();
|
||||||
tbDbo.addAll(Arrays.asList(traceback));
|
tbDbo.addAll(Arrays.asList(traceback));
|
||||||
dbo.put(TRACEBACK, tbDbo);
|
dbo.put(TRACEBACK, tbDbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the rendered message into the document
|
// Put the rendered message into the document
|
||||||
dbo.put(MESSAGE, event.getRenderedMessage());
|
dbo.put(MESSAGE, event.getRenderedMessage());
|
||||||
|
|
||||||
// Insert the document
|
// Insert the document
|
||||||
Calendar now = Calendar.getInstance();
|
Calendar now = Calendar.getInstance();
|
||||||
MDC.put(YEAR, now.get(Calendar.YEAR));
|
MDC.put(YEAR, now.get(Calendar.YEAR));
|
||||||
MDC.put(MONTH, String.format("%1$02d", now.get(Calendar.MONTH) + 1));
|
MDC.put(MONTH, String.format("%1$02d", now.get(Calendar.MONTH) + 1));
|
||||||
MDC.put(DAY, String.format("%1$02d", now.get(Calendar.DAY_OF_MONTH)));
|
MDC.put(DAY, String.format("%1$02d", now.get(Calendar.DAY_OF_MONTH)));
|
||||||
MDC.put(HOUR, String.format("%1$02d", now.get(Calendar.HOUR_OF_DAY)));
|
MDC.put(HOUR, String.format("%1$02d", now.get(Calendar.HOUR_OF_DAY)));
|
||||||
|
|
||||||
String coll = collectionLayout.format(event);
|
String coll = collectionLayout.format(event);
|
||||||
|
|
||||||
MDC.remove(YEAR);
|
MDC.remove(YEAR);
|
||||||
MDC.remove(MONTH);
|
MDC.remove(MONTH);
|
||||||
MDC.remove(DAY);
|
MDC.remove(DAY);
|
||||||
MDC.remove(HOUR);
|
MDC.remove(HOUR);
|
||||||
if (null != applicationId) {
|
if (null != applicationId) {
|
||||||
MDC.remove(APP_ID);
|
MDC.remove(APP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteConcern wc;
|
WriteConcern wc;
|
||||||
if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
|
if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
|
||||||
wc = warnOrHigherWriteConcern;
|
wc = warnOrHigherWriteConcern;
|
||||||
} else {
|
} else {
|
||||||
wc = infoOrLowerWriteConcern;
|
wc = infoOrLowerWriteConcern;
|
||||||
}
|
}
|
||||||
db.getCollection(coll).insert(dbo, wc);
|
db.getCollection(coll).insert(dbo, wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
/*
|
||||||
mongo.close();
|
* (non-Javadoc)
|
||||||
}
|
* @see org.apache.log4j.AppenderSkeleton#close()
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
|
||||||
public boolean requiresLayout() {
|
if (mongo != null) {
|
||||||
return true;
|
mongo.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.apache.log4j.AppenderSkeleton#requiresLayout()
|
||||||
|
*/
|
||||||
|
public boolean requiresLayout() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Infrastructure for to use MongoDB as a logging sink.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.log4j;
|
||||||
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2011 by the original author(s).
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* 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.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 {
|
|
||||||
|
|
||||||
private static final String NAME = AppenderTest.class.getName();
|
|
||||||
private Logger log = Logger.getLogger(NAME);
|
|
||||||
private Mongo mongo;
|
|
||||||
private DB db;
|
|
||||||
private 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testProperties() {
|
|
||||||
MDC.put("property", "one");
|
|
||||||
log.debug("DEBUG message");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* 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.log4j;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.apache.log4j.MDC;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.DBCursor;
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProperties() {
|
||||||
|
|
||||||
|
MDC.put("property", "one");
|
||||||
|
log.debug("DEBUG message");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.log4j;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link MongoLog4jAppender}.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class MongoLog4jAppenderUnitTests {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-641
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void closesWithoutMongoInstancePresent() {
|
||||||
|
new MongoLog4jAppender().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,11 +10,4 @@ log4j.appender.stdout.collectionPattern = %X{year}%X{month}
|
|||||||
log4j.appender.stdout.applicationId = my.application
|
log4j.appender.stdout.applicationId = my.application
|
||||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE
|
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE
|
||||||
|
|
||||||
log4j.category.org.apache.activemq=ERROR
|
log4j.category.org.springframework.data.mongodb=DEBUG
|
||||||
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
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>1.2.0.RELEASE</version>
|
<version>1.2.5.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.data.mongodb.core.MongoActionOperation;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.WriteResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mongo-specific {@link DataIntegrityViolationException}.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class MongoDataIntegrityViolationException extends DataIntegrityViolationException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -186980521176764046L;
|
||||||
|
|
||||||
|
private final WriteResult writeResult;
|
||||||
|
private final MongoActionOperation actionOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link MongoDataIntegrityViolationException} using the given message and {@link WriteResult}.
|
||||||
|
*
|
||||||
|
* @param message the exception message
|
||||||
|
* @param writeResult the {@link WriteResult} that causes the exception, must not be {@literal null}.
|
||||||
|
* @param actionOperation the {@link MongoActionOperation} that caused the exception, must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public MongoDataIntegrityViolationException(String message, WriteResult writeResult,
|
||||||
|
MongoActionOperation actionOperation) {
|
||||||
|
|
||||||
|
super(message);
|
||||||
|
|
||||||
|
Assert.notNull(writeResult, "WriteResult must not be null!");
|
||||||
|
Assert.notNull(actionOperation, "MongoActionOperation must not be null!");
|
||||||
|
|
||||||
|
this.writeResult = writeResult;
|
||||||
|
this.actionOperation = actionOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link WriteResult} that caused the exception.
|
||||||
|
*
|
||||||
|
* @return the writeResult
|
||||||
|
*/
|
||||||
|
public WriteResult getWriteResult() {
|
||||||
|
return writeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link MongoActionOperation} in which the current exception occured.
|
||||||
|
*
|
||||||
|
* @return the actionOperation
|
||||||
|
*/
|
||||||
|
public MongoActionOperation getActionOperation() {
|
||||||
|
return actionOperation;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -134,7 +134,6 @@ public abstract class AbstractMongoConfiguration {
|
|||||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||||
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
||||||
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
|
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
|
||||||
mappingContext.initialize();
|
|
||||||
|
|
||||||
return mappingContext;
|
return mappingContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
|
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
|
||||||
indexHelperBuilder.addConstructorArgReference(ctxRef);
|
indexHelperBuilder.addConstructorArgReference(ctxRef);
|
||||||
indexHelperBuilder.addConstructorArgReference(dbFactoryRef);
|
indexHelperBuilder.addConstructorArgReference(dbFactoryRef);
|
||||||
|
indexHelperBuilder.addDependsOn(ctxRef);
|
||||||
|
|
||||||
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
|
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
|
||||||
INDEX_HELPER));
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 Mark Pollack
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
@@ -43,6 +44,11 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
|||||||
@Override
|
@Override
|
||||||
public void setAsText(String replicaSetString) {
|
public void setAsText(String replicaSetString) {
|
||||||
|
|
||||||
|
if (!StringUtils.hasText(replicaSetString)) {
|
||||||
|
setValue(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString);
|
String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString);
|
||||||
Set<ServerAddress> serverAddresses = new HashSet<ServerAddress>(replicaSetStringArray.length);
|
Set<ServerAddress> serverAddresses = new HashSet<ServerAddress>(replicaSetStringArray.length);
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,14 +26,13 @@ import com.mongodb.DB;
|
|||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class featuring helper methods for internal MongoDb classes.
|
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
|
||||||
* <p/>
|
* framework.
|
||||||
* <p>
|
|
||||||
* Mainly intended for internal use within the framework.
|
|
||||||
*
|
*
|
||||||
* @author Thomas Risberg
|
* @author Thomas Risberg
|
||||||
* @author Graeme Rocher
|
* @author Graeme Rocher
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Randy Watler
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public abstract class MongoDbUtils {
|
public abstract class MongoDbUtils {
|
||||||
@@ -131,8 +130,11 @@ public abstract class MongoDbUtils {
|
|||||||
holderToUse.addDB(databaseName, db);
|
holderToUse.addDB(databaseName, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
|
// synchronize holder only if not yet synchronized
|
||||||
holderToUse.setSynchronizedWithTransaction(true);
|
if (!holderToUse.isSynchronizedWithTransaction()) {
|
||||||
|
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
|
||||||
|
holderToUse.setSynchronizedWithTransaction(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (holderToUse != dbHolder) {
|
if (holderToUse != dbHolder) {
|
||||||
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
|
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
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 java.util.List;
|
||||||
|
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
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.DataAccessException;
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
import com.mongodb.MongoOptions;
|
import com.mongodb.MongoOptions;
|
||||||
@@ -36,6 +39,7 @@ import com.mongodb.WriteConcern;
|
|||||||
* @author Thomas Risberg
|
* @author Thomas Risberg
|
||||||
* @author Graeme Rocher
|
* @author Graeme Rocher
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, DisposableBean,
|
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) {
|
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) {
|
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) {
|
public void setHost(String host) {
|
||||||
@@ -126,15 +157,15 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
mongoOptions = new MongoOptions();
|
mongoOptions = new MongoOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replicaPair != null) {
|
if (!isNullOrEmpty(replicaPair)) {
|
||||||
if (replicaPair.size() < 2) {
|
if (replicaPair.size() < 2) {
|
||||||
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
|
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
|
||||||
}
|
}
|
||||||
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
|
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
|
||||||
} else if (replicaSetSeeds != null) {
|
} else if (!isNullOrEmpty(replicaSetSeeds)) {
|
||||||
mongo = new Mongo(replicaSetSeeds, mongoOptions);
|
mongo = new Mongo(replicaSetSeeds, mongoOptions);
|
||||||
} else {
|
} 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,
|
mongo = port != null ? new Mongo(new ServerAddress(mongoHost, port), mongoOptions) : new Mongo(mongoHost,
|
||||||
mongoOptions);
|
mongoOptions);
|
||||||
}
|
}
|
||||||
@@ -146,6 +177,10 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
|||||||
this.mongo = mongo;
|
this.mongo = mongo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isNullOrEmpty(Collection<?> elements) {
|
||||||
|
return elements == null || elements.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
* @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.
|
* Query for a list of objects of type T from the collection used by the entity class.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
|
* 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.
|
* 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.
|
* Query for a list of objects of type T from the specified collection.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
|
* 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.
|
* 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.
|
* specified type.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||||
* feature rich {@link Query}.
|
* feature rich {@link Query}.
|
||||||
@@ -399,7 +399,7 @@ public interface MongoOperations {
|
|||||||
* type.
|
* type.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||||
* feature rich {@link Query}.
|
* 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.
|
* Map the results of an ad-hoc query on the collection for the entity class to a List of the specified type.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||||
* feature rich {@link Query}.
|
* 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.
|
* Map the results of an ad-hoc query on the specified collection to a List of the specified type.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||||
* feature rich {@link Query}.
|
* 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.
|
* type. The first document that matches the query is returned and also removed from the collection in the database.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||||
* feature rich {@link Query}.
|
* feature rich {@link Query}.
|
||||||
@@ -555,7 +555,7 @@ public interface MongoOperations {
|
|||||||
* Insert the object into the specified collection.
|
* Insert the object into the specified collection.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* Insert is used to initially store the object into the database. To update an existing object use the save method.
|
* 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'.
|
* object is not already present, that is an 'upsert'.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
* 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
|
* 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'.
|
* is an 'upsert'.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
|
* 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/>
|
* <p/>
|
||||||
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
|
* 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
|
* 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
|
* @return
|
||||||
*/
|
*/
|
||||||
MongoConverter getConverter();
|
MongoConverter getConverter();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -44,7 +44,6 @@ import org.springframework.core.convert.ConversionService;
|
|||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.dao.OptimisticLockingFailureException;
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
import org.springframework.data.authentication.UserCredentials;
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
@@ -53,6 +52,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
|||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.BeanWrapper;
|
import org.springframework.data.mapping.model.BeanWrapper;
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
|
import org.springframework.data.mongodb.MongoDataIntegrityViolationException;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||||
@@ -534,8 +534,26 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
mongoConverter, entityClass), near.getMetric());
|
mongoConverter, entityClass), near.getMetric());
|
||||||
List<GeoResult<T>> result = new ArrayList<GeoResult<T>>(results.size());
|
List<GeoResult<T>> result = new ArrayList<GeoResult<T>>(results.size());
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
int elementsToSkip = near.getSkip() != null ? near.getSkip() : 0;
|
||||||
|
|
||||||
for (Object element : results) {
|
for (Object element : results) {
|
||||||
result.add(callback.doWith((DBObject) element));
|
|
||||||
|
/*
|
||||||
|
* As MongoDB currently (2.4.4) doesn't support the skipping of elements in near queries
|
||||||
|
* we skip the elements ourselves to avoid at least the document 2 object mapping overhead.
|
||||||
|
*
|
||||||
|
* @see https://jira.mongodb.org/browse/SERVER-3925
|
||||||
|
*/
|
||||||
|
if (index >= elementsToSkip) {
|
||||||
|
result.add(callback.doWith((DBObject) element));
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementsToSkip > 0) {
|
||||||
|
// as we skipped some elements we have to calculate the averageDistance ourselves:
|
||||||
|
return new GeoResults<T>(result, near.getMetric());
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject stats = (DBObject) commandResult.get("stats");
|
DBObject stats = (DBObject) commandResult.get("stats");
|
||||||
@@ -666,8 +684,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
||||||
|
|
||||||
if (mongoPersistentEntity == null || mongoPersistentEntity.hasVersionProperty()) {
|
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
||||||
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity, null);
|
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity,
|
||||||
|
this.mongoConverter.getConversionService());
|
||||||
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,8 +789,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
// Fresh instance -> initialize version property
|
// Fresh instance -> initialize version property
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
beanWrapper.setProperty(versionProperty, 0);
|
doInsert(collectionName, objectToSave, this.mongoConverter);
|
||||||
doSave(collectionName, objectToSave, this.mongoConverter);
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
assertUpdateableIdIfNotSet(objectToSave);
|
assertUpdateableIdIfNotSet(objectToSave);
|
||||||
@@ -792,12 +810,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject));
|
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject));
|
||||||
Update update = Update.fromDBObject(dbObject, ID_FIELD);
|
Update update = Update.fromDBObject(dbObject, ID_FIELD);
|
||||||
|
|
||||||
updateFirst(query, update, objectToSave.getClass());
|
doUpdate(collectionName, query, update, objectToSave.getClass(), false, false);
|
||||||
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject));
|
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||||
|
|
||||||
assertUpdateableIdIfNotSet(objectToSave);
|
assertUpdateableIdIfNotSet(objectToSave);
|
||||||
@@ -810,7 +827,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
writer.write(objectToSave, dbDoc);
|
writer.write(objectToSave, dbDoc);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
objectToSave = (T) JSON.parse((String) objectToSave);
|
dbDoc = (DBObject) JSON.parse((String) objectToSave);
|
||||||
} catch (JSONParseException e) {
|
} catch (JSONParseException e) {
|
||||||
throw new MappingException("Could not parse given String to save into a JSON document!", e);
|
throw new MappingException("Could not parse given String to save into a JSON document!", e);
|
||||||
}
|
}
|
||||||
@@ -941,7 +958,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
if (entity != null && entity.hasVersionProperty() && !multi) {
|
if (entity != null && entity.hasVersionProperty() && !multi) {
|
||||||
if (writeResult.getN() == 0) {
|
if (writeResult.getN() == 0) {
|
||||||
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
|
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
|
||||||
+ updateObj.toMap().toString());
|
+ updateObj.toMap().toString() + " to collection " + collectionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,11 +998,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
Assert.notNull(object);
|
Assert.notNull(object);
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(object.getClass());
|
Class<?> objectType = object.getClass();
|
||||||
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
||||||
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
||||||
|
|
||||||
if (idProp == null) {
|
if (idProp == null) {
|
||||||
throw new MappingException("No id property found for object of type " + entity.getType().getName());
|
throw new MappingException("No id property found for object of type " + objectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversionService service = mongoConverter.getConversionService();
|
ConversionService service = mongoConverter.getConversionService();
|
||||||
@@ -1306,8 +1324,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
|
* 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
|
* 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
|
* otherwise, an instance of MappingMongoConverter will be used. The query document is specified as a standard
|
||||||
* and so is the fields specification. Can be overridden by subclasses.
|
* DBObject and so is the fields specification. Can be overridden by subclasses.
|
||||||
*
|
*
|
||||||
* @param collectionName name of the collection to retrieve the objects from
|
* @param collectionName name of the collection to retrieve the objects from
|
||||||
* @param query the query document that specifies the criteria used to find a record
|
* @param query the query document that specifies the criteria used to find a record
|
||||||
@@ -1408,19 +1426,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
|
|
||||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||||
|
|
||||||
DBObject updateObj = update.getUpdateObject();
|
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), entity);
|
||||||
for (String key : updateObj.keySet()) {
|
|
||||||
updateObj.put(key, mongoConverter.convertToMongoType(updateObj.get(key)));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBObject mappedQuery = mapper.getMappedObject(query, entity);
|
DBObject mappedQuery = mapper.getMappedObject(query, entity);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug("findAndModify using query: " + mappedQuery + " fields: " + fields + " sort: " + sort
|
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);
|
new ReadDbObjectCallback<T>(readerToUse, entityClass), collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1647,7 +1661,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (writeResultChecking == WriteResultChecking.EXCEPTION) {
|
if (writeResultChecking == WriteResultChecking.EXCEPTION) {
|
||||||
throw new DataIntegrityViolationException(message);
|
throw new MongoDataIntegrityViolationException(message, writeResult, operation);
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error(message);
|
LOGGER.error(message);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -17,9 +17,11 @@ package org.springframework.data.mongodb.core.convert;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -63,6 +65,7 @@ public class CustomConversions {
|
|||||||
private final Set<ConvertiblePair> writingPairs;
|
private final Set<ConvertiblePair> writingPairs;
|
||||||
private final Set<Class<?>> customSimpleTypes;
|
private final Set<Class<?>> customSimpleTypes;
|
||||||
private final SimpleTypeHolder simpleTypeHolder;
|
private final SimpleTypeHolder simpleTypeHolder;
|
||||||
|
private final Map<Class<?>, HashMap<Class<?>, CacheValue>> cache;
|
||||||
|
|
||||||
private final List<Object> converters;
|
private final List<Object> converters;
|
||||||
|
|
||||||
@@ -85,6 +88,7 @@ public class CustomConversions {
|
|||||||
this.readingPairs = new HashSet<ConvertiblePair>();
|
this.readingPairs = new HashSet<ConvertiblePair>();
|
||||||
this.writingPairs = new HashSet<ConvertiblePair>();
|
this.writingPairs = new HashSet<ConvertiblePair>();
|
||||||
this.customSimpleTypes = new HashSet<Class<?>>();
|
this.customSimpleTypes = new HashSet<Class<?>>();
|
||||||
|
this.cache = new HashMap<Class<?>, HashMap<Class<?>, CacheValue>>();
|
||||||
|
|
||||||
this.converters = new ArrayList<Object>();
|
this.converters = new ArrayList<Object>();
|
||||||
this.converters.add(CustomToStringConverter.INSTANCE);
|
this.converters.add(CustomToStringConverter.INSTANCE);
|
||||||
@@ -268,9 +272,11 @@ public class CustomConversions {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
|
public boolean hasCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
|
||||||
|
|
||||||
Assert.notNull(source);
|
Assert.notNull(source);
|
||||||
Assert.notNull(expectedTargetType);
|
Assert.notNull(expectedTargetType);
|
||||||
return getCustomTarget(source, expectedTargetType, readingPairs) != null;
|
|
||||||
|
return getCustomReadTarget(source, expectedTargetType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,8 +305,32 @@ public class CustomConversions {
|
|||||||
return null;
|
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
|
@WritingConverter
|
||||||
private enum CustomToStringConverter implements GenericConverter {
|
private enum CustomToStringConverter implements GenericConverter {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||||
@@ -313,4 +343,30 @@ public class CustomConversions {
|
|||||||
return source.toString();
|
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>() {
|
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||||
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
||||||
|
|
||||||
boolean isConstructorProperty = entity.isConstructorArgument(prop);
|
if (!dbo.containsField(prop.getFieldName()) || entity.isConstructorArgument(prop)) {
|
||||||
boolean hasValueForProperty = dbo.containsField(prop.getFieldName());
|
|
||||||
|
|
||||||
if (!hasValueForProperty || isConstructorProperty) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +829,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
return conversionService.convert(obj, target);
|
return conversionService.convert(obj, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != obj && conversions.isSimpleType(obj.getClass())) {
|
if (conversions.isSimpleType(obj.getClass())) {
|
||||||
// Doesn't need conversion
|
// Doesn't need conversion
|
||||||
return getPotentiallyConvertedSimpleWrite(obj);
|
return getPotentiallyConvertedSimpleWrite(obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.springframework.core.convert.ConversionException;
|
import org.springframework.core.convert.ConversionException;
|
||||||
@@ -41,6 +42,7 @@ import com.mongodb.DBRef;
|
|||||||
*
|
*
|
||||||
* @author Jon Brisbin
|
* @author Jon Brisbin
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Patryk Wasik
|
||||||
*/
|
*/
|
||||||
public class QueryMapper {
|
public class QueryMapper {
|
||||||
|
|
||||||
@@ -83,11 +85,22 @@ public class QueryMapper {
|
|||||||
|
|
||||||
for (String key : query.keySet()) {
|
for (String key : query.keySet()) {
|
||||||
|
|
||||||
MongoPersistentProperty targetProperty = getTargetProperty(key, entity);
|
if (Keyword.isKeyword(key)) {
|
||||||
String newKey = determineKey(key, entity);
|
result.putAll(getMappedKeyword(new Keyword(query, key), entity));
|
||||||
Object value = query.get(key);
|
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;
|
return result;
|
||||||
@@ -103,13 +116,14 @@ public class QueryMapper {
|
|||||||
private DBObject getMappedKeyword(Keyword query, MongoPersistentEntity<?> entity) {
|
private DBObject getMappedKeyword(Keyword query, MongoPersistentEntity<?> entity) {
|
||||||
|
|
||||||
// $or/$nor
|
// $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;
|
Iterable<?> conditions = (Iterable<?>) query.value;
|
||||||
BasicDBList newConditions = new BasicDBList();
|
BasicDBList newConditions = new BasicDBList();
|
||||||
|
|
||||||
for (Object condition : conditions) {
|
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);
|
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.
|
* Returns the mapped keyword considered defining a criteria for the given property.
|
||||||
*
|
*
|
||||||
* @param keyword
|
|
||||||
* @param property
|
* @param property
|
||||||
|
* @param keyword
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public DBObject getMappedKeyword(Keyword keyword, MongoPersistentProperty property) {
|
private DBObject getMappedKeyword(Field property, Keyword keyword) {
|
||||||
|
|
||||||
if (property.isAssociation()) {
|
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
|
||||||
convertAssociation(keyword.value, property);
|
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
|
* Returns the mapped value for the given source object assuming it's a value for the given
|
||||||
* {@link MongoPersistentProperty}.
|
* {@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 property the property the value is a value for
|
||||||
* @param newKey the key the value will be bound to eventually
|
* @param newKey the key the value will be bound to eventually
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Object getMappedValue(Object source, MongoPersistentProperty property, String newKey) {
|
private Object getMappedValue(Field documentField, Object value) {
|
||||||
|
|
||||||
if (property == null) {
|
if (documentField.isIdField()) {
|
||||||
return convertSimpleOrDBObject(source, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (property.isIdProperty() || "_id".equals(newKey)) {
|
if (value instanceof DBObject) {
|
||||||
|
DBObject valueDbo = (DBObject) value;
|
||||||
if (source instanceof DBObject) {
|
|
||||||
DBObject valueDbo = (DBObject) source;
|
|
||||||
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
|
if (valueDbo.containsField("$in") || valueDbo.containsField("$nin")) {
|
||||||
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
|
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
|
||||||
List<Object> ids = new ArrayList<Object>();
|
List<Object> ids = new ArrayList<Object>();
|
||||||
@@ -163,63 +173,25 @@ public class QueryMapper {
|
|||||||
} else if (valueDbo.containsField("$ne")) {
|
} else if (valueDbo.containsField("$ne")) {
|
||||||
valueDbo.put("$ne", convertId(valueDbo.get("$ne")));
|
valueDbo.put("$ne", convertId(valueDbo.get("$ne")));
|
||||||
} else {
|
} else {
|
||||||
return getMappedObject((DBObject) source, null);
|
return getMappedObject((DBObject) value, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return valueDbo;
|
return valueDbo;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return convertId(source);
|
return convertId(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.isAssociation()) {
|
if (Keyword.isKeyword(value)) {
|
||||||
return Keyword.isKeyword(source) ? getMappedKeyword(new Keyword(source), property) : convertAssociation(source,
|
return getMappedKeyword(new Keyword((DBObject) value), null);
|
||||||
property);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertSimpleOrDBObject(source, mappingContext.getPersistentEntity(property));
|
if (documentField.isAssociation()) {
|
||||||
}
|
return convertAssociation(value, documentField.getProperty());
|
||||||
|
|
||||||
private MongoPersistentProperty getTargetProperty(String key, MongoPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
if (isIdKey(key, entity)) {
|
|
||||||
return entity.getIdProperty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(key, entity);
|
return convertSimpleOrDBObject(value, documentField.getPropertyEntity());
|
||||||
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 && DEFAULT_ID_NAMES.contains(key)) {
|
|
||||||
return "_id";
|
|
||||||
}
|
|
||||||
|
|
||||||
PersistentPropertyPath<MongoPersistentProperty> path = getPath(key, entity);
|
|
||||||
return path == null ? key : path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,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 source
|
||||||
* @param property
|
* @param property
|
||||||
@@ -263,31 +235,19 @@ public class QueryMapper {
|
|||||||
return result;
|
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);
|
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}.
|
* Converts the given raw id value into either {@link ObjectId} or {@link String}.
|
||||||
*
|
*
|
||||||
@@ -315,16 +275,27 @@ public class QueryMapper {
|
|||||||
String key;
|
String key;
|
||||||
Object value;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -334,7 +305,11 @@ public class QueryMapper {
|
|||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static boolean isKeyword(Object value) {
|
public static boolean isKeyword(Object value) {
|
||||||
|
|
||||||
|
if (value instanceof String) {
|
||||||
|
return ((String) value).startsWith("$");
|
||||||
|
}
|
||||||
|
|
||||||
if (!(value instanceof DBObject)) {
|
if (!(value instanceof DBObject)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -344,4 +319,192 @@ public class QueryMapper {
|
|||||||
return dbObject.keySet().size() == 1 && dbObject.keySet().iterator().next().startsWith("$");
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Spring Data MongoDB specific converter infrastructure.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.convert;
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ public class GeoResults<T> implements Iterable<GeoResult<T>> {
|
|||||||
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
|
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
|
||||||
|
|
||||||
if (results.isEmpty()) {
|
if (results.isEmpty()) {
|
||||||
return new Distance(0, null);
|
return new Distance(0, metric);
|
||||||
}
|
}
|
||||||
|
|
||||||
double averageDistance = 0;
|
double averageDistance = 0;
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support for MongoDB geo-spatial queries.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.geo;
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support for MongoDB document indexing.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.index;
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.mapping;
|
|||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
import java.beans.PropertyDescriptor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
@@ -51,7 +52,7 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||||
return !MongoSimpleTypes.HOLDER.isSimpleType(type.getType());
|
return !MongoSimpleTypes.HOLDER.isSimpleType(type.getType()) && !AbstractMap.class.isAssignableFrom(type.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Mapping event callback infrastructure for the MongoDB document-to-object mapping subsystem.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.mapping.event;
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Infrastructure for the MongoDB document-to-object mapping subsystem.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.mapping;
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support for MongoDB map-reduce operations.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core.mapreduce;
|
||||||
|
|
||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -39,6 +39,10 @@ import com.mongodb.DBObject;
|
|||||||
/**
|
/**
|
||||||
* Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple
|
* Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple
|
||||||
* criteria. Static import of the 'Criteria.where' method will improve readability.
|
* criteria. Static import of the 'Criteria.where' method will improve readability.
|
||||||
|
*
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class Criteria implements CriteriaDefinition {
|
public class Criteria implements CriteriaDefinition {
|
||||||
|
|
||||||
@@ -396,34 +400,54 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an 'or' criteria using the $or operator for all of the provided criteria
|
* Creates an 'or' criteria using the $or operator for all of the provided criteria
|
||||||
|
* <p>
|
||||||
|
* Note that mongodb doesn't support an $or operator to be wrapped in a $not operator.
|
||||||
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException if {@link #orOperator(Criteria...)} follows a not() call directly.
|
||||||
* @param criteria
|
* @param criteria
|
||||||
*/
|
*/
|
||||||
public Criteria orOperator(Criteria... criteria) {
|
public Criteria orOperator(Criteria... criteria) {
|
||||||
BasicDBList bsonList = createCriteriaList(criteria);
|
BasicDBList bsonList = createCriteriaList(criteria);
|
||||||
criteriaChain.add(new Criteria("$or").is(bsonList));
|
return registerCriteriaChainElement(new Criteria("$or").is(bsonList));
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a 'nor' criteria using the $nor operator for all of the provided criteria
|
* Creates a 'nor' criteria using the $nor operator for all of the provided criteria.
|
||||||
|
* <p>
|
||||||
|
* Note that mongodb doesn't support an $nor operator to be wrapped in a $not operator.
|
||||||
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException if {@link #norOperator(Criteria...)} follows a not() call directly.
|
||||||
* @param criteria
|
* @param criteria
|
||||||
*/
|
*/
|
||||||
public Criteria norOperator(Criteria... criteria) {
|
public Criteria norOperator(Criteria... criteria) {
|
||||||
BasicDBList bsonList = createCriteriaList(criteria);
|
BasicDBList bsonList = createCriteriaList(criteria);
|
||||||
criteriaChain.add(new Criteria("$nor").is(bsonList));
|
return registerCriteriaChainElement(new Criteria("$nor").is(bsonList));
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an 'and' criteria using the $and operator for all of the provided criteria
|
* Creates an 'and' criteria using the $and operator for all of the provided criteria.
|
||||||
|
* <p>
|
||||||
|
* Note that mongodb doesn't support an $and operator to be wrapped in a $not operator.
|
||||||
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException if {@link #andOperator(Criteria...)} follows a not() call directly.
|
||||||
* @param criteria
|
* @param criteria
|
||||||
*/
|
*/
|
||||||
public Criteria andOperator(Criteria... criteria) {
|
public Criteria andOperator(Criteria... criteria) {
|
||||||
BasicDBList bsonList = createCriteriaList(criteria);
|
BasicDBList bsonList = createCriteriaList(criteria);
|
||||||
criteriaChain.add(new Criteria("$and").is(bsonList));
|
return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Criteria registerCriteriaChainElement(Criteria criteria) {
|
||||||
|
|
||||||
|
if (lastOperatorWasNot()) {
|
||||||
|
throw new IllegalArgumentException("operator $not is not allowed around criteria chain element: "
|
||||||
|
+ criteria.getCriteriaObject());
|
||||||
|
} else {
|
||||||
|
criteriaChain.add(criteria);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,6 +492,7 @@ public class Criteria implements CriteriaDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBObject queryCriteria = new BasicDBObject();
|
DBObject queryCriteria = new BasicDBObject();
|
||||||
if (isValue != NOT_SET) {
|
if (isValue != NOT_SET) {
|
||||||
queryCriteria.put(this.key, this.isValue);
|
queryCriteria.put(this.key, this.isValue);
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
public class Field {
|
public class Field {
|
||||||
|
|
||||||
private Map<String, Integer> criteria = new HashMap<String, Integer>();
|
private final Map<String, Integer> criteria = new HashMap<String, Integer>();
|
||||||
|
private final Map<String, Object> slices = new HashMap<String, Object>();
|
||||||
private Map<String, Object> slices = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
public Field include(String key) {
|
public Field include(String key) {
|
||||||
criteria.put(key, Integer.valueOf(1));
|
criteria.put(key, Integer.valueOf(1));
|
||||||
@@ -50,11 +51,54 @@ public class Field {
|
|||||||
public DBObject getFieldsObject() {
|
public DBObject getFieldsObject() {
|
||||||
DBObject dbo = new BasicDBObject();
|
DBObject dbo = new BasicDBObject();
|
||||||
for (String k : criteria.keySet()) {
|
for (String k : criteria.keySet()) {
|
||||||
dbo.put(k, (criteria.get(k)));
|
dbo.put(k, criteria.get(k));
|
||||||
}
|
}
|
||||||
for (String k : slices.keySet()) {
|
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;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.query;
|
package org.springframework.data.mongodb.core.query;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.mongodb.core.geo.CustomMetric;
|
import org.springframework.data.mongodb.core.geo.CustomMetric;
|
||||||
import org.springframework.data.mongodb.core.geo.Distance;
|
import org.springframework.data.mongodb.core.geo.Distance;
|
||||||
import org.springframework.data.mongodb.core.geo.Metric;
|
import org.springframework.data.mongodb.core.geo.Metric;
|
||||||
@@ -29,6 +30,7 @@ import com.mongodb.DBObject;
|
|||||||
* Builder class to build near-queries.
|
* Builder class to build near-queries.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class NearQuery {
|
public class NearQuery {
|
||||||
|
|
||||||
@@ -38,6 +40,7 @@ public class NearQuery {
|
|||||||
private Metric metric;
|
private Metric metric;
|
||||||
private boolean spherical;
|
private boolean spherical;
|
||||||
private Integer num;
|
private Integer num;
|
||||||
|
private Integer skip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link NearQuery}.
|
* Creates a new {@link NearQuery}.
|
||||||
@@ -116,7 +119,7 @@ public class NearQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the number of results to return.
|
* Configures the maximum number of results to return.
|
||||||
*
|
*
|
||||||
* @param num
|
* @param num
|
||||||
* @return
|
* @return
|
||||||
@@ -126,6 +129,29 @@ public class NearQuery {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the number of results to skip.
|
||||||
|
*
|
||||||
|
* @param skip
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public NearQuery skip(int skip) {
|
||||||
|
this.skip = skip;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link Pageable} to use.
|
||||||
|
*
|
||||||
|
* @param pageable
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public NearQuery with(Pageable pageable) {
|
||||||
|
this.num = pageable.getOffset() + pageable.getPageSize();
|
||||||
|
this.skip = pageable.getOffset();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the max distance results shall have from the configured origin. If a {@link Metric} was set before the given
|
* Sets the max distance results shall have from the configured origin. If a {@link Metric} was set before the given
|
||||||
* value will be interpreted as being a value in that metric. E.g.
|
* value will be interpreted as being a value in that metric. E.g.
|
||||||
@@ -290,9 +316,18 @@ public class NearQuery {
|
|||||||
*/
|
*/
|
||||||
public NearQuery query(Query query) {
|
public NearQuery query(Query query) {
|
||||||
this.query = query;
|
this.query = query;
|
||||||
|
this.skip = query.getSkip();
|
||||||
|
this.num = query.getLimit();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of elements to skip.
|
||||||
|
*/
|
||||||
|
public Integer getSkip() {
|
||||||
|
return skip;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link DBObject} built by the {@link NearQuery}.
|
* Returns the {@link DBObject} built by the {@link NearQuery}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -46,22 +46,33 @@ public class Query {
|
|||||||
private String hint;
|
private String hint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static factory method to create a Query using the provided criteria
|
* Static factory method to create a {@link Query} using the provided {@link Criteria}.
|
||||||
*
|
*
|
||||||
* @param critera
|
* @param criteria must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Query query(Criteria critera) {
|
public static Query query(Criteria criteria) {
|
||||||
return new Query(critera);
|
return new Query(criteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query() {
|
public Query() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Query} using the given {@link Criteria}.
|
||||||
|
*
|
||||||
|
* @param criteria must not be {@literal null}.
|
||||||
|
*/
|
||||||
public Query(Criteria criteria) {
|
public Query(Criteria criteria) {
|
||||||
addCriteria(criteria);
|
addCriteria(criteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given {@link Criteria} to the current {@link Query}.
|
||||||
|
*
|
||||||
|
* @param criteria must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Query addCriteria(Criteria criteria) {
|
public Query addCriteria(Criteria criteria) {
|
||||||
CriteriaDefinition existing = this.criteria.get(criteria.getKey());
|
CriteriaDefinition existing = this.criteria.get(criteria.getKey());
|
||||||
String key = criteria.getKey();
|
String key = criteria.getKey();
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -52,7 +52,10 @@ public class Update {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@link Update} instance from the given {@link DBObject}. Allows to explicitly exlude fields from making
|
* Creates an {@link Update} instance from the given {@link DBObject}. Allows to explicitly exlude fields from making
|
||||||
* it into the created {@link Update} object.
|
* it into the created {@link Update} object. Note, that this will set attributes directly and <em>not</em> use
|
||||||
|
* {@literal $set}. This means fields not given in the {@link DBObject} will be nulled when executing the update. To
|
||||||
|
* create an only-updating {@link Update} instance of a {@link DBObject}, call {@link #set(String, Object)} for each
|
||||||
|
* value in it.
|
||||||
*
|
*
|
||||||
* @param object the source {@link DBObject} to create the update from.
|
* @param object the source {@link DBObject} to create the update from.
|
||||||
* @param exclude the fields to exclude.
|
* @param exclude the fields to exclude.
|
||||||
@@ -69,7 +72,7 @@ public class Update {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
update.set(key, object.get(key));
|
update.modifierOps.put(key, object.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
return update;
|
return update;
|
||||||
@@ -160,7 +163,7 @@ public class Update {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pop(String key, Position pos) {
|
public Update pop(String key, Position pos) {
|
||||||
addMultiFieldOperation("$pop", key, (pos == Position.FIRST ? -1 : 1));
|
addMultiFieldOperation("$pop", key, pos == Position.FIRST ? -1 : 1);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,22 +217,23 @@ public class Update {
|
|||||||
return dbo;
|
return dbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void addMultiFieldOperation(String operator, String key, Object value) {
|
protected void addMultiFieldOperation(String operator, String key, Object value) {
|
||||||
|
|
||||||
Object existingValue = this.modifierOps.get(operator);
|
Object existingValue = this.modifierOps.get(operator);
|
||||||
LinkedHashMap<String, Object> keyValueMap;
|
DBObject keyValueMap;
|
||||||
|
|
||||||
if (existingValue == null) {
|
if (existingValue == null) {
|
||||||
keyValueMap = new LinkedHashMap<String, Object>();
|
keyValueMap = new BasicDBObject();
|
||||||
this.modifierOps.put(operator, keyValueMap);
|
this.modifierOps.put(operator, keyValueMap);
|
||||||
} else {
|
} else {
|
||||||
if (existingValue instanceof LinkedHashMap) {
|
if (existingValue instanceof BasicDBObject) {
|
||||||
keyValueMap = (LinkedHashMap<String, Object>) existingValue;
|
keyValueMap = (BasicDBObject) existingValue;
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidDataAccessApiUsageException("Modifier Operations should be a LinkedHashMap but was "
|
throw new InvalidDataAccessApiUsageException("Modifier Operations should be a LinkedHashMap but was "
|
||||||
+ existingValue.getClass());
|
+ existingValue.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyValueMap.put(key, value);
|
keyValueMap.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support for MongoDB GridFS feature.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.gridfs;
|
||||||
|
|
||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,19 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.monitor;
|
package org.springframework.data.mongodb.monitor;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import com.mongodb.Mongo;
|
|
||||||
import org.springframework.jmx.export.annotation.ManagedMetric;
|
import org.springframework.jmx.export.annotation.ManagedMetric;
|
||||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||||
import org.springframework.jmx.support.MetricType;
|
import org.springframework.jmx.support.MetricType;
|
||||||
|
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose basic server information via JMX
|
* Expose basic server information via JMX
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@ManagedResource(description = "Server Information")
|
@ManagedResource(description = "Server Information")
|
||||||
public class ServerInfo extends AbstractMonitor {
|
public class ServerInfo extends AbstractMonitor {
|
||||||
@@ -36,9 +37,20 @@ public class ServerInfo extends AbstractMonitor {
|
|||||||
this.mongo = mongo;
|
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")
|
@ManagedOperation(description = "Server host name")
|
||||||
public String getHostName() throws UnknownHostException {
|
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")
|
@ManagedMetric(displayName = "Uptime Estimate")
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Spring Data's MongoDB abstraction.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb;
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* CDI support for MongoDB specific repository implementation.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.repository.cdi;
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support infrastructure for the configuration of MongoDB specific repositories.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.repository.config;
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ import org.springframework.util.Assert;
|
|||||||
* Base class for {@link RepositoryQuery} implementations for Mongo.
|
* Base class for {@link RepositoryQuery} implementations for Mongo.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractMongoQuery implements RepositoryQuery {
|
public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||||
|
|
||||||
@@ -257,6 +258,11 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
|||||||
nearQuery.maxDistance(maxDistance).in(maxDistance.getMetric());
|
nearQuery.maxDistance(maxDistance).in(maxDistance.getMetric());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pageable pageable = accessor.getPageable();
|
||||||
|
if (pageable != null) {
|
||||||
|
nearQuery.with(pageable);
|
||||||
|
}
|
||||||
|
|
||||||
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
||||||
return (GeoResults<Object>) operations.geoNear(nearQuery, metadata.getJavaType(), metadata.getCollectionName());
|
return (GeoResults<Object>) operations.geoNear(nearQuery, metadata.getJavaType(), metadata.getCollectionName());
|
||||||
}
|
}
|
||||||
@@ -264,7 +270,13 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
|||||||
private boolean isListOfGeoResult() {
|
private boolean isListOfGeoResult() {
|
||||||
|
|
||||||
TypeInformation<?> returnType = method.getReturnType();
|
TypeInformation<?> returnType = method.getReturnType();
|
||||||
return returnType.getType().equals(List.class) && GeoResult.class.equals(returnType.getComponentType());
|
|
||||||
|
if (!returnType.getType().equals(List.class)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInformation<?> componentType = returnType.getComponentType();
|
||||||
|
return componentType == null ? false : GeoResult.class.equals(componentType.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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) {
|
private String toLikeRegex(String source, Type type) {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case STARTING_WITH:
|
case STARTING_WITH:
|
||||||
source = source + "*";
|
source = "^" + source;
|
||||||
break;
|
break;
|
||||||
case ENDING_WITH:
|
case ENDING_WITH:
|
||||||
source = "*" + source;
|
source = source + "$";
|
||||||
break;
|
break;
|
||||||
case CONTAINING:
|
case CONTAINING:
|
||||||
source = "*" + source + "*";
|
source = "*" + source + "*";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
return source.replaceAll("\\*", ".*");
|
return source.replaceAll("\\*", ".*");
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Query derivation mechanism for MongoDB specific repositories.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.repository.query;
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Support infrastructure for query derivation of MongoDB specific repositories.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.repository.support;
|
||||||
|
|
||||||
@@ -11,8 +11,7 @@
|
|||||||
|
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/context"
|
<xsd:import namespace="http://www.springframework.org/schema/context" />
|
||||||
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
|
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
|
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
|
||||||
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd" />
|
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd" />
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
|
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/context"
|
<xsd:import namespace="http://www.springframework.org/schema/context" />
|
||||||
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
|
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
|
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
|
||||||
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
|
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
|
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
<xsd:import namespace="http://www.springframework.org/schema/beans" />
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
<xsd:import namespace="http://www.springframework.org/schema/tool" />
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/context"
|
<xsd:import namespace="http://www.springframework.org/schema/context" />
|
||||||
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
|
|
||||||
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
|
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
|
||||||
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
|
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ Defines a MongoDbFactory for connecting to a specific database
|
|||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
<xsd:complexType>
|
<xsd:complexType>
|
||||||
<xsd:attribute name="id" type="xsd:ID" use="optional">
|
<xsd:attribute name="id" type="xsd:string" use="optional">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The name of the mongo definition (by default "mongoDbFactory").]]></xsd:documentation>
|
The name of the mongo definition (by default "mongoDbFactory").]]></xsd:documentation>
|
||||||
@@ -157,7 +156,7 @@ The Mongo URI string.]]></xsd:documentation>
|
|||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
</xsd:sequence>
|
</xsd:sequence>
|
||||||
<xsd:attribute name="id" type="xsd:ID" use="optional">
|
<xsd:attribute name="id" type="xsd:string" use="optional">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The name of the MappingMongoConverter instance (by default "mappingConverter").]]></xsd:documentation>
|
The name of the MappingMongoConverter instance (by default "mappingConverter").]]></xsd:documentation>
|
||||||
@@ -336,7 +335,7 @@ The Mongo driver options
|
|||||||
<!-- MLP
|
<!-- MLP
|
||||||
<xsd:attributeGroup ref="writeConcern" />
|
<xsd:attributeGroup ref="writeConcern" />
|
||||||
-->
|
-->
|
||||||
<xsd:attribute name="id" type="xsd:ID" use="optional">
|
<xsd:attribute name="id" type="xsd:string" use="optional">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The name of the mongo definition (by default "mongo").]]></xsd:documentation>
|
The name of the mongo definition (by default "mongo").]]></xsd:documentation>
|
||||||
|
|||||||
@@ -19,8 +19,13 @@ import static org.hamcrest.Matchers.*;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
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.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;
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
@@ -63,6 +68,17 @@ public class AbstractMongoConfigurationUnitTests {
|
|||||||
assertScanningDisabled(" ");
|
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 {
|
private static void assertScanningDisabled(final String value) throws ClassNotFoundException {
|
||||||
|
|
||||||
AbstractMongoConfiguration configuration = new SampleMongoConfiguration() {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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}.
|
* Unit tests for {@link ServerAddressPropertyEditor}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class ServerAddressPropertyEditorUnitTests {
|
public class ServerAddressPropertyEditorUnitTests {
|
||||||
|
|
||||||
@@ -70,6 +71,16 @@ public class ServerAddressPropertyEditorUnitTests {
|
|||||||
assertSingleAddressOfLocalhost(editor.getValue());
|
assertSingleAddressOfLocalhost(editor.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-693
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void interpretEmptyStringAsNull() {
|
||||||
|
|
||||||
|
editor.setAsText("");
|
||||||
|
assertNull(editor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertSingleAddressOfLocalhost(Object result) throws UnknownHostException {
|
private static void assertSingleAddressOfLocalhost(Object result) throws UnknownHostException {
|
||||||
|
|
||||||
assertThat(result, is(instanceOf(ServerAddress[].class)));
|
assertThat(result, is(instanceOf(ServerAddress[].class)));
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import com.mongodb.WriteConcern;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
public class StringToWriteConcernConverterUnitTest {
|
public class StringToWriteConcernConverterUnitTests {
|
||||||
|
|
||||||
StringToWriteConcernConverter converter = new StringToWriteConcernConverter();
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,8 @@ import static org.junit.Assert.*;
|
|||||||
import static org.mockito.Matchers.*;
|
import static org.mockito.Matchers.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -28,7 +30,9 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationUtils;
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.Mongo;
|
import com.mongodb.Mongo;
|
||||||
@@ -37,12 +41,12 @@ import com.mongodb.Mongo;
|
|||||||
* Unit tests for {@link MongoDbUtils}.
|
* Unit tests for {@link MongoDbUtils}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Randy Watler
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class MongoDbUtilsUnitTests {
|
public class MongoDbUtilsUnitTests {
|
||||||
|
|
||||||
@Mock
|
@Mock Mongo mongo;
|
||||||
Mongo mongo;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -81,4 +85,94 @@ public class MongoDbUtilsUnitTests {
|
|||||||
assertThat(first, is(notNullValue()));
|
assertThat(first, is(notNullValue()));
|
||||||
assertThat(MongoDbUtils.getDB(mongo, "first"), is(sameInstance(first)));
|
assertThat(MongoDbUtils.getDB(mongo, "first"), is(sameInstance(first)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-737
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void handlesTransactionSynchronizationLifecycle() {
|
||||||
|
|
||||||
|
// ensure transaction synchronization manager has no registered
|
||||||
|
// transaction synchronizations or bound resources at start of test
|
||||||
|
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(true));
|
||||||
|
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
|
||||||
|
|
||||||
|
// access database for one mongo instance, (registers transaction
|
||||||
|
// synchronization and binds transaction resource)
|
||||||
|
MongoDbUtils.getDB(mongo, "first");
|
||||||
|
|
||||||
|
// ensure transaction synchronization manager has registered
|
||||||
|
// transaction synchronizations and bound resources
|
||||||
|
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(false));
|
||||||
|
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(false));
|
||||||
|
|
||||||
|
// simulate transaction completion, (unbinds transaction resource)
|
||||||
|
try {
|
||||||
|
simulateTransactionCompletion();
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("Unexpected exception thrown during transaction completion: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure transaction synchronization manager has no bound resources
|
||||||
|
// at end of test
|
||||||
|
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-737
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void handlesTransactionSynchronizationsLifecycle() {
|
||||||
|
|
||||||
|
// ensure transaction synchronization manager has no registered
|
||||||
|
// transaction synchronizations or bound resources at start of test
|
||||||
|
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(true));
|
||||||
|
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
|
||||||
|
|
||||||
|
// access multiple databases for one mongo instance, (registers
|
||||||
|
// transaction synchronizations and binds transaction resources)
|
||||||
|
MongoDbUtils.getDB(mongo, "first");
|
||||||
|
MongoDbUtils.getDB(mongo, "second");
|
||||||
|
|
||||||
|
// ensure transaction synchronization manager has registered
|
||||||
|
// transaction synchronizations and bound resources
|
||||||
|
assertThat(TransactionSynchronizationManager.getSynchronizations().isEmpty(), is(false));
|
||||||
|
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(false));
|
||||||
|
|
||||||
|
// simulate transaction completion, (unbinds transaction resources)
|
||||||
|
try {
|
||||||
|
simulateTransactionCompletion();
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("Unexpected exception thrown during transaction completion: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure transaction synchronization manager has no bound
|
||||||
|
// transaction resources at end of test
|
||||||
|
assertThat(TransactionSynchronizationManager.getResourceMap().isEmpty(), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulate transaction rollback/commit completion protocol on managed transaction synchronizations which will unbind
|
||||||
|
* managed transaction resources. Does not swallow exceptions for testing purposes.
|
||||||
|
*
|
||||||
|
* @see TransactionSynchronizationUtils#triggerBeforeCompletion()
|
||||||
|
* @see TransactionSynchronizationUtils#triggerAfterCompletion(int)
|
||||||
|
*/
|
||||||
|
private void simulateTransactionCompletion() {
|
||||||
|
|
||||||
|
// triggerBeforeCompletion() implementation without swallowed exceptions
|
||||||
|
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
|
||||||
|
for (TransactionSynchronization synchronization : synchronizations) {
|
||||||
|
synchronization.beforeCompletion();
|
||||||
|
}
|
||||||
|
|
||||||
|
// triggerAfterCompletion() implementation without swallowed exceptions
|
||||||
|
List<TransactionSynchronization> remainingSynchronizations = TransactionSynchronizationManager
|
||||||
|
.getSynchronizations();
|
||||||
|
if (remainingSynchronizations != null) {
|
||||||
|
for (TransactionSynchronization remainingSynchronization : remainingSynchronizations) {
|
||||||
|
remainingSynchronization.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.junit.Test;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.data.mongodb.config.ServerAddressPropertyEditor;
|
||||||
import org.springframework.data.mongodb.config.WriteConcernPropertyEditor;
|
import org.springframework.data.mongodb.config.WriteConcernPropertyEditor;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
import com.mongodb.WriteConcern;
|
import com.mongodb.WriteConcern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests for {@link MongoFactoryBean}.
|
* Integration tests for {@link MongoFactoryBean}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class MongoFactoryBeanIntegrationTest {
|
public class MongoFactoryBeanIntegrationTests {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see DATAMONGO-408
|
* @see DATAMONGO-408
|
||||||
@@ -49,4 +53,22 @@ public class MongoFactoryBeanIntegrationTest {
|
|||||||
MongoFactoryBean bean = factory.getBean("&factory", MongoFactoryBean.class);
|
MongoFactoryBean bean = factory.getBean("&factory", MongoFactoryBean.class);
|
||||||
assertThat(ReflectionTestUtils.getField(bean, "writeConcern"), is((Object) WriteConcern.SAFE));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core;
|
|||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||||
import static org.springframework.data.mongodb.core.query.Update.*;
|
import static org.springframework.data.mongodb.core.query.Update.*;
|
||||||
@@ -30,6 +31,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@@ -42,12 +44,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.dao.OptimisticLockingFailureException;
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
|
import org.springframework.data.annotation.Version;
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||||
|
import org.springframework.data.mongodb.MongoDataIntegrityViolationException;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
@@ -55,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.Index.Duplicates;
|
||||||
import org.springframework.data.mongodb.core.index.IndexField;
|
import org.springframework.data.mongodb.core.index.IndexField;
|
||||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Field;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
@@ -82,20 +88,18 @@ import com.mongodb.WriteResult;
|
|||||||
* @author Thomas Risberg
|
* @author Thomas Risberg
|
||||||
* @author Amol Nayak
|
* @author Amol Nayak
|
||||||
* @author Patryk Wasik
|
* @author Patryk Wasik
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration("classpath:infrastructure.xml")
|
@ContextConfiguration("classpath:infrastructure.xml")
|
||||||
public class MongoTemplateTests {
|
public class MongoTemplateTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired MongoTemplate template;
|
||||||
MongoTemplate template;
|
@Autowired MongoDbFactory factory;
|
||||||
@Autowired
|
|
||||||
MongoDbFactory factory;
|
|
||||||
|
|
||||||
MongoTemplate mappingTemplate;
|
MongoTemplate mappingTemplate;
|
||||||
|
|
||||||
@Rule
|
@Rule public ExpectedException thrown = ExpectedException.none();
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -145,7 +149,10 @@ public class MongoTemplateTests {
|
|||||||
template.dropCollection(TestClass.class);
|
template.dropCollection(TestClass.class);
|
||||||
template.dropCollection(Sample.class);
|
template.dropCollection(Sample.class);
|
||||||
template.dropCollection(MyPerson.class);
|
template.dropCollection(MyPerson.class);
|
||||||
|
template.dropCollection(TypeWithFieldAnnotation.class);
|
||||||
|
template.dropCollection(TypeWithDate.class);
|
||||||
template.dropCollection("collection");
|
template.dropCollection("collection");
|
||||||
|
template.dropCollection("personX");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -272,7 +279,8 @@ public class MongoTemplateTests {
|
|||||||
} catch (DataIntegrityViolationException e) {
|
} catch (DataIntegrityViolationException e) {
|
||||||
assertThat(
|
assertThat(
|
||||||
e.getMessage(),
|
e.getMessage(),
|
||||||
startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId"));
|
CoreMatchers
|
||||||
|
.startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,8 +773,7 @@ public class MongoTemplateTests {
|
|||||||
Query q3 = new Query(Criteria.where("age").in(l1, l2));
|
Query q3 = new Query(Criteria.where("age").in(l1, l2));
|
||||||
template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
|
template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
|
||||||
Assert.fail("Should have trown an InvalidDocumentStoreApiUsageException");
|
Assert.fail("Should have trown an InvalidDocumentStoreApiUsageException");
|
||||||
} catch (InvalidMongoDbApiUsageException e) {
|
} catch (InvalidMongoDbApiUsageException e) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -949,6 +956,7 @@ public class MongoTemplateTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void testUsingReadPreference() throws Exception {
|
public void testUsingReadPreference() throws Exception {
|
||||||
this.template.execute("readPref", new CollectionCallback<Object>() {
|
this.template.execute("readPref", new CollectionCallback<Object>() {
|
||||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||||
@@ -1318,6 +1326,18 @@ public class MongoTemplateTests {
|
|||||||
template.save(person);
|
template.save(person);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-617
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void doesNotFailOnVersionInitForUnversionedEntity() {
|
||||||
|
|
||||||
|
DBObject dbObject = new BasicDBObject();
|
||||||
|
dbObject.put("firstName", "Oliver");
|
||||||
|
|
||||||
|
template.insert(dbObject, template.determineCollectionName(PersonWithVersionPropertyOfTypeInteger.class));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see DATAMONGO-539
|
* @see DATAMONGO-539
|
||||||
*/
|
*/
|
||||||
@@ -1455,6 +1475,199 @@ public class MongoTemplateTests {
|
|||||||
assertThat(template.find(null, PersonWithIdPropertyOfTypeObjectId.class), is(result));
|
assertThat(template.find(null, PersonWithIdPropertyOfTypeObjectId.class), is(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-620
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void versionsObjectIntoDedicatedCollection() {
|
||||||
|
|
||||||
|
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
|
||||||
|
person.firstName = "Dave";
|
||||||
|
|
||||||
|
template.save(person, "personX");
|
||||||
|
assertThat(person.version, is(0));
|
||||||
|
|
||||||
|
template.save(person, "personX");
|
||||||
|
assertThat(person.version, is(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-621
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctlySetsLongVersionProperty() {
|
||||||
|
|
||||||
|
PersonWithVersionPropertyOfTypeLong person = new PersonWithVersionPropertyOfTypeLong();
|
||||||
|
person.firstName = "Dave";
|
||||||
|
|
||||||
|
template.save(person);
|
||||||
|
assertThat(person.version, is(0L));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-622
|
||||||
|
*/
|
||||||
|
@Test(expected = DuplicateKeyException.class)
|
||||||
|
public void preventsDuplicateInsert() {
|
||||||
|
|
||||||
|
template.setWriteConcern(WriteConcern.SAFE);
|
||||||
|
|
||||||
|
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
|
||||||
|
person.firstName = "Dave";
|
||||||
|
|
||||||
|
template.save(person);
|
||||||
|
assertThat(person.version, is(0));
|
||||||
|
|
||||||
|
person.version = null;
|
||||||
|
template.save(person);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-629
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void countAndFindWithoutTypeInformation() {
|
||||||
|
|
||||||
|
Person person = new Person();
|
||||||
|
template.save(person);
|
||||||
|
|
||||||
|
Query query = query(where("_id").is(person.getId()));
|
||||||
|
String collectionName = template.getCollectionName(Person.class);
|
||||||
|
|
||||||
|
assertThat(template.find(query, HashMap.class, collectionName), hasSize(1));
|
||||||
|
assertThat(template.count(query, collectionName), is(1L));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-571
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void nullsPropertiesForVersionObjectUpdates() {
|
||||||
|
|
||||||
|
VersionedPerson person = new VersionedPerson();
|
||||||
|
person.firstname = "Dave";
|
||||||
|
person.lastname = "Matthews";
|
||||||
|
|
||||||
|
template.save(person);
|
||||||
|
assertThat(person.id, is(notNullValue()));
|
||||||
|
|
||||||
|
person.lastname = null;
|
||||||
|
template.save(person);
|
||||||
|
|
||||||
|
person = template.findOne(query(where("id").is(person.id)), VersionedPerson.class);
|
||||||
|
assertThat(person.lastname, is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-571
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void nullsValuesForUpdatesOfUnversionedEntity() {
|
||||||
|
|
||||||
|
Person person = new Person("Dave");
|
||||||
|
template.save(person);
|
||||||
|
|
||||||
|
person.setFirstName(null);
|
||||||
|
template.save(person);
|
||||||
|
|
||||||
|
person = template.findOne(query(where("id").is(person.getId())), Person.class);
|
||||||
|
assertThat(person.getFirstName(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-651
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void throwsMongoSpecificExceptionForDataIntegrityViolations() {
|
||||||
|
|
||||||
|
WriteResult result = mock(WriteResult.class);
|
||||||
|
when(result.getError()).thenReturn("ERROR");
|
||||||
|
|
||||||
|
MongoActionOperation operation = MongoActionOperation.INSERT;
|
||||||
|
|
||||||
|
MongoTemplate mongoTemplate = new MongoTemplate(factory);
|
||||||
|
mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mongoTemplate.handleAnyWriteResultErrors(result, null, operation);
|
||||||
|
fail("Expected MonogoDataIntegrityViolationException!");
|
||||||
|
} catch (MongoDataIntegrityViolationException o_O) {
|
||||||
|
assertThat(o_O.getActionOperation(), is(operation));
|
||||||
|
assertThat(o_O.getWriteResult(), is(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 {
|
static class MyId {
|
||||||
|
|
||||||
String first;
|
String first;
|
||||||
@@ -1463,14 +1676,12 @@ public class MongoTemplateTests {
|
|||||||
|
|
||||||
static class TypeWithMyId {
|
static class TypeWithMyId {
|
||||||
|
|
||||||
@Id
|
@Id MyId id;
|
||||||
MyId id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Sample {
|
public static class Sample {
|
||||||
|
|
||||||
@Id
|
@Id String id;
|
||||||
String id;
|
|
||||||
String field;
|
String field;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1524,4 +1735,22 @@ public class MongoTemplateTests {
|
|||||||
String state;
|
String state;
|
||||||
String city;
|
String city;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class VersionedPerson {
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.mapping.Version;
|
import org.springframework.data.annotation.Version;
|
||||||
|
|
||||||
public class PersonWithVersionPropertyOfTypeInteger {
|
public class PersonWithVersionPropertyOfTypeInteger {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Version;
|
||||||
|
|
||||||
|
public class PersonWithVersionPropertyOfTypeLong {
|
||||||
|
|
||||||
|
String id;
|
||||||
|
String firstName;
|
||||||
|
int age;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
Long version;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PersonWithVersionPropertyOfTypeInteger [id=" + id + ", firstName=" + firstName + ", age=" + age
|
||||||
|
+ ", version=" + version + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.mockito.runners.MockitoJUnitRunner;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.event.ContextRefreshedEvent;
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
@@ -88,7 +87,7 @@ public class MappingMongoConverterUnitTests {
|
|||||||
|
|
||||||
mappingContext = new MongoMappingContext();
|
mappingContext = new MongoMappingContext();
|
||||||
mappingContext.setApplicationContext(context);
|
mappingContext.setApplicationContext(context);
|
||||||
mappingContext.onApplicationEvent(new ContextRefreshedEvent(context));
|
mappingContext.afterPropertiesSet();
|
||||||
|
|
||||||
converter = new MappingMongoConverter(factory, mappingContext);
|
converter = new MappingMongoConverter(factory, mappingContext);
|
||||||
converter.afterPropertiesSet();
|
converter.afterPropertiesSet();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2012 the original author or authors.
|
* Copyright 2011-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,6 +25,7 @@ import java.math.BigInteger;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.junit.Before;
|
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.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.DBObjectUtils;
|
import org.springframework.data.mongodb.core.DBObjectUtils;
|
||||||
import org.springframework.data.mongodb.core.Person;
|
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.DBRef;
|
||||||
import org.springframework.data.mongodb.core.mapping.Field;
|
import org.springframework.data.mongodb.core.mapping.Field;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
@@ -53,6 +55,7 @@ import com.mongodb.QueryBuilder;
|
|||||||
* Unit tests for {@link QueryMapper}.
|
* Unit tests for {@link QueryMapper}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Patryk Wasik
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class QueryMapperUnitTests {
|
public class QueryMapperUnitTests {
|
||||||
@@ -61,8 +64,7 @@ public class QueryMapperUnitTests {
|
|||||||
MongoMappingContext context;
|
MongoMappingContext context;
|
||||||
MappingMongoConverter converter;
|
MappingMongoConverter converter;
|
||||||
|
|
||||||
@Mock
|
@Mock MongoDbFactory factory;
|
||||||
MongoDbFactory factory;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -332,7 +334,11 @@ public class QueryMapperUnitTests {
|
|||||||
DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class));
|
DBObject result = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithDBRef.class));
|
||||||
|
|
||||||
DBObject reference = DBObjectUtils.getAsDBObject(result, "reference");
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -347,6 +353,91 @@ public class QueryMapperUnitTests {
|
|||||||
assertThat(object.get("reference"), is(nullValue()));
|
assertThat(object.get("reference"), is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-629
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void doesNotMapIdIfNoEntityMetadataAvailable() {
|
||||||
|
|
||||||
|
String id = new ObjectId().toString();
|
||||||
|
Query query = query(where("id").is(id));
|
||||||
|
|
||||||
|
DBObject object = mapper.getMappedObject(query.getQueryObject(), null);
|
||||||
|
|
||||||
|
assertThat(object.containsField("id"), is(true));
|
||||||
|
assertThat(object.get("id"), is((Object) id));
|
||||||
|
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 {
|
class IdWrapper {
|
||||||
Object id;
|
Object id;
|
||||||
}
|
}
|
||||||
@@ -359,14 +450,12 @@ public class QueryMapperUnitTests {
|
|||||||
|
|
||||||
class Sample {
|
class Sample {
|
||||||
|
|
||||||
@Id
|
@Id private String foo;
|
||||||
private String foo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BigIntegerId {
|
class BigIntegerId {
|
||||||
|
|
||||||
@Id
|
@Id private BigInteger id;
|
||||||
private BigInteger id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Enum {
|
enum Enum {
|
||||||
@@ -380,14 +469,13 @@ public class QueryMapperUnitTests {
|
|||||||
|
|
||||||
class CustomizedField {
|
class CustomizedField {
|
||||||
|
|
||||||
@Field("foo")
|
@Field("foo") CustomizedField field;
|
||||||
CustomizedField field;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WithDBRef {
|
class WithDBRef {
|
||||||
|
|
||||||
@DBRef
|
String someString;
|
||||||
Reference reference;
|
@DBRef Reference reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Reference {
|
class Reference {
|
||||||
@@ -399,4 +487,9 @@ public class QueryMapperUnitTests {
|
|||||||
|
|
||||||
WithDBRef withDbRef;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.data.mongodb.core.mapping;
|
package org.springframework.data.mongodb.core.mapping;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
@@ -37,14 +36,15 @@ import org.springframework.context.ApplicationContext;
|
|||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.data.annotation.Id;
|
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.MongoCollectionUtils;
|
||||||
import org.springframework.data.mongodb.core.CollectionCallback;
|
import org.springframework.data.mongodb.core.CollectionCallback;
|
||||||
import org.springframework.data.mongodb.core.MongoDbUtils;
|
import org.springframework.data.mongodb.core.MongoDbUtils;
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
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.data.mongodb.core.query.Query;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.DBCollection;
|
import com.mongodb.DBCollection;
|
||||||
@@ -53,7 +53,8 @@ import com.mongodb.Mongo;
|
|||||||
import com.mongodb.MongoException;
|
import com.mongodb.MongoException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
* @author Jon Brisbin
|
||||||
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
public class MappingTests {
|
public class MappingTests {
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ public class MappingTests {
|
|||||||
ApplicationContext applicationContext;
|
ApplicationContext applicationContext;
|
||||||
Mongo mongo;
|
Mongo mongo;
|
||||||
MongoTemplate template;
|
MongoTemplate template;
|
||||||
MongoMappingContext mappingContext;
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -89,7 +90,7 @@ public class MappingTests {
|
|||||||
}
|
}
|
||||||
applicationContext = new ClassPathXmlApplicationContext("/mapping.xml");
|
applicationContext = new ClassPathXmlApplicationContext("/mapping.xml");
|
||||||
template = applicationContext.getBean(MongoTemplate.class);
|
template = applicationContext.getBean(MongoTemplate.class);
|
||||||
mappingContext = (MongoMappingContext) ReflectionTestUtils.getField(template, "mappingContext");
|
mappingContext = template.getConverter().getMappingContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -464,7 +465,7 @@ public class MappingTests {
|
|||||||
template.insert(p4);
|
template.insert(p4);
|
||||||
|
|
||||||
Query q = query(where("id").in("1", "2"));
|
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);
|
List<PersonPojoStringId> people = template.find(q, PersonPojoStringId.class);
|
||||||
assertEquals(2, people.size());
|
assertEquals(2, people.size());
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 by the original author(s).
|
* Copyright 2011-2013 by the original author(s).
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,13 +13,12 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.data.mongodb.core.mapping;
|
package org.springframework.data.mongodb.core.mapping;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.util.AbstractMap;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -29,9 +28,7 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
|
||||||
import org.springframework.data.mapping.model.MappingException;
|
import org.springframework.data.mapping.model.MappingException;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
|
|
||||||
import com.mongodb.DBRef;
|
import com.mongodb.DBRef;
|
||||||
|
|
||||||
@@ -69,15 +66,14 @@ public class MongoMappingContextUnitTests {
|
|||||||
assertThat(context.getPersistentEntity(DBRef.class), is(nullValue()));
|
assertThat(context.getPersistentEntity(DBRef.class), is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-638
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void populatesAbstractMappingContextsApplicationCorrectly() {
|
public void doesNotCreatePersistentEntityForAbstractMap() {
|
||||||
|
|
||||||
MongoMappingContext context = new MongoMappingContext();
|
MongoMappingContext context = new MongoMappingContext();
|
||||||
context.setApplicationContext(applicationContext);
|
assertThat(context.getPersistentEntity(AbstractMap.class), is(nullValue()));
|
||||||
|
|
||||||
Field field = ReflectionUtils.findField(AbstractMappingContext.class, "applicationContext");
|
|
||||||
ReflectionUtils.makeAccessible(field);
|
|
||||||
assertThat(ReflectionUtils.getField(field, context), is(notNullValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClassWithMultipleIdProperties {
|
class ClassWithMultipleIdProperties {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration
|
@ContextConfiguration
|
||||||
public class ValidatingMongoEventListenerTest {
|
public class ValidatingMongoEventListenerTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
MongoTemplate mongoTemplate;
|
MongoTemplate mongoTemplate;
|
||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -24,6 +24,10 @@ import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
|||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
*/
|
||||||
public class CriteriaTests {
|
public class CriteriaTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -68,4 +72,50 @@ public class CriteriaTests {
|
|||||||
assertThat(left, is(not(right)));
|
assertThat(left, is(not(right)));
|
||||||
assertThat(right, is(not(left)));
|
assertThat(right, is(not(left)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-507
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionWhenTryingToNegateAndOperation() {
|
||||||
|
|
||||||
|
new Criteria() //
|
||||||
|
.not() //
|
||||||
|
.andOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-507
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionWhenTryingToNegateOrOperation() {
|
||||||
|
|
||||||
|
new Criteria() //
|
||||||
|
.not() //
|
||||||
|
.orOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-507
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldThrowExceptionWhenTryingToNegateNorOperation() {
|
||||||
|
|
||||||
|
new Criteria() //
|
||||||
|
.not() //
|
||||||
|
.norOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-507
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldNegateFollowingSimpleExpression() {
|
||||||
|
|
||||||
|
Criteria c = Criteria.where("age").not().gt(18).and("status").is("student");
|
||||||
|
DBObject co = c.getCriteriaObject();
|
||||||
|
|
||||||
|
assertThat(co, is(notNullValue()));
|
||||||
|
assertThat(co.toString(), is("{ \"age\" : { \"$not\" : { \"$gt\" : 18}} , \"status\" : \"student\"}"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,14 +19,18 @@ import static org.hamcrest.CoreMatchers.*;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.mongodb.core.geo.Distance;
|
import org.springframework.data.mongodb.core.geo.Distance;
|
||||||
import org.springframework.data.mongodb.core.geo.Metric;
|
import org.springframework.data.mongodb.core.geo.Metric;
|
||||||
import org.springframework.data.mongodb.core.geo.Metrics;
|
import org.springframework.data.mongodb.core.geo.Metrics;
|
||||||
|
import org.springframework.data.mongodb.core.geo.Point;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link NearQuery}.
|
* Unit tests for {@link NearQuery}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
public class NearQueryUnitTests {
|
public class NearQueryUnitTests {
|
||||||
|
|
||||||
@@ -75,4 +79,48 @@ public class NearQueryUnitTests {
|
|||||||
query = query.maxDistance(new Distance(200, Metrics.KILOMETERS));
|
query = query.maxDistance(new Distance(200, Metrics.KILOMETERS));
|
||||||
assertThat(query.getMetric(), is((Metric) Metrics.MILES));
|
assertThat(query.getMetric(), is((Metric) Metrics.MILES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldTakeSkipAndLimitSettingsFromGivenPageable() {
|
||||||
|
|
||||||
|
Pageable pageable = new PageRequest(3, 5);
|
||||||
|
NearQuery query = NearQuery.near(new Point(1, 1)).with(pageable);
|
||||||
|
|
||||||
|
assertThat(query.getSkip(), is(pageable.getPageNumber() * pageable.getPageSize()));
|
||||||
|
assertThat((Integer) query.toDBObject().get("num"), is((pageable.getPageNumber() + 1) * pageable.getPageSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldTakeSkipAndLimitSettingsFromGivenQuery() {
|
||||||
|
|
||||||
|
int limit = 10;
|
||||||
|
int skip = 5;
|
||||||
|
NearQuery query = NearQuery.near(new Point(1, 1)).query(
|
||||||
|
Query.query(Criteria.where("foo").is("bar")).limit(limit).skip(skip));
|
||||||
|
|
||||||
|
assertThat(query.getSkip(), is(skip));
|
||||||
|
assertThat((Integer) query.toDBObject().get("num"), is(limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldTakeSkipAndLimitSettingsFromPageableEvenIfItWasSpecifiedOnQuery() {
|
||||||
|
|
||||||
|
int limit = 10;
|
||||||
|
int skip = 5;
|
||||||
|
Pageable pageable = new PageRequest(3, 5);
|
||||||
|
NearQuery query = NearQuery.near(new Point(1, 1))
|
||||||
|
.query(Query.query(Criteria.where("foo").is("bar")).limit(limit).skip(skip)).with(pageable);
|
||||||
|
|
||||||
|
assertThat(query.getSkip(), is(pageable.getPageNumber() * pageable.getPageSize()));
|
||||||
|
assertThat((Integer) query.toDBObject().get("num"), is((pageable.getPageNumber() + 1) * pageable.getPageSize()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,28 +15,32 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.monitor;
|
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.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test class assumes that you are already running the MongoDB server.
|
* This test class assumes that you are already running the MongoDB server.
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration
|
@ContextConfiguration("classpath:infrastructure.xml")
|
||||||
public class MongoMonitorIntegrationTests {
|
public class MongoMonitorIntegrationTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired Mongo mongo;
|
||||||
Mongo mongo;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serverInfo() {
|
public void serverInfo() {
|
||||||
@@ -45,9 +49,29 @@ public class MongoMonitorIntegrationTests {
|
|||||||
Assert.isTrue(StringUtils.hasText("1."));
|
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
|
@Test
|
||||||
public void operationCounters() {
|
public void operationCounters() {
|
||||||
OperationCounters operationCounters = new OperationCounters(mongo);
|
OperationCounters operationCounters = new OperationCounters(mongo);
|
||||||
operationCounters.getInsertCount();
|
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.Criteria.*;
|
||||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -35,12 +39,15 @@ import org.springframework.core.Constants;
|
|||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
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.core.query.Query;
|
||||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
|
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StopWatch;
|
import org.springframework.util.StopWatch;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.BasicDBList;
|
import com.mongodb.BasicDBList;
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
@@ -60,29 +67,40 @@ import com.mongodb.WriteConcern;
|
|||||||
public class PerformanceTests {
|
public class PerformanceTests {
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "performance";
|
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 StopWatch watch = new StopWatch();
|
||||||
private static final Collection<String> IGNORED_WRITE_CONCERNS = Arrays.asList("MAJORITY", "REPLICAS_SAFE",
|
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 int COLLECTION_SIZE = 1024 * 1024 * 256; // 256 MB
|
||||||
private static final Collection<String> COLLECTION_NAMES = Arrays.asList("template", "driver", "person");
|
private static final Collection<String> COLLECTION_NAMES = Arrays.asList("template", "driver", "person");
|
||||||
|
|
||||||
Mongo mongo;
|
Mongo mongo;
|
||||||
MongoTemplate operations;
|
MongoTemplate operations;
|
||||||
PersonRepository repository;
|
PersonRepository repository;
|
||||||
|
MongoConverter converter;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
this.mongo = new Mongo();
|
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>();
|
MongoRepositoryFactoryBean<PersonRepository, Person, ObjectId> factory = new MongoRepositoryFactoryBean<PersonRepository, Person, ObjectId>();
|
||||||
factory.setMongoOperations(operations);
|
factory.setMongoOperations(operations);
|
||||||
factory.setRepositoryInterface(PersonRepository.class);
|
factory.setRepositoryInterface(PersonRepository.class);
|
||||||
factory.afterPropertiesSet();
|
factory.afterPropertiesSet();
|
||||||
|
|
||||||
repository = factory.getObject();
|
this.repository = factory.getObject();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -90,69 +108,137 @@ public class PerformanceTests {
|
|||||||
executeWithWriteConcerns(new WriteConcernCallback() {
|
executeWithWriteConcerns(new WriteConcernCallback() {
|
||||||
public void doWithWriteConcern(String constantName, WriteConcern concern) {
|
public void doWithWriteConcern(String constantName, WriteConcern concern) {
|
||||||
writeHeadline("WriteConcern: " + constantName);
|
writeHeadline("WriteConcern: " + constantName);
|
||||||
writingObjectsUsingPlainDriver("Writing %s objects using plain driver");
|
System.out.println(String.format("Writing %s objects using plain driver took %sms", NUMBER_OF_PERSONS,
|
||||||
writingObjectsUsingMongoTemplate("Writing %s objects using template");
|
writingObjectsUsingPlainDriver(NUMBER_OF_PERSONS)));
|
||||||
writingObjectsUsingRepositories("Writing %s objects using repository");
|
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();
|
writeFooter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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);
|
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();
|
setupCollections();
|
||||||
|
|
||||||
writeHeadline("Plain driver");
|
statistics.registerTime(Api.DRIVER, Mode.WRITE, writingObjectsUsingPlainDriver(numberOfPersons));
|
||||||
writingObjectsUsingPlainDriver("Writing %s objects using plain driver");
|
statistics.registerTime(Api.TEMPLATE, Mode.WRITE, writingObjectsUsingMongoTemplate(numberOfPersons));
|
||||||
readingUsingPlainDriver("Reading all objects using plain driver");
|
statistics.registerTime(Api.REPOSITORY, Mode.WRITE, writingObjectsUsingRepositories(numberOfPersons));
|
||||||
queryUsingPlainDriver("Executing query using plain driver");
|
|
||||||
writeFooter();
|
|
||||||
|
|
||||||
writeHeadline("Template");
|
statistics.registerTime(Api.DRIVER, Mode.READ, readingUsingPlainDriver());
|
||||||
writingObjectsUsingMongoTemplate("Writing %s objects using template");
|
statistics.registerTime(Api.TEMPLATE, Mode.READ, readingUsingTemplate());
|
||||||
readingUsingTemplate("Reading all objects using template");
|
statistics.registerTime(Api.REPOSITORY, Mode.READ, readingUsingRepository());
|
||||||
queryUsingTemplate("Executing query using template");
|
|
||||||
writeFooter();
|
|
||||||
|
|
||||||
writeHeadline("Repositories");
|
statistics.registerTime(Api.DRIVER, Mode.QUERY, queryUsingPlainDriver());
|
||||||
writingObjectsUsingRepositories("Writing %s objects using repository");
|
statistics.registerTime(Api.TEMPLATE, Mode.QUERY, queryUsingTemplate());
|
||||||
readingUsingRepository("Reading all objects using repository");
|
statistics.registerTime(Api.REPOSITORY, Mode.QUERY, queryUsingRepository());
|
||||||
queryUsingRepository("Executing query using repository");
|
|
||||||
writeFooter();
|
|
||||||
|
|
||||||
writeFooter();
|
if (i > 0 && i % (iterations / 10) == 0) {
|
||||||
|
statistics.printResults(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statistics.printResults(iterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeHeadline(String headline) {
|
private void writeHeadline(String headline) {
|
||||||
System.out.println(headline);
|
System.out.println(headline);
|
||||||
System.out.println("---------------------------------".substring(0, headline.length()));
|
System.out.println(createUnderline(headline));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeFooter() {
|
private void writeFooter() {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queryUsingTemplate(String template) {
|
private long queryUsingTemplate() {
|
||||||
executeWatchedWithTimeAndResultSize(template, new WatchCallback<List<Person>>() {
|
executeWatched(new WatchCallback<List<Person>>() {
|
||||||
public List<Person> doInWatch() {
|
public List<Person> doInWatch() {
|
||||||
Query query = query(where("addresses.zipCode").regex(".*1.*"));
|
Query query = query(where("addresses.zipCode").regex(".*1.*"));
|
||||||
return operations.find(query, Person.class, "template");
|
return operations.find(query, Person.class, "template");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return watch.getLastTaskTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queryUsingRepository(String template) {
|
private long queryUsingRepository() {
|
||||||
executeWatchedWithTimeAndResultSize(template, new WatchCallback<List<Person>>() {
|
executeWatched(new WatchCallback<List<Person>>() {
|
||||||
public List<Person> doInWatch() {
|
public List<Person> doInWatch() {
|
||||||
return repository.findByAddressesZipCodeContaining("1");
|
return repository.findByAddressesZipCodeContaining("1");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return watch.getLastTaskTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeWithWriteConcerns(WriteConcernCallback callback) {
|
private void executeWithWriteConcerns(WriteConcernCallback callback) {
|
||||||
@@ -181,7 +267,7 @@ public class PerformanceTests {
|
|||||||
for (String collectionName : COLLECTION_NAMES) {
|
for (String collectionName : COLLECTION_NAMES) {
|
||||||
DBCollection collection = db.getCollection(collectionName);
|
DBCollection collection = db.getCollection(collectionName);
|
||||||
collection.drop();
|
collection.drop();
|
||||||
db.command(getCreateCollectionCommand(collectionName));
|
collection.getDB().command(getCreateCollectionCommand(collectionName));
|
||||||
collection.ensureIndex(new BasicDBObject("firstname", -1));
|
collection.ensureIndex(new BasicDBObject("firstname", -1));
|
||||||
collection.ensureIndex(new BasicDBObject("lastname", -1));
|
collection.ensureIndex(new BasicDBObject("lastname", -1));
|
||||||
}
|
}
|
||||||
@@ -195,38 +281,42 @@ public class PerformanceTests {
|
|||||||
return dbObject;
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writingObjectsUsingPlainDriver(String template) {
|
private long writingObjectsUsingPlainDriver(int numberOfPersons) {
|
||||||
|
|
||||||
final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
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() {
|
public Void doInWatch() {
|
||||||
for (DBObject person : persons) {
|
for (Person person : persons) {
|
||||||
collection.save(person);
|
collection.save(person.toDBObject());
|
||||||
}
|
}
|
||||||
return null;
|
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() {
|
public Void doInWatch() {
|
||||||
repository.save(persons);
|
repository.save(persons);
|
||||||
return null;
|
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() {
|
public Void doInWatch() {
|
||||||
for (Person person : persons) {
|
for (Person person : persons) {
|
||||||
operations.save(person, "template");
|
operations.save(person, "template");
|
||||||
@@ -234,82 +324,95 @@ public class PerformanceTests {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return watch.getLastTaskTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readingUsingPlainDriver(String template) {
|
private long readingUsingPlainDriver() {
|
||||||
|
|
||||||
final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
executeWatched(new WatchCallback<List<Person>>() {
|
||||||
|
|
||||||
executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback<List<Person>>() {
|
|
||||||
public List<Person> doInWatch() {
|
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) {
|
private long readingUsingTemplate() {
|
||||||
executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback<List<Person>>() {
|
executeWatched(new WatchCallback<List<Person>>() {
|
||||||
public List<Person> doInWatch() {
|
public List<Person> doInWatch() {
|
||||||
return operations.findAll(Person.class, "template");
|
return operations.findAll(Person.class, "template");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return watch.getLastTaskTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readingUsingRepository(String template) {
|
private long readingUsingRepository() {
|
||||||
executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback<List<Person>>() {
|
executeWatched(new WatchCallback<List<Person>>() {
|
||||||
public List<Person> doInWatch() {
|
public List<Person> doInWatch() {
|
||||||
return repository.findAll();
|
return repository.findAll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return watch.getLastTaskTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queryUsingPlainDriver(String template) {
|
private long queryUsingPlainDriver() {
|
||||||
|
|
||||||
final DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
executeWatched(new WatchCallback<List<Person>>() {
|
||||||
|
|
||||||
executeWatchedWithTimeAndResultSize(template, new WatchCallback<List<Person>>() {
|
|
||||||
public List<Person> doInWatch() {
|
public List<Person> doInWatch() {
|
||||||
|
|
||||||
|
DBCollection collection = mongo.getDB(DATABASE_NAME).getCollection("driver");
|
||||||
|
|
||||||
DBObject regex = new BasicDBObject("$regex", Pattern.compile(".*1.*"));
|
DBObject regex = new BasicDBObject("$regex", Pattern.compile(".*1.*"));
|
||||||
DBObject query = new BasicDBObject("addresses.zipCode", regex);
|
DBObject query = new BasicDBObject("addresses.zipCode", regex);
|
||||||
return toPersons(collection.find(query));
|
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()) {
|
for (int i = 0; i < numberOfPersons; i++) {
|
||||||
result.add(person.toDBObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
result.add(person);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch.stop();
|
|
||||||
|
|
||||||
return result;
|
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 {
|
try {
|
||||||
return callback.doInWatch();
|
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) {
|
private static List<Person> toPersons(DBCursor cursor) {
|
||||||
|
|
||||||
List<Person> persons = new ArrayList<Person>();
|
List<Person> persons = new ArrayList<Person>();
|
||||||
@@ -354,10 +435,9 @@ public class PerformanceTests {
|
|||||||
static class Person {
|
static class Person {
|
||||||
|
|
||||||
ObjectId id;
|
ObjectId id;
|
||||||
@Indexed
|
String firstname, lastname;
|
||||||
final String firstname, lastname;
|
List<Address> addresses;
|
||||||
final List<Address> addresses;
|
Set<Order> orders;
|
||||||
final Set<Order> orders;
|
|
||||||
|
|
||||||
public Person(String firstname, String lastname, List<Address> addresses) {
|
public Person(String firstname, String lastname, List<Address> addresses) {
|
||||||
this.firstname = firstname;
|
this.firstname = firstname;
|
||||||
@@ -579,11 +659,253 @@ public class PerformanceTests {
|
|||||||
DBObject toDBObject();
|
DBObject toDBObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<DBObject> writeAll(Collection<? extends Convertible> convertibles) {
|
private static BasicDBList writeAll(Collection<? extends Convertible> convertibles) {
|
||||||
List<DBObject> result = new ArrayList<DBObject>();
|
BasicDBList result = new BasicDBList();
|
||||||
for (Convertible convertible : convertibles) {
|
for (Convertible convertible : convertibles) {
|
||||||
result.add(convertible.toDBObject());
|
result.add(convertible.toDBObject());
|
||||||
}
|
}
|
||||||
return result;
|
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)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
public abstract class AbstractPersonRepositoryIntegrationTests {
|
public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired protected PersonRepository repository;
|
||||||
protected PersonRepository repository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired MongoOperations operations;
|
||||||
MongoOperations operations;
|
|
||||||
|
|
||||||
Person dave, oliver, carter, boyd, stefan, leroi, alicia;
|
Person dave, oliver, carter, boyd, stefan, leroi, alicia;
|
||||||
QPerson person;
|
QPerson person;
|
||||||
@@ -546,4 +544,116 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
|||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
assertThat(result, hasItem(dave));
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void executesGeoPageQueryForWithPageRequestForPageInBetween() {
|
||||||
|
|
||||||
|
Point farAway = new Point(-73.9, 40.7);
|
||||||
|
Point here = new Point(-73.99, 40.73);
|
||||||
|
|
||||||
|
dave.setLocation(farAway);
|
||||||
|
oliver.setLocation(here);
|
||||||
|
carter.setLocation(here);
|
||||||
|
boyd.setLocation(here);
|
||||||
|
leroi.setLocation(here);
|
||||||
|
|
||||||
|
repository.save(Arrays.asList(dave, oliver, carter, boyd, leroi));
|
||||||
|
|
||||||
|
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
|
||||||
|
Metrics.KILOMETERS), new PageRequest(1, 2));
|
||||||
|
|
||||||
|
assertThat(results.getContent().isEmpty(), is(false));
|
||||||
|
assertThat(results.getNumberOfElements(), is(2));
|
||||||
|
assertThat(results.isFirstPage(), is(false));
|
||||||
|
assertThat(results.isLastPage(), is(false));
|
||||||
|
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||||
|
assertThat(results.getAverageDistance().getNormalizedValue(), is(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void executesGeoPageQueryForWithPageRequestForPageAtTheEnd() {
|
||||||
|
|
||||||
|
Point point = new Point(-73.99171, 40.738868);
|
||||||
|
|
||||||
|
dave.setLocation(point);
|
||||||
|
oliver.setLocation(point);
|
||||||
|
carter.setLocation(point);
|
||||||
|
|
||||||
|
repository.save(Arrays.asList(dave, oliver, carter));
|
||||||
|
|
||||||
|
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
|
||||||
|
Metrics.KILOMETERS), new PageRequest(1, 2));
|
||||||
|
assertThat(results.getContent().isEmpty(), is(false));
|
||||||
|
assertThat(results.getNumberOfElements(), is(1));
|
||||||
|
assertThat(results.isFirstPage(), is(false));
|
||||||
|
assertThat(results.isLastPage(), is(true));
|
||||||
|
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void executesGeoPageQueryForWithPageRequestForJustOneElement() {
|
||||||
|
|
||||||
|
Point point = new Point(-73.99171, 40.738868);
|
||||||
|
dave.setLocation(point);
|
||||||
|
repository.save(dave);
|
||||||
|
|
||||||
|
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
|
||||||
|
Metrics.KILOMETERS), new PageRequest(0, 2));
|
||||||
|
|
||||||
|
assertThat(results.getContent().isEmpty(), is(false));
|
||||||
|
assertThat(results.getNumberOfElements(), is(1));
|
||||||
|
assertThat(results.isFirstPage(), is(true));
|
||||||
|
assertThat(results.isLastPage(), is(true));
|
||||||
|
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATAMONGO-445
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void executesGeoPageQueryForWithPageRequestForJustOneElementEmptyPage() {
|
||||||
|
|
||||||
|
dave.setLocation(new Point(-73.99171, 40.738868));
|
||||||
|
repository.save(dave);
|
||||||
|
|
||||||
|
GeoPage<Person> results = repository.findByLocationNear(new Point(-73.99, 40.73), new Distance(2000,
|
||||||
|
Metrics.KILOMETERS), new PageRequest(1, 2));
|
||||||
|
|
||||||
|
assertThat(results.getContent().isEmpty(), is(true));
|
||||||
|
assertThat(results.getNumberOfElements(), is(0));
|
||||||
|
assertThat(results.isFirstPage(), is(false));
|
||||||
|
assertThat(results.isLastPage(), is(true));
|
||||||
|
assertThat(results.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
|||||||
*/
|
*/
|
||||||
List<Person> findByLastname(String lastname);
|
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.
|
* 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);
|
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Matt"), context);
|
||||||
Query query = creator.createQuery();
|
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);
|
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "ews"), context);
|
||||||
Query query = creator.createQuery();
|
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/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">
|
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" />
|
<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/why-sd-doc.xml"/>
|
||||||
<xi:include href="introduction/requirements.xml"/>
|
<xi:include href="introduction/requirements.xml"/>
|
||||||
<xi:include href="introduction/getting-started.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://raw.github.com/SpringSource/spring-data-commons/1.5.3.RELEASE/src/docbkx/repositories.xml">
|
||||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repositories.xml" />
|
<xi:fallback href="../../../spring-data-commons/src/docbkx/repositories.xml" />
|
||||||
</xi:include>
|
</xi:include>
|
||||||
</part>
|
</part>
|
||||||
@@ -72,10 +72,10 @@
|
|||||||
<part id="appendix">
|
<part id="appendix">
|
||||||
<title>Appendix</title>
|
<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.3.RELEASE/src/docbkx/repository-namespace-reference.xml">
|
||||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml" />
|
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml" />
|
||||||
</xi:include>
|
</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.3.RELEASE/src/docbkx/repository-query-keywords-reference.xml">
|
||||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml" />
|
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml" />
|
||||||
</xi:include>
|
</xi:include>
|
||||||
</part>
|
</part>
|
||||||
|
|||||||
BIN
src/docbkx/reference/jconsole.png
Normal file
BIN
src/docbkx/reference/jconsole.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -542,4 +542,52 @@ Page<Person> page = repository.findAll(person.lastname.contains("a"),
|
|||||||
MongoDB queries.</para>
|
MongoDB queries.</para>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Miscellaneous</title>
|
||||||
|
|
||||||
|
<para/>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>CDI Integration</title>
|
||||||
|
|
||||||
|
<para>Instances of the repository interfaces are usually created by a
|
||||||
|
container, which Spring is the most natural choice when working with
|
||||||
|
Spring Data. As of version 1.3.0 Spring Data MongoDB ships with a custom
|
||||||
|
CDI extension that allows using the repository abstraction in CDI
|
||||||
|
environments. The extension is part of the JAR so all you need to do to
|
||||||
|
activate it is dropping the Spring Data MongoDB JAR into your classpath.
|
||||||
|
You can now set up the infrastructure by implementing a CDI Producer for
|
||||||
|
the <classname>MongoTemplate</classname>:</para>
|
||||||
|
|
||||||
|
<programlisting language="java">class MongoTemplateProducer {
|
||||||
|
|
||||||
|
@Produces
|
||||||
|
@ApplicationScoped
|
||||||
|
public MongoOperations createMongoTemplate() throws UnknownHostException, MongoException {
|
||||||
|
|
||||||
|
MongoDbFactory factory = new SimpleMongoDbFactory(new Mongo(), "database");
|
||||||
|
return new MongoTemplate(factory);
|
||||||
|
}
|
||||||
|
}</programlisting>
|
||||||
|
|
||||||
|
<para>The Spring Data MongoDB CDI extension will pick up the
|
||||||
|
<classname>MongoTemplate</classname> available as CDI bean and create a
|
||||||
|
proxy for a Spring Data repository whenever an bean of a repository type
|
||||||
|
is requested by the container. Thus obtaining an instance of a Spring
|
||||||
|
Data repository is a matter of declaring an <code>@Inject</code>-ed
|
||||||
|
property:</para>
|
||||||
|
|
||||||
|
<programlisting language="java">class RepositoryClient {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PersonRepository repository;
|
||||||
|
|
||||||
|
public void businessMethod() {
|
||||||
|
|
||||||
|
List<Person> people = repository.findAll();
|
||||||
|
}
|
||||||
|
}</programlisting>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -1,6 +1,77 @@
|
|||||||
Spring Data MongoDB Changelog
|
Spring Data MongoDB Changelog
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
|
Changes in version 1.2.4.GA (2013-09-30)
|
||||||
|
----------------------------------------
|
||||||
|
** Bug
|
||||||
|
* [DATAMONGO-445] - GeoNear Query Doesn't Work with Pageable
|
||||||
|
* [DATAMONGO-602] - Querying with $in operator on the id field of type BigInteger returns zero results
|
||||||
|
* [DATAMONGO-737] - Extra MongoSynchronizations cause TransactionSynchronizationManager to throw IllegalStateException on transaction complete
|
||||||
|
** Task
|
||||||
|
* [DATAMONGO-742] - Document CDI integration in reference documentation
|
||||||
|
* [DATAMONGO-755] - Release 1.2.4
|
||||||
|
|
||||||
|
Changes in version 1.2.3.GA (2013-07-24)
|
||||||
|
----------------------------------------
|
||||||
|
** Task
|
||||||
|
* [DATAMONGO-728] - Add missing package-info.java files
|
||||||
|
* [DATAMONGO-729] - Release 1.2.3.
|
||||||
|
|
||||||
|
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
|
||||||
|
* [DATAMONGO-571] - Spring Data for MongoDb doesn't save null values when @Version is added to domain class
|
||||||
|
* [DATAMONGO-612] - Fix PDF reference documentation name
|
||||||
|
* [DATAMONGO-613] - Images missing from reference documentation
|
||||||
|
* [DATAMONGO-617] - NullPointerException in MongoTemplate.initializeVersionProperty(…)
|
||||||
|
* [DATAMONGO-620] - MongoTemplate.doSaveVersioned(…) does not consider collection handed into the method
|
||||||
|
* [DATAMONGO-621] - MongoTemplate.initializeVersionProperty(…) does not use ConversionService
|
||||||
|
* [DATAMONGO-622] - An unversioned object should be created using insert(…) instead of save.
|
||||||
|
* [DATAMONGO-629] - Different results when using count and find with the same criteria with 'id' field
|
||||||
|
* [DATAMONGO-638] - MappingContext should not create PersistentEntity instances for native maps
|
||||||
|
* [DATAMONGO-640] - MongoLog4jAppender suffers from potential NullPointerException when closing Mongo instance
|
||||||
|
* [DATAMONGO-641] - MongoLog4jAppender suffers from potential NullPointerException when closing Mongo instance
|
||||||
|
* [DATAMONGO-642] - MongoChangeSetPersister does not use mapped collection name
|
||||||
|
* [DATAMONGO-646] - Can't insert DBObjects through MongoTemplate
|
||||||
|
* [DATAMONGO-648] - ID attributes in namespace shouldn't be XSD IDs
|
||||||
|
|
||||||
|
** Improvement
|
||||||
|
* [DATAMONGO-594] - cross-store=> Define document name using annotation
|
||||||
|
* [DATAMONGO-632] - Polish namespace XSD to avoid errors in STS
|
||||||
|
* [DATAMONGO-635] - Fix some Sonar warnings
|
||||||
|
* [DATAMONGO-637] - Typo in Query.query(…)
|
||||||
|
* [DATAMONGO-651] - WriteResult not available from thrown Exception
|
||||||
|
* [DATAMONGO-656] - Potential NullPointerException when debugging in MongoTemplate
|
||||||
|
|
||||||
|
** Task
|
||||||
|
* [DATAMONGO-597] - Website is severely out-of-date
|
||||||
|
* [DATAMONGO-654] - Release 1.2.1
|
||||||
|
|
||||||
Changes in version 1.2.0.GA (2013-02-08)
|
Changes in version 1.2.0.GA (2013-02-08)
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
** Bug
|
** Bug
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Spring Data Document 1.1.2
|
Spring Data Document 1.2.4
|
||||||
Copyright (c) [2010-2013] SpringSource, a division of VMware, Inc.
|
Copyright (c) [2010-2013] Pivotal, Inc.
|
||||||
|
|
||||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||||
You may not use this product except in compliance with the License.
|
You may not use this product except in compliance with the License.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
SPRING DATA MongoDB 1.0.0.M5
|
SPRING DATA MongoDB 1.2.3.GA
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
Spring Data MongoDB is released under the terms of the Apache Software License Version 2.0 (see license.txt).
|
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