Skip to content

Commit 0997610

Browse files
DATAMONGO-1245 - QBE enhancements for specific property handling.
Rename methods on Example and introduce PropertySpecifiers. Move mapping to separate class.
1 parent 12f5ad8 commit 0997610

File tree

8 files changed

+927
-361
lines changed

8 files changed

+927
-361
lines changed

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

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.springframework.data.domain;
1717

18+
import java.util.LinkedHashMap;
19+
import java.util.Map;
20+
1821
import org.springframework.util.Assert;
1922
import org.springframework.util.ClassUtils;
2023

@@ -25,9 +28,13 @@
2528
public class Example<T> {
2629

2730
private final T probe;
28-
private ObjectMatchMode objectMatchMode = ObjectMatchMode.LENIENT;
29-
private StringMatchMode stringMatchMode = StringMatchMode.DEFAULT;
30-
private boolean ignoreCaseEnabled = false;
31+
32+
private NullHandling nullHandling = NullHandling.IGNORE_NULL;
33+
private StringMatcher defaultStringMatcher = StringMatcher.DEFAULT;
34+
35+
private boolean ignoreCase = false;
36+
37+
private Map<String, PropertySpecifier> propertySpecifiers = new LinkedHashMap<String, PropertySpecifier>();
3138

3239
public <S extends T> Example(S probe) {
3340

@@ -39,51 +46,105 @@ public T getProbe() {
3946
return probe;
4047
}
4148

42-
public ObjectMatchMode getObjectMatchMode() {
43-
return objectMatchMode;
49+
public NullHandling getNullHandling() {
50+
return nullHandling;
4451
}
4552

46-
public StringMatchMode getStringMatchMode() {
47-
return stringMatchMode;
53+
public StringMatcher getDefaultStringMatcher() {
54+
return defaultStringMatcher;
4855
}
4956

5057
public boolean isIngnoreCaseEnabled() {
51-
return this.ignoreCaseEnabled;
58+
return this.ignoreCase;
59+
}
60+
61+
public boolean hasPropertySpecifier(String path) {
62+
return propertySpecifiers.containsKey(path);
63+
}
64+
65+
public PropertySpecifier getPropertySpecifier(String propertyPath) {
66+
return this.propertySpecifiers.get(propertyPath);
67+
}
68+
69+
public boolean hasPropertySpecifiers() {
70+
return !this.propertySpecifiers.isEmpty();
5271
}
5372

5473
@SuppressWarnings("unchecked")
5574
public Class<? extends T> getProbeType() {
5675
return (Class<? extends T>) ClassUtils.getUserClass(probe.getClass());
5776
}
5877

59-
public static <S extends T, T> Example<T> example(S probe) {
78+
public static <S extends T, T> Example<T> exampleOf(S probe) {
6079
return new Example<T>(probe);
6180
}
6281

63-
public static class ExampleBuilder<T> {
82+
public static <S extends T, T> Example<T> exampleOf(S probe, String... ignoredProperties) {
83+
return new Builder<T>(probe).ignore(ignoredProperties).get();
84+
}
85+
86+
public static <S extends T, T> Builder<S> newExampleOf(S probe) {
87+
return new Builder<S>(probe);
88+
}
89+
90+
public static class Builder<T> {
6491

6592
private Example<T> example;
6693

67-
public ExampleBuilder(T probe) {
94+
Builder(T probe) {
6895
example = new Example<T>(probe);
6996
}
7097

71-
public ExampleBuilder<T> objectMatchMode(ObjectMatchMode matchMode) {
98+
public Builder<T> with(NullHandling nullHandling) {
99+
return nullHandling(nullHandling);
100+
}
101+
102+
public Builder<T> with(StringMatcher stringMatcher) {
103+
return stringMatcher(stringMatcher);
104+
}
105+
106+
public Builder<T> with(PropertySpecifier specifier) {
107+
return specify(specifier);
108+
}
109+
110+
public Builder<T> nullHandling(NullHandling nullHandling) {
72111

73-
example.objectMatchMode = matchMode == null ? ObjectMatchMode.LENIENT : matchMode;
112+
example.nullHandling = nullHandling == null ? NullHandling.IGNORE_NULL : nullHandling;
74113
return this;
75114
}
76115

77-
public ExampleBuilder<T> stringMatchMode(StringMatchMode matchMode) {
116+
public Builder<T> stringMatcher(StringMatcher stringMatcher) {
78117

79-
example.stringMatchMode = matchMode == null ? StringMatchMode.DEFAULT : matchMode;
118+
example.defaultStringMatcher = stringMatcher == null ? StringMatcher.DEFAULT : stringMatcher;
80119
return this;
81120
}
82121

83-
public ExampleBuilder<T> stringMatchMode(StringMatchMode matchMode, boolean ignoreCase) {
122+
public Builder<T> stringMatcher(StringMatcher stringMatching, boolean ignoreCase) {
84123

85-
example.stringMatchMode = matchMode == null ? StringMatchMode.DEFAULT : matchMode;
86-
example.ignoreCaseEnabled = ignoreCase;
124+
example.defaultStringMatcher = stringMatching == null ? StringMatcher.DEFAULT : stringMatching;
125+
example.ignoreCase = ignoreCase;
126+
return this;
127+
}
128+
129+
public Builder<T> ignoreCase() {
130+
example.ignoreCase = true;
131+
return this;
132+
}
133+
134+
public Builder<T> specify(PropertySpecifier... specifiers) {
135+
136+
for (PropertySpecifier specifier : specifiers) {
137+
example.propertySpecifiers.put(specifier.getPath(), specifier);
138+
}
139+
return this;
140+
}
141+
142+
public Builder<T> ignore(String... ignoredProperties) {
143+
144+
for (String ignoredProperty : ignoredProperties) {
145+
specify(PropertySpecifier.newPropertySpecifier(ignoredProperty)
146+
.valueTransformer(new ExcludingValueTransformer()).get());
147+
}
87148
return this;
88149
}
89150

@@ -97,23 +158,23 @@ public Example<T> get() {
97158
*
98159
* @author Christoph Strobl
99160
*/
100-
public static enum ObjectMatchMode {
161+
public static enum NullHandling {
101162
/**
102163
* Strict matching will use partially filled objects as reference.
103164
*/
104-
STRICT,
165+
INCLUDE_NULL,
105166
/**
106167
* Lenient matching will inspected nested objects and extract path if needed.
107168
*/
108-
LENIENT
169+
IGNORE_NULL
109170
}
110171

111172
/**
112173
* Match modes indicates treatment of {@link String} values.
113174
*
114175
* @author Christoph Strobl
115176
*/
116-
public static enum StringMatchMode {
177+
public static enum StringMatcher {
117178

118179
/**
119180
* Store specific default.
@@ -141,9 +202,12 @@ public static enum StringMatchMode {
141202
REGEX
142203
}
143204

144-
// TODO: add default null handling
145-
// TODO: add default String handling
146-
// TODO: add per field null handling
147-
// TODO: add per field String handling
205+
public static class ExcludingValueTransformer implements PropertyValueTransformer {
206+
207+
@Override
208+
public Object tranform(Object source) {
209+
return null;
210+
}
211+
}
148212

149213
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright 2015 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 org.springframework.data.domain;
17+
18+
import org.springframework.data.domain.Example.StringMatcher;
19+
import org.springframework.util.Assert;
20+
21+
/**
22+
* @author Christoph Strobl
23+
*/
24+
public class PropertySpecifier {
25+
26+
private PropertyValueTransformer valueTransformer;
27+
private StringMatcher stringMatcher = StringMatcher.DEFAULT;
28+
private boolean ignoreCase = false;
29+
private final String path;
30+
31+
PropertySpecifier(String path) {
32+
33+
Assert.hasText(path, "Path must not be null/empty!");
34+
this.path = path;
35+
}
36+
37+
public StringMatcher getStringMatcher() {
38+
return this.stringMatcher == null ? StringMatcher.DEFAULT : stringMatcher;
39+
}
40+
41+
public boolean isIgnoreCaseEnabled() {
42+
return ignoreCase;
43+
}
44+
45+
public PropertyValueTransformer getPropertyValueTransformer() {
46+
return valueTransformer == null ? NoOpPropertyValueTransformer.INSTANCE : valueTransformer;
47+
}
48+
49+
public String getPath() {
50+
return path;
51+
}
52+
53+
public Object transformValue(Object source) {
54+
return getPropertyValueTransformer().tranform(source);
55+
}
56+
57+
public static PropertySpecifier ignoreCase(String propertyPath) {
58+
return new Builder(propertyPath).ignoreCase().get();
59+
}
60+
61+
public static Builder newPropertySpecifier(String propertyPath) {
62+
return new Builder(propertyPath);
63+
}
64+
65+
public static class Builder {
66+
67+
private PropertySpecifier specifier;
68+
69+
Builder(String path) {
70+
specifier = new PropertySpecifier(path);
71+
}
72+
73+
public Builder with(StringMatcher stringMatcher) {
74+
return stringMatcher(stringMatcher);
75+
}
76+
77+
public Builder with(PropertyValueTransformer valueTransformer) {
78+
return valueTransformer(valueTransformer);
79+
}
80+
81+
public Builder stringMatcher(StringMatcher stringMatcher) {
82+
specifier.stringMatcher = stringMatcher;
83+
return this;
84+
}
85+
86+
public Builder ignoreCase() {
87+
specifier.ignoreCase = true;
88+
return this;
89+
}
90+
91+
public Builder valueTransformer(PropertyValueTransformer valueTransformer) {
92+
specifier.valueTransformer = valueTransformer;
93+
return this;
94+
}
95+
96+
public PropertySpecifier get() {
97+
return this.specifier;
98+
}
99+
}
100+
101+
static enum NoOpPropertyValueTransformer implements PropertyValueTransformer {
102+
103+
INSTANCE;
104+
105+
@Override
106+
public Object tranform(Object source) {
107+
return source;
108+
}
109+
110+
}
111+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2015 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 org.springframework.data.domain;
17+
18+
/**
19+
* @author Christoph Strobl
20+
*/
21+
public interface PropertyValueTransformer {
22+
Object tranform(Object souce);
23+
}

0 commit comments

Comments
 (0)