├── .gitignore
├── .travis.yml
├── LICENSE
├── jpa-projections
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ ├── Customer.java
│ │ ├── CustomerDto.java
│ │ ├── CustomerProjection.java
│ │ ├── CustomerRepository.java
│ │ ├── CustomerSummary.java
│ │ └── package-info.java
│ └── test
│ └── java
│ └── example
│ └── CustomerRepositoryIntegrationTest.java
├── jpa-query-by-example
├── README.md
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ ├── SpecialUser.java
│ │ ├── User.java
│ │ ├── UserRepository.java
│ │ └── package-info.java
│ └── test
│ └── java
│ └── example
│ ├── ApplicationConfiguration.java
│ ├── UserRepositoryInheritanceIntegrationTests.java
│ └── UserRepositoryIntegrationTests.java
├── jpa-query-method-wrapped-parameters
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ ├── Person.java
│ │ ├── PersonRepository.java
│ │ └── package-info.java
│ └── test
│ └── java
│ └── example
│ └── PersonRepositoryIntegrationTests.java
├── mongodb-composed-annotations
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ ├── FindWalter.java
│ │ ├── ImprovedVenue.java
│ │ ├── MyGeoIndexAnnotation.java
│ │ ├── Person.java
│ │ ├── PersonRepository.java
│ │ └── Venue.java
│ └── test
│ └── java
│ └── example
│ ├── ApplicationConfiguration.java
│ ├── ComposedAnnotationIntegrationTest.java
│ └── RepositoryIntegrationTest.java
├── mongodb-query-by-example
├── README.md
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ ├── Contact.java
│ │ ├── ContactRepository.java
│ │ ├── Person.java
│ │ ├── Relative.java
│ │ ├── RelativeRepository.java
│ │ ├── UserRepository.java
│ │ └── package-info.java
│ └── test
│ └── java
│ └── example
│ ├── ApplicationConfiguration.java
│ ├── ContactRepositoryIntegrationTests.java
│ ├── MongoOperationsIntegrationTests.java
│ └── UserRepositoryIntegrationTests.java
├── mongodb-reactive
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ ├── Person.java
│ │ ├── ReactivePersonRepository.java
│ │ ├── ReactorPersonRepository.java
│ │ └── RxJavaPersonRepository.java
│ └── test
│ ├── java
│ └── example
│ │ ├── ApplicationConfiguration.java
│ │ ├── ReactiveMongoOperationsIntegrationTests.java
│ │ ├── ReactivePersonRepositoryIntegrationTests.java
│ │ ├── ReactorPersonRepositoryIntegrationTests.java
│ │ └── RxJavaPersonRepositoryIntegrationTests.java
│ └── resources
│ └── application.properties
├── pom.xml
├── readme.adoc
├── redis-cluster
├── .gitignore
├── Makefile
├── pom.xml
├── readme.md
└── src
│ ├── main
│ └── java
│ │ └── example
│ │ └── AppConfig.java
│ └── test
│ ├── java
│ └── example
│ │ └── BasicUsageTests.java
│ └── resources
│ └── application.properties
└── redis-repositories
├── .gitignore
├── pom.xml
└── src
├── main
└── java
│ └── example
│ ├── City.java
│ ├── Person.java
│ └── PersonRepository.java
└── test
└── java
└── example
├── EmbeddedRedisRule.java
├── RedisRepositoryTests.java
└── RedisTestConfiguration.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | .springBeans
4 | .settings/
5 | target/
6 |
7 | #IntelliJ Stuff
8 | .idea
9 | *.iml
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | jdk:
4 | - oraclejdk8
5 |
6 | cache:
7 | directories:
8 | - $HOME/.m2
9 | - $HOME/.embedmongo
10 |
11 | sudo: false
12 |
13 | install: make -C redis-cluster start
14 |
15 | script: "mvn clean dependency:list test -Dsort"
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/jpa-projections/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | com.springone.2016
7 | whats-new-in-spring-data
8 | 1.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-data-jpa-projections
12 | What's new in Spring Data? - JPA Projections
13 |
14 |
15 | Hopper-SR2
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-jpa
23 |
24 |
25 |
26 | org.hsqldb
27 | hsqldb
28 | runtime
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/jpa-projections/src/main/java/example/Customer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import javax.persistence.Entity;
19 | import javax.persistence.GeneratedValue;
20 | import javax.persistence.Id;
21 |
22 | import lombok.Data;
23 | import lombok.RequiredArgsConstructor;
24 |
25 | /**
26 | * @author Oliver Gierke
27 | */
28 | @Data
29 | @Entity
30 | @RequiredArgsConstructor
31 | public class Customer {
32 |
33 | private @GeneratedValue @Id Long id;
34 | private final String firstname, lastname;
35 |
36 | protected Customer() {
37 | this.firstname = null;
38 | this.lastname = null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/jpa-projections/src/main/java/example/CustomerDto.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import lombok.Data;
19 | import lombok.RequiredArgsConstructor;
20 |
21 | /**
22 | * @author Oliver Gierke
23 | */
24 | @Data
25 | @RequiredArgsConstructor
26 | public class CustomerDto {
27 |
28 | private final String firstname;
29 | }
30 |
--------------------------------------------------------------------------------
/jpa-projections/src/main/java/example/CustomerProjection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | /**
19 | *
20 | * @author Oliver Gierke
21 | */
22 | public interface CustomerProjection {
23 |
24 | String getFirstname();
25 | }
26 |
--------------------------------------------------------------------------------
/jpa-projections/src/main/java/example/CustomerRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import java.util.Collection;
19 |
20 | import org.springframework.beans.factory.annotation.Value;
21 | import org.springframework.data.jpa.repository.Query;
22 | import org.springframework.data.repository.CrudRepository;
23 |
24 | /**
25 | * @author Oliver Gierke
26 | */
27 | public interface CustomerRepository extends CrudRepository {
28 |
29 | /**
30 | * Uses a projection interface to indicate the fields to be returned. As the projection doesn't use any dynamic
31 | * fields, the query execution will be restricted to only the fields needed by the projection.
32 | *
33 | * @return
34 | */
35 | Collection findAllProjectedBy();
36 |
37 | /**
38 | * When a projection is used that contains dynamic properties (i.e. SpEL expressions in an {@link Value} annotation),
39 | * the normal target entity will be loaded but dynamically projected so that the target can be referred to in the
40 | * expression.
41 | *
42 | * @return
43 | */
44 | Collection findAllSummarizedBy();
45 |
46 | /**
47 | * Projection interfaces can be used with manually declared queries, too. Make sure you alias the projects matching
48 | * the projection fields.
49 | *
50 | * @return
51 | */
52 | @Query("select c.firstname as firstname, c.lastname as lastname from Customer c")
53 | Collection findsByProjectedColumns();
54 |
55 | /**
56 | * Uses a concrete DTO type to indicate the fields to be returned. This gets translated into a constructor expression
57 | * in the query.
58 | *
59 | * @return
60 | */
61 | Collection findAllDtoedBy();
62 |
63 | /**
64 | * Passes in the projection type dynamically (either interface or DTO).
65 | *
66 | * @param firstname
67 | * @param projection
68 | * @return
69 | */
70 | Collection findByFirstname(String firstname, Class projection);
71 |
72 | /**
73 | * Projection for a single entity.
74 | *
75 | * @param id
76 | * @return
77 | */
78 | CustomerProjection findProjectedById(Long id);
79 |
80 | /**
81 | * Dynamic projection for a single entity.
82 | *
83 | * @param id
84 | * @param projection
85 | * @return
86 | */
87 | T findProjectedById(Long id, Class projection);
88 | }
89 |
--------------------------------------------------------------------------------
/jpa-projections/src/main/java/example/CustomerSummary.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.beans.factory.annotation.Value;
19 |
20 | /**
21 | * @author Oliver Gierke
22 | */
23 | public interface CustomerSummary {
24 |
25 | @Value("#{target.firstname + ' ' + target.lastname}")
26 | String getFullName();
27 | }
28 |
--------------------------------------------------------------------------------
/jpa-projections/src/main/java/example/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample showing Projection on Query methods related features of Spring Data JPA.
3 | *
4 | * @author Mark Paluch
5 | */
6 | package example;
7 |
--------------------------------------------------------------------------------
/jpa-projections/src/test/java/example/CustomerRepositoryIntegrationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import java.util.Collection;
22 | import java.util.Map;
23 |
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.boot.autoconfigure.SpringBootApplication;
29 | import org.springframework.boot.test.context.SpringBootTest;
30 | import org.springframework.data.projection.TargetAware;
31 | import org.springframework.test.context.junit4.SpringRunner;
32 | import org.springframework.transaction.annotation.Transactional;
33 |
34 | /**
35 | * Integration tests for {@link CustomerRepository} to show projection capabilities.
36 | *
37 | * @author Oliver Gierke
38 | * @author Mark Paluch
39 | */
40 | @RunWith(SpringRunner.class)
41 | @Transactional
42 | @SpringBootTest
43 | @SpringBootApplication
44 | public class CustomerRepositoryIntegrationTest {
45 |
46 | @Autowired CustomerRepository customers;
47 |
48 | Customer dave, carter;
49 |
50 | @Before
51 | public void setUp() {
52 |
53 | this.dave = customers.save(new Customer("Dave", "Matthews"));
54 | this.carter = customers.save(new Customer("Carter", "Beauford"));
55 | }
56 |
57 | @Test
58 | public void projectsEntityIntoInterface() {
59 |
60 | Collection result = customers.findAllProjectedBy();
61 |
62 | assertThat(result, hasSize(2));
63 | assertThat(result.iterator().next().getFirstname(), is("Dave"));
64 | }
65 |
66 | @Test
67 | public void projectsEntityIntoOpenProjectionInterface() {
68 |
69 | Collection result = customers.findAllSummarizedBy();
70 |
71 | assertThat(result, hasSize(2));
72 | assertThat(result.iterator().next().getFullName(), is("Dave Matthews"));
73 | }
74 |
75 | @Test
76 | public void projectsMapIntoInterface() {
77 |
78 | Collection result = customers.findsByProjectedColumns();
79 |
80 | assertThat(result, hasSize(2));
81 | assertThat(result.iterator().next().getFirstname(), is("Dave"));
82 | }
83 |
84 | @Test
85 | public void projectsToDto() {
86 |
87 | Collection result = customers.findAllDtoedBy();
88 |
89 | assertThat(result, hasSize(2));
90 | assertThat(result.iterator().next().getFirstname(), is("Dave"));
91 | }
92 |
93 | @Test
94 | public void projectsDynamically() {
95 |
96 | Collection result = customers.findByFirstname("Dave", CustomerProjection.class);
97 |
98 | assertThat(result, hasSize(1));
99 | assertThat(result.iterator().next().getFirstname(), is("Dave"));
100 | }
101 |
102 | @Test
103 | public void projectsIndividualDynamically() {
104 |
105 | CustomerSummary result = customers.findProjectedById(dave.getId(), CustomerSummary.class);
106 |
107 | assertThat(result.getFullName(), is("Dave Matthews"));
108 |
109 | // Proxy backed by original instance as the projection uses dynamic elements
110 | assertThat(((TargetAware) result).getTarget(), is(instanceOf(Customer.class)));
111 | }
112 |
113 | @Test
114 | public void projectIndividualInstance() {
115 |
116 | CustomerProjection projectedDave = customers.findProjectedById(dave.getId());
117 |
118 | assertThat(projectedDave.getFirstname(), is("Dave"));
119 | assertThat(((TargetAware) projectedDave).getTarget(), is(instanceOf(Map.class)));
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/jpa-query-by-example/README.md:
--------------------------------------------------------------------------------
1 | # Spring Data JPA - Query-by-Example (QBE) example
2 |
3 | This project contains samples of Query-by-Example of Spring Data JPA.
4 |
5 | ## Support for Query-by-Example
6 |
7 | Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation and does not require to write queries containing field names. In fact, Query by Example does not require to write queries using JPA-QL at all.
8 |
9 | An `Example` takes a data object (usually the entity object or a subtype of it) and a specification how to match properties. You can use Query by Example with JPA Repositories.
10 |
11 | ```java
12 | public interface PersonRepository extends CrudRepository, QueryByExampleExecutor {
13 | }
14 | ```
15 |
16 | ```java
17 | Example example = Example.of(new Person("Jon", "Snow"));
18 | repo.findAll(example);
19 |
20 |
21 | ExampleMatcher matcher = ExampleMatcher.matching().
22 | .withMatcher("firstname", endsWith())
23 | .withMatcher("lastname", startsWith().ignoreCase());
24 |
25 | Example example = Example.of(new Person("Jon", "Snow"), matcher);
26 | repo.count(example);
27 | ```
28 |
29 | This example contains a test class to illustrate Query-by-Example with a Repository in `UserRepositoryIntegrationTests`.
30 |
--------------------------------------------------------------------------------
/jpa-query-by-example/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | com.springone.2016
7 | whats-new-in-spring-data
8 | 1.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-data-jpa-query-by-example
12 | What's new in Spring Data? - JPA Query-by-Example (QBE)
13 |
14 |
15 | Hopper-SR2
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-jpa
23 |
24 |
25 |
26 | org.hsqldb
27 | hsqldb
28 | runtime
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/main/java/example/SpecialUser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import lombok.Data;
19 | import lombok.NoArgsConstructor;
20 |
21 | import javax.persistence.Entity;
22 |
23 | /**
24 | * Sample class that extends {@link User}.
25 | *
26 | * @author Mark Paluch
27 | * @author Oliver Gierke
28 | */
29 | @Entity
30 | @Data
31 | @NoArgsConstructor
32 | public class SpecialUser extends User {
33 |
34 | public SpecialUser(String firstname, String lastname, Integer age) {
35 | super(firstname, lastname, age);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/main/java/example/User.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import lombok.Data;
19 | import lombok.NoArgsConstructor;
20 | import lombok.RequiredArgsConstructor;
21 |
22 | import javax.persistence.Entity;
23 | import javax.persistence.GeneratedValue;
24 | import javax.persistence.Id;
25 |
26 | /**
27 | * Sample user class.
28 | *
29 | * @author Mark Paluch
30 | * @author Oliver Gierke
31 | */
32 | @Entity
33 | @Data
34 | @NoArgsConstructor(force = true)
35 | @RequiredArgsConstructor
36 | public class User {
37 |
38 | private @Id @GeneratedValue Long id;
39 | private final String firstname, lastname;
40 | private final Integer age;
41 | }
42 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/main/java/example/UserRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.data.repository.CrudRepository;
19 | import org.springframework.data.repository.query.QueryByExampleExecutor;
20 |
21 | /**
22 | * Simple repository interface for {@link User} instances. The interface implements {@link QueryByExampleExecutor} and
23 | * allows execution of methods accepting {@link org.springframework.data.domain.Example}.
24 | *
25 | * @author Mark Paluch
26 | */
27 | public interface UserRepository extends CrudRepository, QueryByExampleExecutor {}
28 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/main/java/example/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample showing Query-by-Example related features of Spring Data JPA.
3 | *
4 | * @author Mark Paluch
5 | */
6 | package example.springdata.jpa.querybyexample;
7 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/test/java/example/ApplicationConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.boot.autoconfigure.SpringBootApplication;
19 |
20 | /**
21 | * @author Mark Paluch
22 | * @author Oliver Gierke
23 | */
24 | @SpringBootApplication
25 | public class ApplicationConfiguration {}
26 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/test/java/example/UserRepositoryInheritanceIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.CoreMatchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 | import org.springframework.beans.factory.annotation.Autowired;
25 | import org.springframework.boot.test.context.SpringBootTest;
26 | import org.springframework.data.domain.Example;
27 | import org.springframework.test.context.junit4.SpringRunner;
28 | import org.springframework.transaction.annotation.Transactional;
29 |
30 | /**
31 | * Integration test showing the usage of JPA Query-by-Example support through Spring Data repositories and entities
32 | * using inheritance.
33 | *
34 | * @author Mark Paluch
35 | * @author Oliver Gierke
36 | */
37 | @RunWith(SpringRunner.class)
38 | @Transactional
39 | @SpringBootTest
40 | public class UserRepositoryInheritanceIntegrationTests {
41 |
42 | @Autowired UserRepository repository;
43 |
44 | User skyler, walter, flynn;
45 |
46 | @Before
47 | public void setUp() {
48 |
49 | repository.deleteAll();
50 |
51 | this.skyler = repository.save(new User("Skyler", "White", 45));
52 | this.walter = repository.save(new SpecialUser("Walter", "White", 50));
53 | this.flynn = repository.save(new SpecialUser("Walter Jr. (Flynn)", "White", 17));
54 | }
55 |
56 | @Test
57 | public void countByExample() {
58 | assertThat(repository.count(Example.of(new User(null, "White", null))), is(3L));
59 | }
60 |
61 | @Test
62 | public void countSubtypesByExample() {
63 | assertThat(repository.count(Example.of(new SpecialUser(null, "White", null))), is(2L));
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/jpa-query-by-example/src/test/java/example/UserRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.CoreMatchers.*;
19 | import static org.junit.Assert.*;
20 | import static org.springframework.data.domain.ExampleMatcher.*;
21 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.*;
22 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith;
23 |
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.boot.test.context.SpringBootTest;
29 | import org.springframework.data.domain.Example;
30 | import org.springframework.data.domain.ExampleMatcher.StringMatcher;
31 | import org.springframework.test.context.junit4.SpringRunner;
32 | import org.springframework.transaction.annotation.Transactional;
33 |
34 | /**
35 | * Integration test showing the usage of JPA Query-by-Example support through Spring Data repositories.
36 | *
37 | * @author Mark Paluch
38 | * @author Oliver Gierke
39 | */
40 | @SuppressWarnings("unused")
41 | @RunWith(SpringRunner.class)
42 | @Transactional
43 | @SpringBootTest
44 | public class UserRepositoryIntegrationTests {
45 |
46 | @Autowired UserRepository repository;
47 |
48 | User skyler, walter, flynn, marie, hank;
49 |
50 | @Before
51 | public void setUp() {
52 |
53 | repository.deleteAll();
54 |
55 | this.skyler = repository.save(new User("Skyler", "White", 45));
56 | this.walter = repository.save(new User("Walter", "White", 50));
57 | this.flynn = repository.save(new User("Walter Jr. (Flynn)", "White", 17));
58 | this.marie = repository.save(new User("Marie", "Schrader", 38));
59 | this.hank = repository.save(new User("Hank", "Schrader", 43));
60 | }
61 |
62 | @Test
63 | public void countBySimpleExample() {
64 |
65 | Example example = Example.of(new User(null, "White", null));
66 |
67 | assertThat(repository.count(example), is(3L));
68 | }
69 |
70 | @Test
71 | public void ignorePropertiesAndMatchByAge() {
72 |
73 | Example example = Example.of(flynn, matching().//
74 | withIgnorePaths("firstname", "lastname"));
75 |
76 | assertThat(repository.findOne(example), is(flynn));
77 | }
78 |
79 | @Test
80 | public void substringMatching() {
81 |
82 | Example example = Example.of(new User("er", null, null), matching().//
83 | withStringMatcher(StringMatcher.ENDING));
84 |
85 | assertThat(repository.findAll(example), hasItems(skyler, walter));
86 | }
87 |
88 | @Test
89 | public void matchStartingStringsIgnoreCase() {
90 |
91 | Example example = Example.of(new User("Walter", "WHITE", null),
92 | matching().//
93 | withIgnorePaths("age").//
94 | withMatcher("firstname", startsWith()).//
95 | withMatcher("lastname", ignoreCase()));
96 |
97 | assertThat(repository.findAll(example), hasItems(flynn, walter));
98 | }
99 |
100 | @Test
101 | public void configuringMatchersUsingLambdas() {
102 |
103 | Example example = Example.of(new User("Walter", "WHITE", null),
104 | matching().//
105 | withIgnorePaths("age").//
106 | withMatcher("firstname", matcher -> matcher.startsWith()).//
107 | withMatcher("lastname", matcher -> matcher.ignoreCase()));
108 |
109 | assertThat(repository.findAll(example), hasItems(flynn, walter));
110 | }
111 |
112 | @Test
113 | public void valueTransformer() {
114 |
115 | Example example = Example.of(new User(null, "White", 99), matching(). //
116 | withMatcher("age", matcher -> matcher.transform(value -> Integer.valueOf(50))));
117 |
118 | assertThat(repository.findAll(example), hasItems(walter));
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/jpa-query-method-wrapped-parameters/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | com.springone.2016
7 | whats-new-in-spring-data
8 | 1.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-data-jpa-query-method-wrapped-parameters
12 | What's new in Spring Data? - JPA Wrapped query method parameters
13 |
14 |
15 | Hopper-SR2
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-jpa
23 |
24 |
25 |
26 | org.hsqldb
27 | hsqldb
28 | runtime
29 |
30 |
31 |
32 | com.google.guava
33 | guava
34 | 19.0
35 |
36 |
37 |
38 | org.scala-lang
39 | scala-library
40 | 2.11.7
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/jpa-query-method-wrapped-parameters/src/main/java/example/Person.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import javax.persistence.Entity;
19 | import javax.persistence.GeneratedValue;
20 | import javax.persistence.Id;
21 |
22 | import lombok.Data;
23 | import lombok.NoArgsConstructor;
24 | import lombok.RequiredArgsConstructor;
25 |
26 | /**
27 | * Sample user class.
28 | *
29 | * @author Mark Paluch
30 | */
31 | @Entity
32 | @Data
33 | @NoArgsConstructor(force = true)
34 | @RequiredArgsConstructor
35 | public class Person {
36 |
37 | private @Id @GeneratedValue Long id;
38 | private final String firstname, lastname;
39 | private final String gender;
40 | }
41 |
--------------------------------------------------------------------------------
/jpa-query-method-wrapped-parameters/src/main/java/example/PersonRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import java.util.List;
19 | import java.util.Optional;
20 |
21 | import org.springframework.data.repository.CrudRepository;
22 |
23 | import scala.Option;
24 |
25 | /**
26 | * Simple repository interface for {@link Person} instances.
27 | *
28 | * @author Mark Paluch
29 | */
30 | public interface PersonRepository extends CrudRepository {
31 |
32 | /**
33 | * @param gender a plain {@link String}
34 | * @return
35 | */
36 | List findByGender(String gender);
37 |
38 | /**
39 | * @param gender a Java 8 {@link Optional}
40 | * @return
41 | */
42 | List findByGender(Optional gender);
43 |
44 | /**
45 | * @param gender a Guava {@link com.google.common.base.Optional}
46 | * @return
47 | */
48 | List findByGender(com.google.common.base.Optional gender);
49 |
50 | /**
51 | * @param gender a Scala {@link Option}
52 | * @return
53 | */
54 | List findByGender(Option gender);
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/jpa-query-method-wrapped-parameters/src/main/java/example/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample showing Query-by-Example related features of Spring Data JPA.
3 | *
4 | * @author Mark Paluch
5 | */
6 | package example.springdata.jpa.querybyexample;
7 |
--------------------------------------------------------------------------------
/jpa-query-method-wrapped-parameters/src/test/java/example/PersonRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import java.util.Optional;
22 |
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.springframework.beans.factory.annotation.Autowired;
27 | import org.springframework.boot.autoconfigure.SpringBootApplication;
28 | import org.springframework.boot.test.context.SpringBootTest;
29 | import org.springframework.test.context.junit4.SpringRunner;
30 | import org.springframework.transaction.annotation.Transactional;
31 |
32 | import scala.Option;
33 |
34 | /**
35 | * Integration test showing the usage of JPA wrapped query method parameters support through Spring Data repositories.
36 | *
37 | * @author Mark Paluch
38 | */
39 | @SuppressWarnings("unused")
40 | @RunWith(SpringRunner.class)
41 | @Transactional
42 | @SpringBootTest
43 | @SpringBootApplication
44 | public class PersonRepositoryIntegrationTests {
45 |
46 | @Autowired PersonRepository repository;
47 |
48 | Person gomez, mortica, thing, itt;
49 |
50 | @Before
51 | public void setUp() {
52 |
53 | repository.deleteAll();
54 |
55 | this.gomez = repository.save(new Person("Gomez", "Addams", "male"));
56 | this.mortica = repository.save(new Person("Mortica", "Addams", "female"));
57 | this.thing = repository.save(new Person("Thing T.", "Thing", null));
58 | this.itt = repository.save(new Person("Cousin", "Itt", null));
59 | }
60 |
61 | @Test
62 | public void findByGender() {
63 |
64 | assertThat(repository.findByGender("male"), contains(gomez));
65 |
66 | assertThat(repository.findByGender((String) null), hasItems(thing, itt));
67 | assertThat(repository.findByGender((String) null), not(hasItems(gomez, mortica)));
68 | }
69 |
70 | @Test
71 | public void findByGenderWrappedIn8Optional() {
72 |
73 | assertThat(repository.findByGender(Optional.of("male")), contains(gomez));
74 |
75 | assertThat(repository.findByGender(Optional.empty()), hasItems(thing, itt));
76 | assertThat(repository.findByGender(Optional.empty()), not(hasItems(gomez, mortica)));
77 | }
78 |
79 | @Test
80 | public void findByGenderWrappedInGuavaOptional() {
81 |
82 | assertThat(repository.findByGender(com.google.common.base.Optional.of("male")), contains(gomez));
83 |
84 | assertThat(repository.findByGender(com.google.common.base.Optional.absent()), hasItems(thing, itt));
85 | assertThat(repository.findByGender(com.google.common.base.Optional.absent()), not(hasItems(gomez, mortica)));
86 | }
87 |
88 | @Test
89 | public void findByGenderWrappedInScalaOption() {
90 |
91 | assertThat(repository.findByGender(Option.apply("male")), contains(gomez));
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | com.springone.2016
7 | whats-new-in-spring-data
8 | 1.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-data-mongodb-composed-annotations
12 | What's new in Spring Data? - Composed Annotations
13 |
14 |
15 | Hopper-SR2
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-mongodb
23 |
24 |
25 |
26 | de.flapdoodle.embed
27 | de.flapdoodle.embed.mongo
28 | runtime
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/main/java/example/FindWalter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | import org.springframework.core.annotation.AliasFor;
24 | import org.springframework.data.mongodb.repository.Query;
25 |
26 | /**
27 | * @author Mark Paluch
28 | */
29 | @Retention(RetentionPolicy.RUNTIME)
30 | @Target({ ElementType.METHOD })
31 | @Query
32 | @interface FindWalter {
33 |
34 | @AliasFor(annotation = Query.class, attribute = "value")
35 | String query() default "{ 'firstname' : 'Walter' }";
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/main/java/example/ImprovedVenue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.data.annotation.Id;
19 | import org.springframework.data.geo.Point;
20 | import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
21 | import org.springframework.data.mongodb.core.mapping.Document;
22 |
23 | import lombok.Data;
24 | import lombok.NoArgsConstructor;
25 |
26 | /**
27 | * @author Mark Paluch
28 | */
29 | @Data
30 | @NoArgsConstructor
31 | @Document
32 | public class ImprovedVenue {
33 |
34 | @Id String id;
35 | String address;
36 |
37 | @MyGeoIndexAnnotation("index_name") Point point;
38 |
39 | public ImprovedVenue(String address, Point point) {
40 | this.address = address;
41 | this.point = point;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/main/java/example/MyGeoIndexAnnotation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | import org.springframework.core.annotation.AliasFor;
24 | import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
25 | import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
26 |
27 | /**
28 | * @author Mark Paluch
29 | */
30 | @Retention(RetentionPolicy.RUNTIME)
31 | @Target({ ElementType.FIELD })
32 | @GeoSpatialIndexed
33 | @interface MyGeoIndexAnnotation {
34 |
35 | @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "name")
36 | String value();
37 |
38 | @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "bits")
39 | int bits() default 2;
40 |
41 | @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "max")
42 | int max() default 50;
43 |
44 | @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "min")
45 | int min() default -120;
46 |
47 | @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "type")
48 | GeoSpatialIndexType type() default GeoSpatialIndexType.GEO_2D;
49 |
50 | @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "useGeneratedName")
51 | boolean dont_change_me() default false;
52 |
53 | String comment() default "What light?";
54 | }
55 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/main/java/example/Person.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.data.annotation.Id;
19 | import org.springframework.data.mongodb.core.mapping.Document;
20 |
21 | import lombok.Data;
22 | import lombok.NoArgsConstructor;
23 |
24 | /**
25 | * @author Mark Paluch
26 | */
27 | @Document
28 | @Data
29 | @NoArgsConstructor
30 | public class Person {
31 |
32 | @Id String id;
33 | String firstname;
34 | String lastname;
35 |
36 | public Person(String firstname, String lastname){
37 | this.firstname = firstname;
38 | this.lastname = lastname;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/main/java/example/PersonRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import java.util.List;
19 |
20 | import org.springframework.data.mongodb.repository.Query;
21 | import org.springframework.data.repository.CrudRepository;
22 |
23 | /**
24 | * @author Mark Paluch
25 | */
26 | public interface PersonRepository extends CrudRepository {
27 |
28 | @Query("{ 'firstname' : 'Walter' }")
29 | List findWalterUsingQueryAnnotation();
30 |
31 | @FindWalter
32 | List findWalterUsingComposedAnnotations();
33 | }
34 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/main/java/example/Venue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.data.annotation.Id;
19 | import org.springframework.data.geo.Point;
20 | import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
21 | import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
22 | import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
23 | import org.springframework.data.mongodb.core.mapping.Document;
24 |
25 | import lombok.Data;
26 | import lombok.NoArgsConstructor;
27 |
28 | /**
29 | * @author Mark Paluch
30 | */
31 | @Data
32 | @NoArgsConstructor
33 | @Document
34 | public class Venue {
35 |
36 | @Id String id;
37 | String address;
38 |
39 | @GeoSpatialIndexed(bits = 2, max = 50, min = -120, type = GeoSpatialIndexType.GEO_2D, useGeneratedName = false,
40 | name = "myGeoIndex") Point point;
41 |
42 | public Venue(String address, Point point) {
43 | this.address = address;
44 | this.point = point;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/test/java/example/ApplicationConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.boot.autoconfigure.SpringBootApplication;
19 |
20 | /**
21 | * @author Mark Paluch
22 | */
23 | @SpringBootApplication
24 | public class ApplicationConfiguration {}
25 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/test/java/example/ComposedAnnotationIntegrationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 | import org.springframework.beans.factory.annotation.Autowired;
25 | import org.springframework.boot.test.context.SpringBootTest;
26 | import org.springframework.data.geo.GeoResult;
27 | import org.springframework.data.geo.GeoResults;
28 | import org.springframework.data.geo.Metrics;
29 | import org.springframework.data.geo.Point;
30 | import org.springframework.data.mongodb.core.MongoOperations;
31 | import org.springframework.data.mongodb.core.index.GeospatialIndex;
32 | import org.springframework.data.mongodb.core.query.NearQuery;
33 | import org.springframework.data.mongodb.core.query.Query;
34 | import org.springframework.test.context.junit4.SpringRunner;
35 |
36 | /**
37 | * Integration test showing the usage of MongoDB Composed Annotations support.
38 | *
39 | * @author Mark Paluch
40 | */
41 | @SuppressWarnings("unused")
42 | @RunWith(SpringRunner.class)
43 | @SpringBootTest
44 | public class ComposedAnnotationIntegrationTest {
45 |
46 | @Autowired MongoOperations operations;
47 |
48 | Venue theWhiteResidence, jessesHouse;
49 | ImprovedVenue carWash, pollosHermanos, saulsOffice;
50 |
51 | @Before
52 | public void setUp() {
53 |
54 | operations.remove(new Query(), Venue.class);
55 | operations.remove(new Query(), ImprovedVenue.class);
56 |
57 | this.theWhiteResidence = new Venue("308 Negra Arroyo Lane, Albuquerque, New Mexico, 87104",
58 | new Point(-106.5387498, 35.1261101));
59 |
60 | this.jessesHouse = new Venue("9809 Margo Street, Albuquerque, New Mexico 87104",
61 | new Point(-106.6677747, 35.087538));
62 |
63 | this.carWash = new ImprovedVenue("9516 Snow Heights Circle NE, Albuqerque, New Mexico 87112",
64 | new Point(-106.5369764, 35.1084638));
65 |
66 | this.pollosHermanos = new ImprovedVenue("12000 – 12100 Coors Rd SW, Albuquerque NM, 87045",
67 | new Point(-106.688545, 35.0146382));
68 |
69 | this.saulsOffice = new ImprovedVenue("9800 Montgomery Blvd NE, Albuquerque, New Mexico, 87111",
70 | new Point(-106.5346129, 35.1293502));
71 |
72 | operations.save(this.theWhiteResidence);
73 | operations.save(this.jessesHouse);
74 | operations.save(this.carWash);
75 | operations.save(this.pollosHermanos);
76 | operations.save(this.saulsOffice);
77 | }
78 |
79 | /**
80 | * Issue a {@code geoNear} query using a 2d legacy index specified by the built-in {@link GeospatialIndex} annotation.
81 | */
82 | @Test
83 | public void findsVenuesWithRegularAnnotations() {
84 |
85 | GeoResults geoResults = operations
86 | .geoNear(NearQuery.near(jessesHouse.getPoint()).maxDistance(10, Metrics.MILES), Venue.class);
87 |
88 | assertThat(geoResults.getContent(), hasSize(2));
89 |
90 | GeoResult geoResult = geoResults.getContent().get(1);
91 |
92 | assertThat(geoResult.getContent(), is(equalTo(theWhiteResidence)));
93 | assertThat(geoResult.getDistance().getValue(), is(closeTo(7.7, 0.1)));
94 | }
95 |
96 | /**
97 | * Issue a {@code geoNear} query using a 2d legacy index specified by a custom, composed {@link MyGeoIndexAnnotation}
98 | * annotation.
99 | */
100 | @Test
101 | public void findsVenuesWithComposedAnnotations() {
102 |
103 | GeoResults geoResults = operations
104 | .geoNear(NearQuery.near(theWhiteResidence.getPoint()).maxDistance(2, Metrics.MILES), ImprovedVenue.class);
105 |
106 | assertThat(geoResults.getContent(), hasSize(2));
107 |
108 | GeoResult geoResult = geoResults.getContent().get(1);
109 |
110 | assertThat(geoResult.getContent(), is(equalTo(carWash)));
111 | assertThat(geoResult.getDistance().getValue(), is(closeTo(1.2, 0.1)));
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/mongodb-composed-annotations/src/test/java/example/RepositoryIntegrationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import java.util.List;
22 |
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.springframework.beans.factory.annotation.Autowired;
27 | import org.springframework.boot.test.context.SpringBootTest;
28 | import org.springframework.data.mongodb.repository.Query;
29 | import org.springframework.test.context.junit4.SpringRunner;
30 |
31 | /**
32 | * Integration test showing the usage of MongoDB Composed Annotations support through a MongoDB repository.
33 | *
34 | * @author Mark Paluch
35 | */
36 | @SuppressWarnings("unused")
37 | @RunWith(SpringRunner.class)
38 | @SpringBootTest
39 | public class RepositoryIntegrationTest {
40 |
41 | @Autowired PersonRepository repository;
42 |
43 | Person skyler, walter, flynn;
44 |
45 | @Before
46 | public void setUp() {
47 |
48 | repository.deleteAll();
49 |
50 | this.skyler = repository.save(new Person("Skyler", "White"));
51 | this.walter = repository.save(new Person("Walter", "White"));
52 | this.flynn = repository.save(new Person("Walter Jr. (Flynn)", "White"));
53 | }
54 |
55 | /**
56 | * Execute a query method annotated with the built-in {@link Query} annotation.
57 | */
58 | @Test
59 | public void findWalterUsingQueryAnnotation() {
60 |
61 | List result = repository.findWalterUsingQueryAnnotation();
62 |
63 | assertThat(result, contains(walter));
64 | }
65 |
66 | /**
67 | * Execute a query method annotated with a custom {@link FindWalter} annotation.
68 | */
69 | @Test
70 | public void findWalterUsingComposedAnnotations() {
71 |
72 | List result = repository.findWalterUsingComposedAnnotations();
73 |
74 | assertThat(result, contains(walter));
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/README.md:
--------------------------------------------------------------------------------
1 | # Spring Data MongoDB - Query-by-Example (QBE) example
2 |
3 | This project contains samples of Query-by-Example of Spring Data MongoDB.
4 |
5 | ## Support for Query-by-Example
6 |
7 | Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation and does not require to write queries containing field names. In fact, Query by Example does not require to write queries using JPA-QL at all.
8 |
9 | An `Example` takes a data object (usually the entity object or a subtype of it) and a specification how to match properties. You can use Query by Example with `MongoOperations` and Repositories.
10 |
11 | ```java
12 | public interface PersonRepository extends CrudRepository, QueryByExampleExecutor {
13 | }
14 | ```
15 |
16 | ```java
17 | Example example = Example.of(new Person("Jon", "Snow"));
18 | repo.findAll(example);
19 |
20 |
21 | ExampleMatcher matcher = ExampleMatcher.matching().
22 | .withMatcher("firstname", endsWith())
23 | .withMatcher("lastname", startsWith().ignoreCase());
24 |
25 | Example example = Example.of(new Person("Jon", "Snow"), matcher);
26 | repo.count(example);
27 | ```
28 |
29 | This example contains two test classes to illustrate Query-by-Example with `MongoOperations` in `MongoOperationsIntegrationTests` and the usage with a Repository in `UserRepositoryIntegrationTests`.
30 |
31 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | com.springone.2016
7 | whats-new-in-spring-data
8 | 1.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-data-mongodb-query-by-example
12 | What's new in Spring Data? - MongoDB Query-by-Example (QBE)
13 |
14 |
15 | Hopper-SR2
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-mongodb
23 |
24 |
25 |
26 | de.flapdoodle.embed
27 | de.flapdoodle.embed.mongo
28 | runtime
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/Contact.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import lombok.EqualsAndHashCode;
19 | import lombok.Getter;
20 | import lombok.ToString;
21 |
22 | import org.bson.types.ObjectId;
23 | import org.springframework.data.mongodb.core.mapping.Document;
24 |
25 | /**
26 | * @author Oliver Gierke
27 | */
28 | @Document(collection = "contacts")
29 | @EqualsAndHashCode
30 | @ToString
31 | public abstract class Contact {
32 |
33 | private @Getter ObjectId id;
34 | }
35 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/ContactRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import example.Contact;
19 |
20 | import org.bson.types.ObjectId;
21 | import org.springframework.data.repository.CrudRepository;
22 | import org.springframework.data.repository.query.QueryByExampleExecutor;
23 |
24 | /**
25 | * Repository interface for {@link Contact} and sub-types.
26 | *
27 | * @author Oliver Gierke
28 | */
29 | public interface ContactRepository extends CrudRepository, QueryByExampleExecutor {}
30 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/Person.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import lombok.Getter;
19 | import lombok.RequiredArgsConstructor;
20 |
21 | import org.springframework.data.mongodb.core.mapping.Document;
22 |
23 | /**
24 | * Sample user class.
25 | *
26 | * @author Mark Paluch
27 | * @author Oliver Gierke
28 | */
29 | @Getter
30 | @RequiredArgsConstructor
31 | @Document(collection = "contacts")
32 | public class Person extends Contact {
33 |
34 | private final String firstname, lastname;
35 | private final Integer age;
36 | }
37 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/Relative.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import lombok.Getter;
19 | import lombok.RequiredArgsConstructor;
20 |
21 | import org.springframework.data.mongodb.core.mapping.Document;
22 |
23 | /**
24 | * Sample contact class.
25 | *
26 | * @author Mark Paluch
27 | * @author Oliver Gierke
28 | */
29 | @Getter
30 | @RequiredArgsConstructor
31 | @Document(collection = "contacts")
32 | public class Relative extends Contact {
33 |
34 | private final String firstname, lastname;
35 | private final Integer age;
36 | }
37 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/RelativeRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.data.repository.CrudRepository;
19 | import org.springframework.data.repository.query.QueryByExampleExecutor;
20 |
21 | /**
22 | * Simple repository interface for {@link Relative} instances. The interface implements {@link QueryByExampleExecutor}
23 | * and allows execution of methods accepting {@link org.springframework.data.domain.Example}.
24 | *
25 | * @author Mark Paluch
26 | */
27 | public interface RelativeRepository extends CrudRepository, QueryByExampleExecutor {}
28 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/UserRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.data.repository.CrudRepository;
19 | import org.springframework.data.repository.query.QueryByExampleExecutor;
20 |
21 | /**
22 | * Simple repository interface for {@link Person} instances. The interface implements {@link QueryByExampleExecutor} and
23 | * allows execution of methods accepting {@link org.springframework.data.domain.Example}.
24 | *
25 | * @author Mark Paluch
26 | */
27 | public interface UserRepository extends CrudRepository, QueryByExampleExecutor {}
28 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/main/java/example/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * Sample showing Query-by-Example related features of Spring Data MongoDB.
19 | *
20 | * @author Mark Paluch
21 | */
22 | package example;
23 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/test/java/example/ApplicationConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.boot.autoconfigure.SpringBootApplication;
19 |
20 | /**
21 | * @author Mark Paluch
22 | */
23 | @SpringBootApplication
24 | public class ApplicationConfiguration {}
25 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/test/java/example/ContactRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.CoreMatchers.is;
19 | import static org.hamcrest.CoreMatchers.not;
20 | import static org.hamcrest.Matchers.*;
21 | import static org.junit.Assert.*;
22 | import static org.springframework.data.domain.ExampleMatcher.*;
23 |
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.boot.test.context.SpringBootTest;
29 | import org.springframework.data.domain.Example;
30 | import org.springframework.data.domain.ExampleMatcher.*;
31 | import org.springframework.data.mongodb.core.MongoOperations;
32 | import org.springframework.test.context.junit4.SpringRunner;
33 |
34 | /**
35 | * Integration test showing the usage of MongoDB Query-by-Example support through Spring Data repositories for a case
36 | * where two domain types are stored in one collection.
37 | *
38 | * @author Mark Paluch
39 | * @author Oliver Gierke
40 | * @soundtrack Paul van Dyk - VONYC Sessions Episode 496 with guest Armin van Buuren
41 | */
42 | @RunWith(SpringRunner.class)
43 | @SpringBootTest
44 | public class ContactRepositoryIntegrationTests {
45 |
46 | @Autowired UserRepository userRepository;
47 | @Autowired ContactRepository contactRepository;
48 | @Autowired MongoOperations mongoOperations;
49 |
50 | Person skyler, walter, flynn;
51 | Relative marie, hank;
52 |
53 | @Before
54 | public void setUp() {
55 |
56 | contactRepository.deleteAll();
57 |
58 | this.skyler = contactRepository.save(new Person("Skyler", "White", 45));
59 | this.walter = contactRepository.save(new Person("Walter", "White", 50));
60 | this.flynn = contactRepository.save(new Person("Walter Jr. (Flynn)", "White", 17));
61 | this.marie = contactRepository.save(new Relative("Marie", "Schrader", 38));
62 | this.hank = contactRepository.save(new Relative("Hank", "Schrader", 43));
63 | }
64 |
65 | @Test
66 | public void countByConcreteSubtypeExample() {
67 |
68 | Example example = Example.of(new Person(null, null, null));
69 |
70 | assertThat(userRepository.count(example), is(3L));
71 | }
72 |
73 | @Test
74 | public void findAllPersonsBySimpleExample() {
75 |
76 | Example example = Example.of(new Person(".*", null, null), //
77 | matching().withStringMatcher(StringMatcher.REGEX));
78 |
79 | assertThat(userRepository.findAll(example), containsInAnyOrder(skyler, walter, flynn));
80 | assertThat(userRepository.findAll(example), not(containsInAnyOrder(hank, marie)));
81 | }
82 |
83 | @Test
84 | public void findAllRelativesBySimpleExample() {
85 |
86 | Example example = Example.of(new Relative(".*", null, null), //
87 | matching().withStringMatcher(StringMatcher.REGEX));
88 |
89 | assertThat(contactRepository.findAll(example), containsInAnyOrder(hank, marie));
90 | assertThat(contactRepository.findAll(example), not(containsInAnyOrder(skyler, walter, flynn)));
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/test/java/example/MongoOperationsIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package example;
18 |
19 | import static org.hamcrest.CoreMatchers.*;
20 | import static org.junit.Assert.*;
21 | import static org.springframework.data.domain.ExampleMatcher.*;
22 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.*;
23 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith;
24 | import static org.springframework.data.mongodb.core.query.Criteria.*;
25 | import static org.springframework.data.mongodb.core.query.Query.*;
26 |
27 | import org.junit.Before;
28 | import org.junit.Test;
29 | import org.junit.runner.RunWith;
30 | import org.springframework.beans.factory.annotation.Autowired;
31 | import org.springframework.boot.test.context.SpringBootTest;
32 | import org.springframework.data.domain.Example;
33 | import org.springframework.data.domain.ExampleMatcher.*;
34 | import org.springframework.data.mongodb.core.MongoOperations;
35 | import org.springframework.data.mongodb.core.query.Query;
36 | import org.springframework.test.context.junit4.SpringRunner;
37 |
38 | /**
39 | * Integration test showing the usage of MongoDB Query-by-Example support through Spring Data repositories.
40 | *
41 | * @author Mark Paluch
42 | * @author Oliver Gierke
43 | */
44 | @RunWith(SpringRunner.class)
45 | @SpringBootTest
46 | public class MongoOperationsIntegrationTests {
47 |
48 | @Autowired MongoOperations operations;
49 |
50 | Person skyler, walter, flynn, marie, hank;
51 |
52 | @Before
53 | public void setUp() {
54 |
55 | operations.remove(new Query(), Person.class);
56 |
57 | this.skyler = new Person("Skyler", "White", 45);
58 | this.walter = new Person("Walter", "White", 50);
59 | this.flynn = new Person("Walter Jr. (Flynn)", "White", 17);
60 | this.marie = new Person("Marie", "Schrader", 38);
61 | this.hank = new Person("Hank", "Schrader", 43);
62 |
63 | operations.save(this.skyler);
64 | operations.save(this.walter);
65 | operations.save(this.flynn);
66 | operations.save(this.marie);
67 | operations.save(this.hank);
68 | }
69 |
70 | @Test
71 | public void ignoreNullProperties() {
72 |
73 | Query query = query(byExample(new Person(null, null, 17)));
74 |
75 | assertThat(operations.find(query, Person.class), hasItems(flynn));
76 | }
77 |
78 | @Test
79 | public void substringMatching() {
80 |
81 | Example example = Example.of(new Person("er", null, null), matching().//
82 | withStringMatcher(StringMatcher.ENDING));
83 |
84 | assertThat(operations.find(query(byExample(example)), Person.class), hasItems(skyler, walter));
85 | }
86 |
87 | @Test
88 | public void regexMatching() {
89 |
90 | Example example = Example.of(new Person("(Skyl|Walt)er", null, null), matching().//
91 | withMatcher("firstname", matcher -> matcher.regex()));
92 |
93 | assertThat(operations.find(query(byExample(example)), Person.class), hasItems(skyler, walter));
94 | }
95 |
96 | @Test
97 | public void matchStartingStringsIgnoreCase() {
98 |
99 | Example example = Example.of(new Person("Walter", "WHITE", null),
100 | matching(). //
101 | withIgnorePaths("age").//
102 | withMatcher("firstname", startsWith()).//
103 | withMatcher("lastname", ignoreCase()));
104 |
105 | assertThat(operations.find(query(byExample(example)), Person.class), hasItems(flynn, walter));
106 | }
107 |
108 | @Test
109 | public void configuringMatchersUsingLambdas() {
110 |
111 | Example example = Example.of(new Person("Walter", "WHITE", null),
112 | matching().//
113 | withIgnorePaths("age"). //
114 | withMatcher("firstname", matcher -> matcher.startsWith()). //
115 | withMatcher("lastname", matcher -> matcher.ignoreCase()));
116 |
117 | assertThat(operations.find(query(byExample(example)), Person.class), hasItems(flynn, walter));
118 | }
119 |
120 | @Test
121 | public void valueTransformer() {
122 |
123 | Example example = Example.of(new Person(null, "White", 99), matching(). //
124 | withMatcher("age", matcher -> matcher.transform(value -> Integer.valueOf(50))));
125 |
126 | assertThat(operations.find(query(byExample(example)), Person.class), hasItems(walter));
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/mongodb-query-by-example/src/test/java/example/UserRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.CoreMatchers.*;
19 | import static org.junit.Assert.*;
20 | import static org.springframework.data.domain.ExampleMatcher.*;
21 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.*;
22 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith;
23 |
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.boot.test.context.SpringBootTest;
29 | import org.springframework.data.domain.Example;
30 | import org.springframework.data.domain.ExampleMatcher.StringMatcher;
31 | import org.springframework.test.context.junit4.SpringRunner;
32 |
33 | /**
34 | * Integration test showing the usage of MongoDB Query-by-Example support through Spring Data repositories.
35 | *
36 | * @author Mark Paluch
37 | * @author Oliver Gierke
38 | */
39 | @SuppressWarnings("unused")
40 | @RunWith(SpringRunner.class)
41 | @SpringBootTest
42 | public class UserRepositoryIntegrationTests {
43 |
44 | @Autowired UserRepository repository;
45 |
46 | Person skyler, walter, flynn, marie, hank;
47 |
48 | @Before
49 | public void setUp() {
50 |
51 | repository.deleteAll();
52 |
53 | this.skyler = repository.save(new Person("Skyler", "White", 45));
54 | this.walter = repository.save(new Person("Walter", "White", 50));
55 | this.flynn = repository.save(new Person("Walter Jr. (Flynn)", "White", 17));
56 | this.marie = repository.save(new Person("Marie", "Schrader", 38));
57 | this.hank = repository.save(new Person("Hank", "Schrader", 43));
58 | }
59 |
60 | @Test
61 | public void countBySimpleExample() {
62 |
63 | Example example = Example.of(new Person(null, "White", null));
64 |
65 | assertThat(repository.count(example), is(3L));
66 | }
67 |
68 | @Test
69 | public void ignorePropertiesAndMatchByAge() {
70 |
71 | Example example = Example.of(flynn, matching(). //
72 | withIgnorePaths("firstname", "lastname"));
73 |
74 | assertThat(repository.findOne(example), is(flynn));
75 | }
76 |
77 | @Test
78 | public void substringMatching() {
79 |
80 | Example example = Example.of(new Person("er", null, null), matching().//
81 | withStringMatcher(StringMatcher.ENDING));
82 |
83 | assertThat(repository.findAll(example), hasItems(skyler, walter));
84 | }
85 |
86 | @Test
87 | public void regexMatching() {
88 |
89 | Example example = Example.of(new Person("(Skyl|Walt)er", null, null), matching().//
90 | withMatcher("firstname", matcher -> matcher.regex()));
91 |
92 | assertThat(repository.findAll(example), hasItems(skyler, walter));
93 | }
94 |
95 | @Test
96 | public void matchStartingStringsIgnoreCase() {
97 |
98 | Example example = Example.of(new Person("Walter", "WHITE", null),
99 | matching().//
100 | withIgnorePaths("age").//
101 | withMatcher("firstname", startsWith()).//
102 | withMatcher("lastname", ignoreCase()));
103 |
104 | assertThat(repository.findAll(example), hasItems(flynn, walter));
105 | }
106 |
107 | @Test
108 | public void configuringMatchersUsingLambdas() {
109 |
110 | Example example = Example.of(new Person("Walter", "WHITE", null),
111 | matching().//
112 | withIgnorePaths("age").//
113 | withMatcher("firstname", matcher -> matcher.startsWith()).//
114 | withMatcher("lastname", matcher -> matcher.ignoreCase()));
115 |
116 | assertThat(repository.findAll(example), hasItems(flynn, walter));
117 | }
118 |
119 | @Test
120 | public void valueTransformer() {
121 |
122 | Example example = Example.of(new Person(null, "White", 99), matching(). //
123 | withMatcher("age", matcher -> matcher.transform(value -> Integer.valueOf(50))));
124 |
125 | assertThat(repository.findAll(example), hasItems(walter));
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/mongodb-reactive/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | com.springone.2016
7 | whats-new-in-spring-data
8 | 1.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-data-mongodb-reactive
12 | What's new in Spring Data? - MongoDB Reactive Data Access
13 |
14 |
15 |
16 |
17 | org.springframework.data
18 | spring-data-commons
19 | 2.0.0.DATACMNS-836-SNAPSHOT
20 |
21 |
22 |
23 | org.springframework.data
24 | spring-data-mongodb
25 | 2.0.0.DATAMONGO-1444-SNAPSHOT
26 |
27 |
28 |
29 | org.mongodb
30 | mongodb-driver-reactivestreams
31 | 1.2.0
32 |
33 |
34 |
35 | org.mongodb
36 | mongo-java-driver
37 | 3.2.2
38 |
39 |
40 |
41 | io.projectreactor
42 | reactor-core
43 | 3.0.0.RC1
44 |
45 |
46 |
47 | io.reactivex
48 | rxjava
49 | 1.1.5
50 |
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-starter-data-mongodb
55 |
56 |
57 |
58 | de.flapdoodle.embed
59 | de.flapdoodle.embed.mongo
60 | runtime
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/main/java/example/Person.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.bson.types.ObjectId;
19 | import org.springframework.data.annotation.Id;
20 | import org.springframework.data.mongodb.core.mapping.Document;
21 |
22 | import lombok.Data;
23 | import lombok.NoArgsConstructor;
24 |
25 | /**
26 | * Sample user class.
27 | *
28 | * @author Mark Paluch
29 | */
30 | @Data
31 | @Document(collection = "contacts")
32 | @NoArgsConstructor
33 | public class Person {
34 |
35 | @Id private ObjectId objectId;
36 | private String firstname;
37 | private String lastname;
38 | private Integer age;
39 |
40 | public Person(String firstname, String lastname, Integer age) {
41 | this.firstname = firstname;
42 | this.lastname = lastname;
43 | this.age = age;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/main/java/example/ReactivePersonRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.bson.types.ObjectId;
19 | import org.springframework.data.repository.NoRepositoryBean;
20 | import org.springframework.data.repository.Repository;
21 |
22 | import reactor.core.publisher.Mono;
23 | import rx.Observable;
24 | import rx.Single;
25 |
26 | /**
27 | * Reactive Repository using Project Reactor and RxJava types.
28 | *
29 | * @author Mark Paluch
30 | */
31 | @NoRepositoryBean
32 | public interface ReactivePersonRepository extends Repository {
33 |
34 | /**
35 | * Find one by {@code firstname},
36 | *
37 | * @param firstname
38 | * @param lastname
39 | * @return an {@link Single}
40 | */
41 | Mono findByFirstnameAndLastname(String firstname, String lastname);
42 |
43 | /**
44 | * Find many by {@code lastname}.
45 | *
46 | * @param lastname
47 | * @return an {@link Observable}
48 | */
49 | Observable findByLastname(String lastname);
50 |
51 | /**
52 | * Find one by {@code firstname} wrapped inside a {@link Mono} and {@code lastname}.
53 | *
54 | * @param firstname
55 | * @param lastname
56 | * @return a {@link Mono}
57 | */
58 | Mono findByFirstnameAndLastname(Mono firstname, String lastname);
59 |
60 | /**
61 | * Find one by {@code id} wrapped inside a {@link Mono}.
62 | *
63 | * @param objectId
64 | * @return
65 | */
66 | Mono findOne(Mono objectId);
67 |
68 | /**
69 | * Find one by {@code id} wrapped inside a {@link Single}.
70 | *
71 | * @param objectId
72 | * @return
73 | */
74 | Single findOne(Single objectId);
75 |
76 | Mono deleteAll();
77 |
78 | Mono save(Person person);
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/main/java/example/ReactorPersonRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.bson.types.ObjectId;
19 | import org.springframework.data.repository.NoRepositoryBean;
20 | import org.springframework.data.repository.reactive.ReactiveCrudRepository;
21 |
22 | import reactor.core.publisher.Flux;
23 | import reactor.core.publisher.Mono;
24 |
25 | /**
26 | * Reactive Repository using Project Reactor types like {@link Flux} and {@link Mono}.
27 | *
28 | * @author Mark Paluch
29 | */
30 | @NoRepositoryBean
31 | public interface ReactorPersonRepository extends ReactiveCrudRepository {
32 |
33 | /**
34 | * Find one by {@code firstname} and {@code lastname}.
35 | *
36 | * @param firstname
37 | * @param lastname
38 | * @return a {@link Mono}
39 | */
40 | Mono findByFirstnameAndLastname(String firstname, String lastname);
41 |
42 | /**
43 | * Find many by {@code lastname}.
44 | *
45 | * @param lastname
46 | * @return a {@link Flux}
47 | */
48 | Flux findByLastname(String lastname);
49 |
50 | /**
51 | * Find many by {@code firstname} wrapped inside a {@link Mono}.
52 | *
53 | * @param lastname
54 | * @return a {@link Flux}
55 | */
56 | Flux findByLastname(Mono lastname);
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/main/java/example/RxJavaPersonRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.bson.types.ObjectId;
19 | import org.springframework.data.repository.NoRepositoryBean;
20 | import org.springframework.data.repository.reactive.RxJavaCrudRepository;
21 |
22 | import rx.Observable;
23 | import rx.Single;
24 |
25 | /**
26 | * Reactive Repository using RxJava types like {@link Observable} and {@link Single}.
27 | *
28 | * @author Mark Paluch
29 | */
30 | @NoRepositoryBean
31 | public interface RxJavaPersonRepository extends RxJavaCrudRepository {
32 |
33 | /**
34 | * Find one by {@code firstname} and {@code lastname}.
35 | *
36 | * @param firstname
37 | * @param lastname
38 | * @return a {@link Single}
39 | */
40 | Single findByFirstnameAndLastname(String firstname, String lastname);
41 |
42 | /**
43 | * Find many by {@code lastname}.
44 | *
45 | * @param lastname
46 | * @return an {@link Observable}
47 | */
48 | Observable findByLastname(String lastname);
49 |
50 | /**
51 | * Find many by {@code firstname} wrapped inside a {@link Single}.
52 | *
53 | * @param lastname
54 | * @return an {@link Observable}
55 | */
56 | Observable findByLastname(Single lastname);
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/test/java/example/ApplicationConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.beans.BeansException;
19 | import org.springframework.beans.factory.BeanClassLoaderAware;
20 | import org.springframework.beans.factory.BeanFactory;
21 | import org.springframework.beans.factory.BeanFactoryAware;
22 | import org.springframework.beans.factory.annotation.Value;
23 | import org.springframework.boot.autoconfigure.SpringBootApplication;
24 | import org.springframework.context.annotation.Bean;
25 | import org.springframework.data.mongodb.core.ReactiveMongoDbFactory;
26 | import org.springframework.data.mongodb.core.ReactiveMongoOperations;
27 | import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
28 | import org.springframework.data.mongodb.core.mapping.event.LoggingEventListener;
29 | import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactory;
30 | import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRepository;
31 | import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
32 |
33 | import com.mongodb.reactivestreams.client.MongoClient;
34 | import com.mongodb.reactivestreams.client.MongoClients;
35 | import com.mongodb.reactivestreams.client.MongoDatabase;
36 |
37 | /**
38 | * @author Mark Paluch
39 | */
40 | @SpringBootApplication
41 | public class ApplicationConfiguration implements BeanClassLoaderAware, BeanFactoryAware {
42 |
43 | @Value("${mongo.database:reactive}") private String database;
44 |
45 | private ClassLoader classLoader;
46 | private BeanFactory beanFactory;
47 |
48 | @Bean
49 | MongoClient mongoClient() {
50 | return MongoClients.create();
51 | }
52 |
53 | @Bean
54 | MongoDatabase mongoDatabase(MongoClient mongoClient) {
55 | return mongoClient.getDatabase(database);
56 | }
57 |
58 | @Bean
59 | ReactiveMongoDbFactory reactiveMongoDbFactory(MongoClient mongoClient) {
60 | return new ReactiveMongoDbFactory(mongoClient, database);
61 | }
62 |
63 | @Bean
64 | ReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDbFactory mongoDbFactory) {
65 | return new ReactiveMongoTemplate(mongoDbFactory);
66 | }
67 |
68 | @Bean
69 | ReactiveMongoRepositoryFactory reactiveMongoRepositoryFactory(ReactiveMongoOperations reactiveMongoOperations) {
70 |
71 | ReactiveMongoRepositoryFactory factory = new ReactiveMongoRepositoryFactory(reactiveMongoOperations);
72 | factory.setRepositoryBaseClass(SimpleReactiveMongoRepository.class);
73 | factory.setBeanClassLoader(classLoader);
74 | factory.setBeanFactory(beanFactory);
75 | factory.setEvaluationContextProvider(DefaultEvaluationContextProvider.INSTANCE);
76 |
77 | return factory;
78 | }
79 |
80 | @Bean
81 | RxJavaPersonRepository rxJavaPersonRepository(ReactiveMongoRepositoryFactory factory) {
82 | return factory.getRepository(RxJavaPersonRepository.class);
83 | }
84 |
85 | @Bean
86 | ReactorPersonRepository reactivePersonRepository(ReactiveMongoRepositoryFactory factory) {
87 | return factory.getRepository(ReactorPersonRepository.class);
88 | }
89 |
90 | @Bean
91 | ReactivePersonRepository mixedReactivePersonRepository(ReactiveMongoRepositoryFactory factory) {
92 | return factory.getRepository(ReactivePersonRepository.class);
93 | }
94 |
95 | @Override
96 | public void setBeanClassLoader(ClassLoader classLoader) {
97 | this.classLoader = classLoader;
98 | }
99 |
100 | @Override
101 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
102 | this.beanFactory = beanFactory;
103 | }
104 |
105 | public @Bean LoggingEventListener mongoEventListener() {
106 | return new LoggingEventListener();
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/test/java/example/ReactiveMongoOperationsIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 | import org.springframework.beans.factory.annotation.Autowired;
25 | import org.springframework.boot.test.context.SpringBootTest;
26 | import org.springframework.data.mongodb.core.ReactiveMongoOperations;
27 | import org.springframework.data.mongodb.core.query.Query;
28 | import org.springframework.test.context.junit4.SpringRunner;
29 |
30 | import reactor.core.publisher.Flux;
31 | import reactor.core.publisher.Mono;
32 | import reactor.test.TestSubscriber;
33 |
34 | /**
35 | * Integration tests showing the usage of Reactive MongoDB support through
36 | * {@link org.springframework.data.mongodb.core.ReactiveMongoOperations}.
37 | *
38 | * @author Mark Paluch
39 | */
40 | @SuppressWarnings("unused")
41 | @RunWith(SpringRunner.class)
42 | @SpringBootTest
43 | public class ReactiveMongoOperationsIntegrationTests {
44 |
45 | @Autowired ReactiveMongoOperations operations;
46 |
47 | Person skyler, walter, flynn;
48 |
49 | @Before
50 | public void setUp() {
51 | TestSubscriber testSubscriber = TestSubscriber.subscribe(operations.dropCollection(Person.class));
52 | testSubscriber.await();
53 |
54 | this.skyler = subscribe(operations.save(new Person("Skyler", "White", 45)));
55 | this.walter = subscribe(operations.save(Mono.just(new Person("Walter", "White", 50))));
56 | }
57 |
58 | @Test
59 | public void shouldReturnCount() {
60 |
61 | Mono count = operations.count(new Query(), Person.class);
62 |
63 | assertThat(count.block(), is(2L));
64 | }
65 |
66 | @Test
67 | public void insertCountAndDeleteChain() {
68 |
69 | flynn = new Person("Walter Jr. (Flynn)", "White", 17);
70 |
71 | Flux flux = operations.insert(Mono.just(flynn))//
72 | .then(() -> {
73 | return operations.count(new Query(), Person.class);
74 | }) //
75 | .flatMap(count -> {
76 | System.out.println("Count: " + count);
77 | assertThat(count, is(3L));
78 | return operations.remove(flynn);
79 | }) //
80 | .flatMap(deleteResult -> operations.count(new Query(), Person.class)) //
81 | .doOnNext(count -> {
82 | System.out.println("Count: " + count);
83 | assertThat(count, is(2L));
84 | });
85 |
86 | flux.then().block();
87 | }
88 |
89 | private T subscribe(Mono extends T> mono) {
90 | return mono.block();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/test/java/example/ReactivePersonRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import java.util.List;
22 |
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.springframework.beans.factory.annotation.Autowired;
27 | import org.springframework.boot.test.context.SpringBootTest;
28 | import org.springframework.test.context.junit4.SpringRunner;
29 |
30 | import reactor.core.publisher.Flux;
31 | import reactor.core.publisher.Mono;
32 | import reactor.test.TestSubscriber;
33 | import rx.Observable;
34 | import rx.Single;
35 |
36 | /**
37 | * Integration tests showing the usage of Reactive MongoDB support using mixed reactive types through Spring Data
38 | * repositories.
39 | *
40 | * @author Mark Paluch
41 | */
42 | @SuppressWarnings("unused")
43 | @RunWith(SpringRunner.class)
44 | @SpringBootTest
45 | public class ReactivePersonRepositoryIntegrationTests {
46 |
47 | @Autowired ReactivePersonRepository repository;
48 |
49 | Person skyler, walter, flynn;
50 |
51 | @Before
52 | public void setUp() {
53 | TestSubscriber testSubscriber = TestSubscriber.subscribe(repository.deleteAll());
54 | testSubscriber.await();
55 |
56 | this.skyler = subscribe(repository.save(new Person("Skyler", "White", 45)));
57 | this.walter = subscribe(repository.save(new Person("Walter", "White", 50)));
58 | this.flynn = subscribe(repository.save(new Person("Walter Jr. (Flynn)", "White", 17)));
59 | }
60 |
61 | @Test
62 | public void shouldFindByLastname() {
63 |
64 | Observable whites = repository.findByLastname("White");
65 |
66 | List result = whites.toList().toBlocking().single();
67 |
68 | assertThat(result, hasItems(skyler, walter, flynn));
69 | }
70 |
71 | @Test
72 | public void shouldFindByFirstnameAndLastname() {
73 |
74 | Mono walter = repository.findByFirstnameAndLastname("Walter", "White");
75 |
76 | assertThat(walter.block(), is(this.walter));
77 | }
78 |
79 | /**
80 | * Parameters can be wrapped inside of {@link Mono}, {@link Flux}, or {@link org.reactivestreams.Publisher}.
81 | * Parameters are unwrapped upon subscription to the result type.
82 | */
83 | @Test
84 | public void shouldFindByWrappedLastname() {
85 |
86 | Mono walter = repository.findByFirstnameAndLastname(Mono.just("Walter"), "White");
87 |
88 | TestSubscriber testSubscriber = TestSubscriber.subscribe(walter);
89 |
90 | testSubscriber.await();
91 | testSubscriber.assertNoError();
92 | testSubscriber.assertValues(this.walter);
93 | }
94 |
95 | /**
96 | * Reactive Repositories allow redeclaration of base methods and wrapper type conversion.
97 | */
98 | @Test
99 | public void findOne() {
100 |
101 | Single findOneRxJava = repository.findOne(Single.just(skyler.getObjectId()));
102 | Person skylerFromRxJava = findOneRxJava.toBlocking().value();
103 |
104 | assertThat(skylerFromRxJava, is(skyler));
105 |
106 | Mono findOneReactor = repository.findOne(Mono.just(skyler.getObjectId()));
107 | Person skylerFromRxReactor = findOneReactor.block();
108 |
109 | assertThat(skylerFromRxReactor, is(skyler));
110 | }
111 |
112 | private T subscribe(Mono extends T> mono) {
113 | return mono.block();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/test/java/example/ReactorPersonRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import org.assertj.core.util.Sets;
22 | import org.junit.Before;
23 | import org.junit.Test;
24 | import org.junit.runner.RunWith;
25 | import org.springframework.beans.factory.annotation.Autowired;
26 | import org.springframework.boot.test.context.SpringBootTest;
27 | import org.springframework.test.context.junit4.SpringRunner;
28 |
29 | import reactor.core.publisher.Flux;
30 | import reactor.core.publisher.Mono;
31 | import reactor.test.TestSubscriber;
32 |
33 | /**
34 | * Integration tests showing the usage of Reactive MongoDB support using Project Reactor types through Spring Data
35 | * repositories.
36 | *
37 | * @author Mark Paluch
38 | */
39 | @SuppressWarnings("unused")
40 | @RunWith(SpringRunner.class)
41 | @SpringBootTest
42 | public class ReactorPersonRepositoryIntegrationTests {
43 |
44 | @Autowired ReactorPersonRepository repository;
45 |
46 | Person skyler, walter, flynn;
47 |
48 | @Before
49 | public void setUp() {
50 | TestSubscriber testSubscriber = TestSubscriber.subscribe(repository.deleteAll());
51 | testSubscriber.await();
52 |
53 | this.skyler = subscribe(repository.save(new Person("Skyler", "White", 45)));
54 | this.walter = subscribe(repository.save(new Person("Walter", "White", 50)));
55 | this.flynn = subscribe(repository.save(new Person("Walter Jr. (Flynn)", "White", 17)));
56 | }
57 |
58 | /**
59 | * Observables are handles to an execution. Nothing happens without a subscription to a
60 | * {@link org.reactivestreams.Publisher}.
61 | */
62 | @Test
63 | public void shouldExecuteOnlyOnSubscribe() {
64 |
65 | assertThat(subscribe(repository.count()), is(3L));
66 |
67 | repository.save(new Person("Marie", "Schrader", 38));
68 | repository.save(new Person("Hank", "Schrader", 43));
69 |
70 | assertThat(subscribe(repository.count()), is(3L));
71 | }
72 |
73 | /**
74 | * {@link Flux} execution can emit zero, one or many items. Declaring {@link Flux} as return type translates to a
75 | * MongoDB {@code find} execution.
76 | */
77 | @Test
78 | public void shouldFindByLastname() {
79 |
80 | Flux whites = repository.findByLastname("White");
81 |
82 | TestSubscriber testSubscriber = TestSubscriber.subscribe(whites.doOnNext(System.out::println));
83 |
84 | testSubscriber.await();
85 | testSubscriber.assertNoError();
86 | testSubscriber.assertValueCount(3);
87 | testSubscriber.assertContainValues(Sets.newLinkedHashSet(skyler, walter, flynn));
88 | }
89 |
90 | /**
91 | * {@link Mono} execution can emit zero or one item. Declaring {@link Mono} as return type translates to a MongoDB
92 | * {@code findOne} execution.
93 | */
94 | @Test
95 | public void shouldFindByFirstnameAndLastname() {
96 |
97 | Mono walter = repository.findByFirstnameAndLastname("Walter", "White");
98 |
99 | TestSubscriber testSubscriber = TestSubscriber.subscribe(walter);
100 |
101 | testSubscriber.await();
102 | testSubscriber.assertNoError();
103 | testSubscriber.awaitAndAssertNextValues(this.walter);
104 | }
105 |
106 | /**
107 | * Parameters can be wrapped inside of {@link Mono}, {@link Flux}, or {@link org.reactivestreams.Publisher}.
108 | * Parameters are unwrapped upon subscription to the result type.
109 | */
110 | @Test
111 | public void shouldFindByWrappedLastname() {
112 |
113 | Flux whites = repository.findByLastname(Mono.just("White"));
114 |
115 | TestSubscriber testSubscriber = TestSubscriber.subscribe(whites);
116 |
117 | testSubscriber.await();
118 | testSubscriber.assertNoError();
119 | testSubscriber.assertValueCount(3);
120 | testSubscriber.assertContainValues(Sets.newLinkedHashSet(skyler, walter, flynn));
121 | }
122 |
123 | private T subscribe(Mono extends T> mono) {
124 | return mono.block();
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/test/java/example/RxJavaPersonRepositoryIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.Matchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 | import org.springframework.beans.factory.annotation.Autowired;
25 | import org.springframework.boot.test.context.SpringBootTest;
26 | import org.springframework.test.context.junit4.SpringRunner;
27 |
28 | import rx.Observable;
29 | import rx.Single;
30 | import rx.observers.TestSubscriber;
31 |
32 | /**
33 | * Integration tests showing the usage of Reactive MongoDB support using RxJava types through Spring Data repositories.
34 | *
35 | * @author Mark Paluch
36 | */
37 | @SuppressWarnings("unused")
38 | @RunWith(SpringRunner.class)
39 | @SpringBootTest
40 | public class RxJavaPersonRepositoryIntegrationTests {
41 |
42 | @Autowired RxJavaPersonRepository repository;
43 |
44 | Person skyler, walter, flynn;
45 |
46 | @Before
47 | public void setUp() {
48 | TestSubscriber testSubscriber = new TestSubscriber<>();
49 | repository.deleteAll().subscribe(testSubscriber);
50 | testSubscriber.awaitTerminalEvent();
51 |
52 | this.skyler = subscribe(repository.save(new Person("Skyler", "White", 45)));
53 | this.walter = subscribe(repository.save(new Person("Walter", "White", 50)));
54 | this.flynn = subscribe(repository.save(new Person("Walter Jr. (Flynn)", "White", 17)));
55 | }
56 |
57 | /**
58 | * Observables are handles to an execution. Nothing happens without a subscription to a {@link Observable}.
59 | */
60 | @Test
61 | public void shouldExecuteOnlyOnSubscribe() {
62 |
63 | assertThat(subscribe(repository.count()), is(3L));
64 |
65 | repository.save(new Person("Marie", "Schrader", 38));
66 | repository.save(new Person("Hank", "Schrader", 43));
67 |
68 | assertThat(subscribe(repository.count()), is(3L));
69 | }
70 |
71 | /**
72 | * {@link Observable} execution can emit zero, one or many items. Declaring {@link Observable} as return type
73 | * translates to a MongoDB {@code find} execution.
74 | */
75 | @Test
76 | public void shouldFindByLastname() {
77 |
78 | Observable whites = repository.findByLastname("White");
79 |
80 | TestSubscriber testSubscriber = new TestSubscriber<>();
81 |
82 | whites.doOnNext(System.out::println).subscribe(testSubscriber);
83 |
84 | testSubscriber.awaitTerminalEvent();
85 | testSubscriber.assertNoErrors();
86 | testSubscriber.assertValueCount(3);
87 |
88 | assertThat(testSubscriber.getOnNextEvents(), hasItems(skyler, walter, flynn));
89 | }
90 |
91 | /**
92 | * {@link Single} execution can emit zero or one item. Declaring {@link Single} as return type translates to a MongoDB
93 | * {@code findOne} execution.
94 | */
95 | @Test
96 | public void shouldFindByFirstnameAndLastname() {
97 |
98 | Single walter = repository.findByFirstnameAndLastname("Walter", "White");
99 |
100 | TestSubscriber testSubscriber = new TestSubscriber<>();
101 |
102 | walter.subscribe(testSubscriber);
103 |
104 | testSubscriber.awaitTerminalEvent();
105 | testSubscriber.assertNoErrors();
106 |
107 | testSubscriber.assertValueCount(1);
108 |
109 | assertThat(testSubscriber.getOnNextEvents(), hasItems(this.walter));
110 | }
111 |
112 | /**
113 | * Parameters can be wrapped inside of {@link Single} or {@link Observable}. Parameters are unwrapped upon
114 | * subscription to the result type.
115 | */
116 | @Test
117 | public void shouldFindByWrappedLastname() {
118 |
119 | Observable whites = repository.findByLastname(Single.just("White"));
120 |
121 | TestSubscriber testSubscriber = new TestSubscriber<>();
122 |
123 | whites.subscribe(testSubscriber);
124 |
125 | testSubscriber.awaitTerminalEvent();
126 | testSubscriber.assertNoErrors();
127 |
128 | testSubscriber.assertValueCount(3);
129 |
130 | assertThat(testSubscriber.getOnNextEvents(), hasItems(skyler, walter, flynn));
131 | }
132 |
133 | private T subscribe(Single extends T> single) {
134 | return single.toBlocking().value();
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/mongodb-reactive/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 | logging.level.org.springframework.data.mongodb=INFO
3 | logging.level.org.springframework.boot.autoconfigure.mongo.embedded=WARN
4 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.springone.2016
6 | whats-new-in-spring-data
7 | 1.0.0.BUILD-SNAPSHOT
8 | pom
9 |
10 | What's new in Spring Data?
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 1.4.0.RELEASE
16 |
17 |
18 |
19 | jpa-query-by-example
20 | mongodb-query-by-example
21 | jpa-projections
22 | mongodb-composed-annotations
23 | jpa-query-method-wrapped-parameters
24 | redis-cluster
25 | redis-repositories
26 | mongodb-reactive
27 |
28 |
29 |
30 |
31 | 1.1.3
32 | 1.8
33 | 4.0.9
34 | Ingalls-M1
35 |
36 |
37 |
38 |
39 |
40 | cstrobl
41 | Christoph Strobl
42 | cstrobl@pivotal.io
43 |
44 |
45 | mpaluch
46 | Mark Paluch
47 | mpaluch@pivotal.io
48 |
49 |
50 |
51 |
52 |
53 |
54 | org.projectlombok
55 | lombok
56 | 1.16.6
57 | provided
58 |
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-devtools
63 | true
64 |
65 |
66 |
67 |
68 |
69 | org.springframework.boot
70 | spring-boot-starter-test
71 | test
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-compiler-plugin
81 |
82 | ${java.version}
83 | ${java.version}
84 | -parameters
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | spring-libs-snapshot
94 | https://repo.spring.io/libs-snapshot
95 |
96 |
97 |
98 |
99 |
100 | spring-libs-snapshot
101 | https://repo.spring.io/libs-snapshot
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/readme.adoc:
--------------------------------------------------------------------------------
1 | = What's new in Spring Data?
2 |
3 | image:https://travis-ci.org/mp911de/whats-new-in-spring-data.svg?branch=master["Build Status", link="https://travis-ci.org/mp911de/whats-new-in-spring-data"]
4 |
5 | This repository contains code for the https://2016.event.springoneplatform.io/schedule/sessions/what_s_new_in_spring_data.html[What's New in Spring Data?] talk. It will give you a broad overview of the new features introduced in the latest Spring Data release trains.
6 |
7 |
8 | == Building the project
9 |
10 | === Prerequisites
11 |
12 | - Maven 3
13 | - Java 8
14 |
15 | ```
16 | $ git clone https://github.com/SpringOnePlatform2016/whats-new-in-spring-data.git
17 | $ cd whats-new-in-spring-data
18 | $ make -C redis-cluster start
19 | $ mvn clean install
20 | ```
21 |
22 | ## Getting Help
23 |
24 | The main project http://projects.spring.io/spring-data/[website] contains links to basic project information such as source code, JavaDocs, Issue tracking, etc.
25 |
26 | For more detailed questions, please refer to http://stackoverflow.com/questions/tagged/spring-data[spring-data on stackoverflow]. If you are new to Spring as well as to Spring Data, look for information about https://spring.io/projects[Spring projects].
27 |
--------------------------------------------------------------------------------
/redis-cluster/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /work/
3 | dump.rdb
4 |
--------------------------------------------------------------------------------
/redis-cluster/Makefile:
--------------------------------------------------------------------------------
1 |
2 | REDIS_VERSION:=3.2.0
3 |
4 | #########
5 | # Cluster
6 | #########
7 | .PRECIOUS: work/cluster-%.conf
8 |
9 | work/cluster-%.conf:
10 | @mkdir -p $(@D)
11 |
12 | echo port $* >> $@
13 | echo cluster-enabled yes >> $@
14 | echo cluster-config-file $(shell pwd)/work/nodes-$*.conf >> $@
15 | echo cluster-node-timeout 5 >> $@
16 | echo pidfile $(shell pwd)/work/cluster-$*.pid >> $@
17 | echo logfile $(shell pwd)/work/cluster-$*.log >> $@
18 | echo save \"\" >> $@
19 |
20 | work/cluster-%.pid: work/cluster-%.conf work/redis/bin/redis-server
21 | work/redis/bin/redis-server $< &
22 |
23 | cluster-start: work/cluster-7379.pid work/cluster-7380.pid work/cluster-7381.pid work/cluster-7382.pid
24 |
25 | work/meet-%:
26 | -work/redis/bin/redis-cli -p $* cluster meet 127.0.0.1 7379
27 |
28 | # Handled separately because this node is a slave
29 | work/meet-7381:
30 | -work/redis/bin/redis-cli -p 7381 cluster meet 127.0.0.1 7379
31 | sleep 2
32 | -work/redis/bin/redis-cli -p 7381 cluster replicate $(shell work/redis/bin/redis-cli -p 7379 cluster myid)
33 |
34 | # Handled separately because this node is a slave
35 | work/meet-7382:
36 | -work/redis/bin/redis-cli -p 7382 cluster meet 127.0.0.1 7379
37 | sleep 2
38 | -work/redis/bin/redis-cli -p 7382 cluster replicate $(shell work/redis/bin/redis-cli -p 7380 cluster myid)
39 |
40 | cluster-meet: work/meet-7380 work/meet-7381 work/meet-7382
41 |
42 | cluster-stop: stop-7379 stop-7380 stop-7381 stop-7382
43 |
44 | cluster-slots:
45 | -work/redis/bin/redis-cli -p 7379 cluster addslots $(shell seq 0 8191)
46 | -work/redis/bin/redis-cli -p 7380 cluster addslots $(shell seq 8192 16383)
47 |
48 | cluster-init: cluster-start cluster-meet cluster-slots
49 |
50 | ########
51 | # Global
52 | ########
53 | clean:
54 | rm -rf work/*.conf work/*.log
55 |
56 | clobber:
57 | rm -rf work
58 |
59 | work/redis/bin/redis-cli work/redis/bin/redis-server:
60 | @mkdir -p work/redis
61 |
62 | curl -sSL https://github.com/antirez/redis/archive/$(REDIS_VERSION).tar.gz | tar xzf - -C work
63 | $(MAKE) -C work/redis-$(REDIS_VERSION) -j
64 | $(MAKE) -C work/redis-$(REDIS_VERSION) PREFIX=$(shell pwd)/work/redis install
65 | rm -rf work/redis-$(REDIS_VERSION)
66 |
67 | start: cluster-init
68 |
69 | stop-%: work/redis/bin/redis-cli
70 | -work/redis/bin/redis-cli -p $* shutdown
71 |
72 | stop: cluster-stop
73 |
--------------------------------------------------------------------------------
/redis-cluster/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | spring-data-redis-cluster-support
6 | What's new in Spring Data? - Redis Cluster support
7 |
8 |
9 | com.springone.2016
10 | whats-new-in-spring-data
11 | 1.0.0.BUILD-SNAPSHOT
12 |
13 |
14 |
15 | 2.9.0
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-redis
23 |
24 |
25 |
26 | org.springframework.data
27 | spring-data-redis
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/redis-cluster/readme.md:
--------------------------------------------------------------------------------
1 | # Spring Data Redis - Cluster Examples #
2 |
3 | This project contains Redis 3 Cluster specific features of Spring Data Redis.
4 |
5 | To run the code in this sample a running cluster environment is required. Please refer to the [redis cluster-tutorial](http://redis.io/topics/cluster-tutorial) for detailed information or check the Cluster Setup section below.
6 |
7 | ## Support for Cluster ##
8 |
9 | Cluster Support uses the same building blocks as the non clustered counterpart. We use `application.properties` to point to an initial set of known cluster nodes which will be picked up by the auto configuration.
10 |
11 | ```properties
12 | spring.redis.cluster.nodes[0]=127.0.0.1:7379
13 | spring.redis.cluster.nodes[1]=127.0.0.1:7380
14 | spring.redis.cluster.nodes[2]=127.0.0.1:7381
15 | ```
16 |
17 | **INFORMATION:** The tests flush the db of all known instances during the JUnit _setup_ phase to allow inspecting data directly on the cluster nodes after a test is run.
18 |
19 | ## Cluster Setup ##
20 |
21 | To quickly set up a cluster of 4 nodes (2 master | 2 slave) simply invoke `make start`.
22 |
23 |
24 | ```bash
25 | $ ./make start
26 | ```
27 |
28 | It is now possible to connect to the cluster using the `redis-cli`.
29 |
30 | ```bash
31 | redis/src $ ./redis-cli -c -p 7379
32 | 127.0.0.1:7379> cluster nodes
33 |
34 | b85eeb... 127.0.0.1:7380 master - 0 1466584139197 0 connected 8192-16383
35 | 952146... 127.0.0.1:7381 slave 42b9e7... 0 1466584139197 2 connected
36 | 42b9e7... 127.0.0.1:7379 myself,master - 0 0 1 connected 0-8191
37 | 208c1b... 127.0.0.1:7382 slave b85eeb... 0 1466584139197 3 connected
38 | ```
39 |
40 | To shutdown the cluster use the `make stop` command.
41 |
42 | ```bash
43 | $ ./make stop
44 | ```
45 |
--------------------------------------------------------------------------------
/redis-cluster/src/main/java/example/AppConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
19 | import org.springframework.data.redis.connection.RedisConnectionFactory;
20 | import org.springframework.data.redis.core.RedisTemplate;
21 |
22 | /**
23 | * Application context configuration setting up {@link RedisConnectionFactory} and {@link RedisTemplate} according to
24 | * {@link ClusterConfigurationProperties}.
25 | *
26 | * @author Christoph Strobl
27 | */
28 | @EnableAutoConfiguration
29 | public class AppConfig {
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/redis-cluster/src/test/java/example/BasicUsageTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.core.Is.*;
19 | import static org.hamcrest.core.IsCollectionContaining.*;
20 | import static org.junit.Assert.*;
21 |
22 | import java.util.Arrays;
23 |
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.boot.test.context.SpringBootTest;
29 | import org.springframework.dao.DataAccessException;
30 | import org.springframework.data.redis.connection.RedisConnection;
31 | import org.springframework.data.redis.core.RedisCallback;
32 | import org.springframework.data.redis.core.RedisOperations;
33 | import org.springframework.data.redis.core.RedisTemplate;
34 | import org.springframework.test.context.junit4.SpringRunner;
35 |
36 | /**
37 | * {@link BasicUsageTests} shows general usage of {@link RedisTemplate} and {@link RedisOperations} in a clustered
38 | * environment.
39 | *
40 | * @author Christoph Strobl
41 | */
42 | @RunWith(SpringRunner.class)
43 | @SpringBootTest(classes = AppConfig.class)
44 | public class BasicUsageTests {
45 |
46 | @Autowired RedisTemplate template;
47 |
48 | @Before
49 | public void setUp() {
50 |
51 | template.execute(new RedisCallback() {
52 |
53 | @Override
54 | public String doInRedis(RedisConnection connection) throws DataAccessException {
55 | connection.flushDb();
56 | return "FLUSHED";
57 | }
58 | });
59 | }
60 |
61 | /**
62 | * Operation executed on a single node and slot.
63 | * -> {@code SLOT 5798} served by {@code 127.0.0.1:7379}
64 | */
65 | @Test
66 | public void singleSlotOperation() {
67 |
68 | template.opsForValue().set("name", "rand al'thor"); // slot 5798
69 | assertThat(template.opsForValue().get("name"), is("rand al'thor"));
70 | }
71 |
72 | /**
73 | * Operation executed on multiple nodes and slots.
74 | * -> {@code SLOT 5798} served by {@code 127.0.0.1:7379}
75 | * -> {@code SLOT 14594} served by {@code 127.0.0.1:7380}
76 | */
77 | @Test
78 | public void multiSlotOperation() {
79 |
80 | template.opsForValue().set("name", "matrim cauthon"); // slot 5798
81 | template.opsForValue().set("nickname", "prince of the ravens"); // slot 14594
82 |
83 | assertThat(template.opsForValue().multiGet(Arrays.asList("name", "nickname")),
84 | hasItems("matrim cauthon", "prince of the ravens"));
85 | }
86 |
87 | /**
88 | * Operation executed on a single node and slot because of pinned slot key
89 | * -> {@code SLOT 5798} served by {@code 127.0.0.1:7379}
90 | */
91 | @Test
92 | public void fixedSlotOperation() {
93 |
94 | template.opsForValue().set("{user}.name", "perrin aybara"); // slot 5474
95 | template.opsForValue().set("{user}.nickname", "wolfbrother"); // slot 5474
96 |
97 | assertThat(template.opsForValue().multiGet(Arrays.asList("{user}.name", "{user}.nickname")),
98 | hasItems("perrin aybara", "wolfbrother"));
99 | }
100 |
101 | /**
102 | * Operation executed across the cluster to retrieve cumulated result.
103 | * -> {@code KEY age} served by {@code 127.0.0.1:7379}
104 | * -> {@code KEY name} served by {@code 127.0.0.1:7379}
105 | * -> {@code KEY nickname} served by {@code 127.0.0.1:7380}
106 | */
107 | @Test
108 | public void multiNodeOperation() {
109 |
110 | template.opsForValue().set("age", "23"); // slot 741;
111 | template.opsForValue().set("name", "rand al'thor"); // slot 5798
112 | template.opsForValue().set("nickname", "dragon reborn"); // slot 14594
113 |
114 | assertThat(template.keys("*"), hasItems("name", "nickname", "age"));
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/redis-cluster/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.redis.cluster.nodes[0]=127.0.0.1:7379
2 | spring.redis.cluster.nodes[1]=127.0.0.1:7380
3 | spring.redis.cluster.nodes[2]=127.0.0.1:7381
4 |
--------------------------------------------------------------------------------
/redis-repositories/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/redis-repositories/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | spring-data-redis-repository-support
6 | What's new in Spring Data? - Redis Repositories
7 |
8 |
9 | com.springone.2016
10 | whats-new-in-spring-data
11 | 1.0.0.BUILD-SNAPSHOT
12 |
13 |
14 |
15 | 2.9.0
16 |
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-redis
23 |
24 |
25 |
26 | com.github.kstyrc
27 | embedded-redis
28 | 0.6
29 | test
30 |
31 |
32 |
33 | org.springframework.data
34 | spring-data-keyvalue
35 | 1.2.0.M1
36 |
37 |
38 |
39 | org.springframework.data
40 | spring-data-redis
41 | 1.8.0.M1
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/redis-repositories/src/main/java/example/City.java:
--------------------------------------------------------------------------------
1 | package example;
2 |
3 | import org.springframework.data.annotation.Id;
4 | import org.springframework.data.keyvalue.annotation.KeySpace;
5 |
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | class City {
12 |
13 | String name;
14 |
15 | public City(String name) {
16 | this.name = name;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/redis-repositories/src/main/java/example/Person.java:
--------------------------------------------------------------------------------
1 | package example;
2 |
3 | import java.util.Collections;
4 | import java.util.Map;
5 |
6 | import org.springframework.data.annotation.Id;
7 | import org.springframework.data.annotation.Reference;
8 | import org.springframework.data.redis.core.RedisHash;
9 | import org.springframework.data.redis.core.index.Indexed;
10 |
11 | import lombok.Data;
12 |
13 | @Data
14 | @RedisHash("persons")
15 | class Person {
16 |
17 | @Id String id;
18 | @Indexed String firstname;
19 | String lastname;
20 |
21 | Map attributes = Collections.emptyMap();
22 |
23 | City city;
24 |
25 | @Reference Person mother;
26 | }
27 |
--------------------------------------------------------------------------------
/redis-repositories/src/main/java/example/PersonRepository.java:
--------------------------------------------------------------------------------
1 | package example;
2 |
3 | import java.util.List;
4 |
5 | import org.springframework.data.repository.CrudRepository;
6 |
7 | interface PersonRepository extends CrudRepository {
8 |
9 | List findByFirstname(String firstname);
10 |
11 | List findByLastname(String lastname);
12 |
13 | List findByFirstnameAndLastname(String firstname, String lastname);
14 | }
15 |
--------------------------------------------------------------------------------
/redis-repositories/src/test/java/example/EmbeddedRedisRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import redis.embedded.RedisServer;
19 |
20 | import java.io.IOException;
21 |
22 | import org.junit.rules.ExternalResource;
23 |
24 | /**
25 | * JUnit rule implementation to start and shut down an embedded Redis instance.
26 | *
27 | * @author Christoph Strobl
28 | * @author Oliver Gierke
29 | */
30 | public class EmbeddedRedisRule extends ExternalResource {
31 |
32 | private RedisServer server;
33 |
34 | /*
35 | * (non-Javadoc)
36 | * @see org.junit.rules.ExternalResource#before()
37 | */
38 | @Override
39 | protected void before() throws IOException {
40 |
41 | this.server = new RedisServer(6379);
42 | this.server.start();
43 | }
44 |
45 | /*
46 | * (non-Javadoc)
47 | * @see org.junit.rules.ExternalResource#after()
48 | */
49 | @Override
50 | protected void after() {
51 | this.server.stop();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/redis-repositories/src/test/java/example/RedisRepositoryTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import static org.hamcrest.CoreMatchers.*;
19 | import static org.junit.Assert.*;
20 |
21 | import java.util.Arrays;
22 |
23 | import org.junit.Before;
24 | import org.junit.ClassRule;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.boot.test.context.SpringBootTest;
29 | import org.springframework.data.keyvalue.core.KeyValueTemplate;
30 | import org.springframework.data.redis.connection.RedisConnectionFactory;
31 | import org.springframework.data.redis.core.PartialUpdate;
32 | import org.springframework.data.redis.core.RedisOperations;
33 | import org.springframework.test.context.junit4.SpringRunner;
34 |
35 | /**
36 | * @author Thomas Darimont
37 | * @author Oliver Gierke
38 | */
39 | @RunWith(SpringRunner.class)
40 | @SpringBootTest
41 | public class RedisRepositoryTests {
42 |
43 | public static @ClassRule EmbeddedRedisRule embeddedRedis = new EmbeddedRedisRule();
44 |
45 | @Autowired RedisConnectionFactory redisConnectionFactory;
46 | @Autowired RedisOperations redis;
47 | @Autowired KeyValueTemplate kvTemplate;
48 | @Autowired PersonRepository repository;
49 |
50 | @Before
51 | public void setup() {
52 | kvTemplate.delete(Person.class);
53 | }
54 |
55 | @Test
56 | public void simpleFindByMultipleProperties() {
57 |
58 | Person egwene = new Person();
59 | egwene.firstname = "egwene";
60 | egwene.lastname = "al'vere";
61 | egwene.city = new City("new york");
62 |
63 | Person marin = new Person();
64 | marin.firstname = "marin";
65 | marin.lastname = "al'vere";
66 |
67 | repository.save(Arrays.asList(egwene, marin));
68 |
69 | assertThat(repository.findByLastname("al'vere").size(), is(2));
70 |
71 | assertThat(repository.findByFirstnameAndLastname("egwene", "al'vere").size(), is(1));
72 | assertThat(repository.findByFirstnameAndLastname("egwene", "al'vere").get(0), is(egwene));
73 | }
74 |
75 | @Test
76 | public void partialUpdate() {
77 |
78 | Person egwene = new Person();
79 | egwene.firstname = "egwene";
80 | egwene.lastname = "al'vere";
81 | egwene.city = new City("new york");
82 |
83 | Person marin = new Person();
84 | marin.firstname = "marin";
85 | marin.lastname = "al'vere";
86 |
87 | repository.save(Arrays.asList(egwene, marin));
88 |
89 | PartialUpdate partialUpdate = PartialUpdate //
90 | .newPartialUpdate(egwene.getId(), Person.class)//
91 | .del("lastname")//
92 | .set("city.name", "Tear");
93 |
94 | kvTemplate.update(partialUpdate);
95 |
96 | Person loaded = repository.findOne(egwene.getId());
97 |
98 | assertThat(loaded.getLastname(), is(nullValue()));
99 | assertThat(loaded.getCity().getName(), is(equalTo("Tear")));
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/redis-repositories/src/test/java/example/RedisTestConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package example;
17 |
18 | import example.RedisTestConfiguration.CustomIndexConfiguration;
19 |
20 | import java.util.Arrays;
21 |
22 | import javax.annotation.PreDestroy;
23 |
24 | import org.springframework.beans.factory.annotation.Autowired;
25 | import org.springframework.boot.autoconfigure.SpringBootApplication;
26 | import org.springframework.data.redis.connection.RedisConnectionFactory;
27 | import org.springframework.data.redis.core.index.IndexConfiguration;
28 | import org.springframework.data.redis.core.index.RedisIndexDefinition;
29 | import org.springframework.data.redis.core.index.SimpleIndexDefinition;
30 | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
31 |
32 | /**
33 | * @author Thomas Darimont
34 | * @author Oliver Gierke
35 | * @author Christoph Strobl
36 | */
37 | @SpringBootApplication
38 | @EnableRedisRepositories(indexConfiguration = CustomIndexConfiguration.class)
39 | public class RedisTestConfiguration {
40 |
41 | @Autowired RedisConnectionFactory factory;
42 |
43 | /**
44 | * Clear database before shut down.
45 | */
46 | @PreDestroy
47 | public void flushTestDb() {
48 | factory.getConnection().flushDb();
49 | }
50 |
51 | static class CustomIndexConfiguration extends IndexConfiguration {
52 |
53 | @Override
54 | protected Iterable initialConfiguration() {
55 | return Arrays.asList(new SimpleIndexDefinition("persons", "lastname"));
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------