Skip to content

Commit 4c04ddf

Browse files
DATAMONGO-1245 - QBE now uses common MongoRegexCreator.
Introduced MongoRegexCreator. Added some javadoc. Still need to do reference documentation.
1 parent 0997610 commit 4c04ddf

File tree

10 files changed

+504
-195
lines changed

10 files changed

+504
-195
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/domain/Example.java

Lines changed: 192 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,75 +18,142 @@
1818
import java.util.LinkedHashMap;
1919
import java.util.Map;
2020

21+
import org.springframework.data.repository.query.parser.Part;
22+
import org.springframework.data.repository.query.parser.Part.Type;
2123
import org.springframework.util.Assert;
2224
import org.springframework.util.ClassUtils;
2325

2426
/**
27+
* Support for query by example (QBE).
28+
*
2529
* @author Christoph Strobl
2630
* @param <T>
2731
*/
2832
public class Example<T> {
2933

3034
private final T probe;
3135

32-
private NullHandling nullHandling = NullHandling.IGNORE_NULL;
36+
private NullHandler nullHandler = NullHandler.IGNORE;
3337
private StringMatcher defaultStringMatcher = StringMatcher.DEFAULT;
38+
private PropertySpecifiers propertySpecifiers = new PropertySpecifiers();
3439

3540
private boolean ignoreCase = false;
3641

37-
private Map<String, PropertySpecifier> propertySpecifiers = new LinkedHashMap<String, PropertySpecifier>();
38-
42+
/**
43+
* Create a new {@link Example} including all non-null properties by default.
44+
*
45+
* @param probe The example to use. Must not be {@literal null}.
46+
*/
3947
public <S extends T> Example(S probe) {
4048

4149
Assert.notNull(probe, "Probe must not be null!");
4250
this.probe = probe;
4351
}
4452

53+
/**
54+
* Get the example used.
55+
*
56+
* @return never {@literal null}.
57+
*/
4558
public T getProbe() {
4659
return probe;
4760
}
4861

49-
public NullHandling getNullHandling() {
50-
return nullHandling;
62+
/**
63+
* Get defined null handling.
64+
*
65+
* @return never {@literal null}
66+
*/
67+
public NullHandler getNullHandler() {
68+
return nullHandler;
5169
}
5270

71+
/**
72+
* Get defined {@link StringMatcher}.
73+
*
74+
* @return never {@literal null}.
75+
*/
5376
public StringMatcher getDefaultStringMatcher() {
5477
return defaultStringMatcher;
5578
}
5679

80+
/**
81+
* @return {@literal true} if {@link String} should be matched with ignore case option.
82+
*/
5783
public boolean isIngnoreCaseEnabled() {
5884
return this.ignoreCase;
5985
}
6086

87+
/**
88+
* @param path Dot-Path to property.
89+
* @return {@literal true} in case {@link PropertySpecifier} defined for given path.
90+
*/
6191
public boolean hasPropertySpecifier(String path) {
62-
return propertySpecifiers.containsKey(path);
92+
return propertySpecifiers.hasSpecifierForPath(path);
6393
}
6494

65-
public PropertySpecifier getPropertySpecifier(String propertyPath) {
66-
return this.propertySpecifiers.get(propertyPath);
95+
/**
96+
* @param path Dot-Path to property.
97+
* @return {@literal null} when no {@link PropertySpecifier} defined for path.
98+
*/
99+
public PropertySpecifier getPropertySpecifier(String path) {
100+
return propertySpecifiers.getForPath(path);
67101
}
68102

103+
/**
104+
* @return true if at least one {@link PropertySpecifier} defined.
105+
*/
69106
public boolean hasPropertySpecifiers() {
70-
return !this.propertySpecifiers.isEmpty();
107+
return this.propertySpecifiers.hasValues();
71108
}
72109

110+
/**
111+
* Get the actual type for the example used.
112+
*
113+
* @return
114+
*/
73115
@SuppressWarnings("unchecked")
74116
public Class<? extends T> getProbeType() {
75117
return (Class<? extends T>) ClassUtils.getUserClass(probe.getClass());
76118
}
77119

120+
/**
121+
* Create a new {@link Example} including all non-null properties by default.
122+
*
123+
* @param probe must not be {@literal null}.
124+
* @return
125+
*/
78126
public static <S extends T, T> Example<T> exampleOf(S probe) {
79127
return new Example<T>(probe);
80128
}
81129

130+
/**
131+
* Create a new {@link Example} including all non-null properties, excluding explicitly named properties to ignore.
132+
*
133+
* @param probe must not be {@literal null}.
134+
* @return
135+
*/
82136
public static <S extends T, T> Example<T> exampleOf(S probe, String... ignoredProperties) {
83137
return new Builder<T>(probe).ignore(ignoredProperties).get();
84138
}
85139

140+
/**
141+
* Create new {@link Builder} for specifying {@link Example}.
142+
*
143+
* @param probe must not be {@literal null}.
144+
* @return
145+
* @see Builder
146+
*/
86147
public static <S extends T, T> Builder<S> newExampleOf(S probe) {
87148
return new Builder<S>(probe);
88149
}
89150

151+
/**
152+
* Builder for specifying desired behavior of {@link Example}.
153+
*
154+
* @author Christoph Strobl
155+
* @param <T>
156+
*/
90157
public static class Builder<T> {
91158

92159
private Example<T> example;
@@ -95,50 +162,103 @@ public static class Builder<T> {
95162
example = new Example<T>(probe);
96163
}
97164

98-
public Builder<T> with(NullHandling nullHandling) {
165+
/**
166+
* Sets {@link NullHandler} used for {@link Example}.
167+
*
168+
* @param nullHandling
169+
* @return
170+
* @see Builder#nullHandling(NullHandler)
171+
*/
172+
public Builder<T> with(NullHandler nullHandling) {
99173
return nullHandling(nullHandling);
100174
}
101175

176+
/**
177+
* Sets default {@link StringMatcher} used for {@link Example}.
178+
*
179+
* @param stringMatcher
180+
* @return
181+
* @see Builder#stringMatcher(StringMatcher)
182+
*/
102183
public Builder<T> with(StringMatcher stringMatcher) {
103184
return stringMatcher(stringMatcher);
104185
}
105186

106-
public Builder<T> with(PropertySpecifier specifier) {
107-
return specify(specifier);
187+
/**
188+
* Adds {@link PropertySpecifier} used for {@link Example}.
189+
*
190+
* @param specifier
191+
* @return
192+
* @see Builder#specify(PropertySpecifier...)
193+
*/
194+
public Builder<T> with(PropertySpecifier... specifiers) {
195+
return specify(specifiers);
108196
}
109197

110-
public Builder<T> nullHandling(NullHandling nullHandling) {
198+
/**
199+
* Sets {@link NullHandler} used for {@link Example}.
200+
*
201+
* @param nullHandling Defaulted to {@link NullHandler#INCLUDE} in case of {@literal null}.
202+
* @return
203+
*/
204+
public Builder<T> nullHandling(NullHandler nullHandling) {
111205

112-
example.nullHandling = nullHandling == null ? NullHandling.IGNORE_NULL : nullHandling;
206+
example.nullHandler = nullHandling == null ? NullHandler.IGNORE : nullHandling;
113207
return this;
114208
}
115209

210+
/**
211+
* Sets the default {@link StringMatcher} used for {@link Example}.
212+
*
213+
* @param stringMatcher Defaulted to {@link StringMatcher#DEFAULT} in case of {@literal null}.
214+
* @return
215+
*/
116216
public Builder<T> stringMatcher(StringMatcher stringMatcher) {
117-
118-
example.defaultStringMatcher = stringMatcher == null ? StringMatcher.DEFAULT : stringMatcher;
119-
return this;
217+
return stringMatcher(stringMatcher, example.ignoreCase);
120218
}
121219

220+
/**
221+
* Sets the default {@link StringMatcher} used for {@link Example}.
222+
*
223+
* @param stringMatcher Defaulted to {@link StringMatcher#DEFAULT} in case of {@literal null}.
224+
* @param ignoreCase
225+
* @return
226+
*/
122227
public Builder<T> stringMatcher(StringMatcher stringMatching, boolean ignoreCase) {
123228

124229
example.defaultStringMatcher = stringMatching == null ? StringMatcher.DEFAULT : stringMatching;
125230
example.ignoreCase = ignoreCase;
126231
return this;
127232
}
128233

234+
/**
235+
* @return
236+
*/
129237
public Builder<T> ignoreCase() {
130238
example.ignoreCase = true;
131239
return this;
132240
}
133241

242+
/**
243+
* Define specific property handling.
244+
*
245+
* @param specifiers
246+
* @return
247+
*/
134248
public Builder<T> specify(PropertySpecifier... specifiers) {
135249

136250
for (PropertySpecifier specifier : specifiers) {
137-
example.propertySpecifiers.put(specifier.getPath(), specifier);
251+
example.propertySpecifiers.add(specifier);
138252
}
139253
return this;
140254
}
141255

256+
/**
257+
* Ignore given properties.
258+
*
259+
* @param ignoredProperties
260+
* @return
261+
*/
142262
public Builder<T> ignore(String... ignoredProperties) {
143263

144264
for (String ignoredProperty : ignoredProperties) {
@@ -148,29 +268,26 @@ public Builder<T> ignore(String... ignoredProperties) {
148268
return this;
149269
}
150270

271+
/**
272+
* @return {@link Example} as defined.
273+
*/
151274
public Example<T> get() {
152275
return this.example;
153276
}
154277
}
155278

156279
/**
157-
* Match modes indicates inclusion of complex objects.
280+
* Null handling for creating criterion out of an {@link Example}.
158281
*
159282
* @author Christoph Strobl
160283
*/
161-
public static enum NullHandling {
162-
/**
163-
* Strict matching will use partially filled objects as reference.
164-
*/
165-
INCLUDE_NULL,
166-
/**
167-
* Lenient matching will inspected nested objects and extract path if needed.
168-
*/
169-
IGNORE_NULL
284+
public static enum NullHandler {
285+
286+
INCLUDE, IGNORE
170287
}
171288

172289
/**
173-
* Match modes indicates treatment of {@link String} values.
290+
* Match modes for treatment of {@link String} values.
174291
*
175292
* @author Christoph Strobl
176293
*/
@@ -179,35 +296,74 @@ public static enum StringMatcher {
179296
/**
180297
* Store specific default.
181298
*/
182-
DEFAULT,
299+
DEFAULT(null),
183300
/**
184301
* Matches the exact string
185302
*/
186-
EXACT,
303+
EXACT(Type.SIMPLE_PROPERTY),
187304
/**
188305
* Matches string starting with pattern
189306
*/
190-
STARTING,
307+
STARTING(Type.STARTING_WITH),
191308
/**
192309
* Matches string ending with pattern
193310
*/
194-
ENDING,
311+
ENDING(Type.ENDING_WITH),
195312
/**
196313
* Matches string containing pattern
197314
*/
198-
CONTAINING,
315+
CONTAINING(Type.CONTAINING),
199316
/**
200317
* Treats strings as regular expression patterns
201318
*/
202-
REGEX
319+
REGEX(Type.REGEX);
320+
321+
private Type type;
322+
323+
private StringMatcher(Type type) {
324+
this.type = type;
325+
}
326+
327+
/**
328+
* Get the according {@link Part.Type}.
329+
*
330+
* @return {@literal null} for {@link StringMatcher#DEFAULT}.
331+
*/
332+
public Type getPartType() {
333+
return type;
334+
}
335+
203336
}
204337

205338
public static class ExcludingValueTransformer implements PropertyValueTransformer {
206339

207340
@Override
208-
public Object tranform(Object source) {
341+
public Object convert(Object source) {
209342
return null;
210343
}
211344
}
212345

346+
static class PropertySpecifiers {
347+
348+
private Map<String, PropertySpecifier> propertySpecifiers = new LinkedHashMap<String, PropertySpecifier>();
349+
350+
public void add(PropertySpecifier specifier) {
351+
352+
Assert.notNull(specifier, "PropertySpecifier must not be null!");
353+
propertySpecifiers.put(specifier.getPath(), specifier);
354+
}
355+
356+
public boolean hasSpecifierForPath(String path) {
357+
return propertySpecifiers.containsKey(path);
358+
}
359+
360+
public PropertySpecifier getForPath(String path) {
361+
return propertySpecifiers.get(path);
362+
}
363+
364+
public boolean hasValues() {
365+
return !propertySpecifiers.isEmpty();
366+
}
367+
}
368+
213369
}

0 commit comments

Comments
 (0)