Skip to content

Commit 31cf501

Browse files
committed
Retrofit ExampleMatcher with TypedPropertyPath.
1 parent fa1cf89 commit 31cf501

File tree

7 files changed

+151
-20
lines changed

7 files changed

+151
-20
lines changed

src/main/java/org/springframework/data/mapping/TypedPropertyPath.java renamed to src/main/java/org/springframework/data/core/TypedPropertyPath.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.springframework.data.mapping;
16+
package org.springframework.data.core;
1717

1818
import java.io.Serializable;
1919
import java.util.Collections;
2020
import java.util.Iterator;
2121

2222
import org.jspecify.annotations.Nullable;
23-
import org.springframework.data.util.TypeInformation;
2423

2524
/**
2625
* Type-safe representation of a property path expressed through method references.
@@ -32,13 +31,13 @@
3231
* <p>
3332
* Typed property paths can be created directly they are accepted used or conveniently using the static factory method
3433
* {@link #of(TypedPropertyPath)} with method references:
35-
*
34+
*
3635
* <pre class="code">
3736
* PropertyPath.of(Person::getName);
3837
* </pre>
39-
*
38+
*
4039
* Property paths can be composed to navigate nested properties using {@link #then(TypedPropertyPath)}:
41-
*
40+
*
4241
* <pre class="code">
4342
* PropertyPath.of(Person::getAddress).then(Address::getCountry).then(Country::getName);
4443
* </pre>
@@ -56,7 +55,7 @@
5655
* <p>
5756
* Note that using lambda expressions requires bytecode analysis of the declaration site classes and therefore presence
5857
* of their class files.
59-
*
58+
*
6059
* @param <T> the owning type of the property path segment, but typically the root type for composed property paths.
6160
* @param <P> the property value type at this path segment.
6261
* @author Mark Paluch

src/main/java/org/springframework/data/mapping/TypedPropertyPaths.java renamed to src/main/java/org/springframework/data/core/TypedPropertyPaths.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.springframework.data.mapping;
16+
package org.springframework.data.core;
1717

1818
import java.beans.Introspector;
1919
import java.beans.PropertyDescriptor;
@@ -46,8 +46,6 @@
4646
import org.springframework.beans.BeanUtils;
4747
import org.springframework.core.ResolvableType;
4848
import org.springframework.dao.InvalidDataAccessApiUsageException;
49-
import org.springframework.data.mapping.model.Property;
50-
import org.springframework.data.util.TypeInformation;
5149
import org.springframework.util.ClassUtils;
5250
import org.springframework.util.ConcurrentReferenceHashMap;
5351
import org.springframework.util.ObjectUtils;
@@ -59,7 +57,7 @@
5957
class TypedPropertyPaths {
6058

6159
private static final Map<ClassLoader, Map<Object, PropertyPathInformation>> lambdas = new WeakHashMap<>();
62-
private static final Map<ClassLoader, Map<TypedPropertyPath, ResolvedTypedPropertyPath<?, ?>>> resolved = new WeakHashMap<>();
60+
private static final Map<ClassLoader, Map<TypedPropertyPath<?, ?>, ResolvedTypedPropertyPath<?, ?>>> resolved = new WeakHashMap<>();
6361

6462
/**
6563
* Retrieve {@link PropertyPathInformation} for a given {@link TypedPropertyPath}.
@@ -92,7 +90,7 @@ public static <P, T> TypedPropertyPath<T, P> of(TypedPropertyPath<T, P> lambda)
9290
return lambda;
9391
}
9492

95-
Map<TypedPropertyPath, ResolvedTypedPropertyPath<?, ?>> cache;
93+
Map<TypedPropertyPath<?, ?>, ResolvedTypedPropertyPath<?, ?>> cache;
9694
synchronized (resolved) {
9795
cache = resolved.computeIfAbsent(lambda.getClass().getClassLoader(), k -> new ConcurrentReferenceHashMap<>());
9896
}
@@ -168,7 +166,7 @@ public static PropertyPathInformation ofFieldAccess(Class<?> owner, String field
168166

169167
Field field = ReflectionUtils.findField(owner, fieldName, fieldType);
170168
if (field == null) {
171-
throw new IllegalArgumentException("Field %s.%s() not found".formatted(owner.getName(), field));
169+
throw new IllegalArgumentException("Field %s.%s() not found".formatted(owner.getName(), fieldName));
172170
}
173171

174172
return new PropertyPathInformation(TypeInformation.of(owner),

src/main/java/org/springframework/data/domain/ExampleMatcher.java

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

18+
import java.util.Arrays;
1819
import java.util.Collection;
1920
import java.util.LinkedHashMap;
2021
import java.util.Map;
@@ -24,6 +25,7 @@
2425

2526
import org.jspecify.annotations.Nullable;
2627

28+
import org.springframework.data.core.TypedPropertyPath;
2729
import org.springframework.lang.CheckReturnValue;
2830
import org.springframework.lang.Contract;
2931
import org.springframework.util.Assert;
@@ -77,6 +79,21 @@ static ExampleMatcher matchingAll() {
7779
return new TypedExampleMatcher().withMode(MatchMode.ALL);
7880
}
7981

82+
/**
83+
* Returns a copy of this {@link ExampleMatcher} with the specified {@code propertyPaths}. This instance is immutable
84+
* and unaffected by this method call.
85+
*
86+
* @param ignoredPaths must not be {@literal null} and not empty.
87+
* @return new instance of {@link ExampleMatcher}.
88+
* @since 4.1
89+
*/
90+
@Contract("_ -> new")
91+
@CheckReturnValue
92+
default <T> ExampleMatcher withIgnorePaths(TypedPropertyPath<T, ?>... ignoredPaths) {
93+
return withIgnorePaths(Arrays.stream(ignoredPaths).map(TypedPropertyPath::of).map(TypedPropertyPath::toDotPath)
94+
.toArray(String[]::new));
95+
}
96+
8097
/**
8198
* Returns a copy of this {@link ExampleMatcher} with the specified {@code propertyPaths}. This instance is immutable
8299
* and unaffected by this method call.
@@ -122,6 +139,22 @@ default ExampleMatcher withIgnoreCase() {
122139
@CheckReturnValue
123140
ExampleMatcher withIgnoreCase(boolean defaultIgnoreCase);
124141

142+
/**
143+
* Returns a copy of this {@link ExampleMatcher} with the specified {@code GenericPropertyMatcher} for the
144+
* {@code propertyPath}. This instance is immutable and unaffected by this method call.
145+
*
146+
* @param propertyPath must not be {@literal null}.
147+
* @param matcherConfigurer callback to configure a {@link GenericPropertyMatcher}, must not be {@literal null}.
148+
* @return new instance of {@link ExampleMatcher}.
149+
* @since 4.1
150+
*/
151+
@Contract("_, _ -> new")
152+
@CheckReturnValue
153+
default <T, P> ExampleMatcher withMatcher(TypedPropertyPath<T, P> propertyPath,
154+
MatcherConfigurer<GenericPropertyMatcher> matcherConfigurer) {
155+
return withMatcher(propertyPath.toDotPath(), matcherConfigurer);
156+
}
157+
125158
/**
126159
* Returns a copy of this {@link ExampleMatcher} with the specified {@code GenericPropertyMatcher} for the
127160
* {@code propertyPath}. This instance is immutable and unaffected by this method call.
@@ -143,6 +176,21 @@ default ExampleMatcher withMatcher(String propertyPath, MatcherConfigurer<Generi
143176
return withMatcher(propertyPath, genericPropertyMatcher);
144177
}
145178

179+
/**
180+
* Returns a copy of this {@link ExampleMatcher} with the specified {@code GenericPropertyMatcher} for the
181+
* {@code propertyPath}. This instance is immutable and unaffected by this method call.
182+
*
183+
* @param propertyPath must not be {@literal null}.
184+
* @param genericPropertyMatcher callback to configure a {@link GenericPropertyMatcher}, must not be {@literal null}.
185+
* @return new instance of {@link ExampleMatcher}.
186+
*/
187+
@Contract("_, _ -> new")
188+
@CheckReturnValue
189+
default <T, P> ExampleMatcher withMatcher(TypedPropertyPath<T, P> propertyPath,
190+
GenericPropertyMatcher genericPropertyMatcher) {
191+
return withMatcher(propertyPath.toDotPath(), genericPropertyMatcher);
192+
}
193+
146194
/**
147195
* Returns a copy of this {@link ExampleMatcher} with the specified {@code GenericPropertyMatcher} for the
148196
* {@code propertyPath}. This instance is immutable and unaffected by this method call.
@@ -155,6 +203,22 @@ default ExampleMatcher withMatcher(String propertyPath, MatcherConfigurer<Generi
155203
@CheckReturnValue
156204
ExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher);
157205

206+
/**
207+
* Returns a copy of this {@link ExampleMatcher} with the specified {@code PropertyValueTransformer} for the
208+
* {@code propertyPath}.
209+
*
210+
* @param propertyPath must not be {@literal null}.
211+
* @param propertyValueTransformer must not be {@literal null}.
212+
* @return new instance of {@link ExampleMatcher}.
213+
* @since 4.1
214+
*/
215+
@Contract("_, _ -> new")
216+
@CheckReturnValue
217+
default <T, P> ExampleMatcher withTransformer(TypedPropertyPath<T, P> propertyPath,
218+
PropertyValueTransformer propertyValueTransformer) {
219+
return withTransformer(propertyPath.toDotPath(), propertyValueTransformer);
220+
}
221+
158222
/**
159223
* Returns a copy of this {@link ExampleMatcher} with the specified {@code PropertyValueTransformer} for the
160224
* {@code propertyPath}.
@@ -167,6 +231,20 @@ default ExampleMatcher withMatcher(String propertyPath, MatcherConfigurer<Generi
167231
@CheckReturnValue
168232
ExampleMatcher withTransformer(String propertyPath, PropertyValueTransformer propertyValueTransformer);
169233

234+
/**
235+
* Returns a copy of this {@link ExampleMatcher} with ignore case sensitivity for the {@code propertyPaths}. This
236+
* instance is immutable and unaffected by this method call.
237+
*
238+
* @param propertyPaths must not be {@literal null} and not empty.
239+
* @return new instance of {@link ExampleMatcher}.
240+
*/
241+
@Contract("_ -> new")
242+
@CheckReturnValue
243+
default <T> ExampleMatcher withIgnoreCase(TypedPropertyPath<T, ?>... propertyPaths) {
244+
return withIgnoreCase(Arrays.stream(propertyPaths).map(TypedPropertyPath::of).map(TypedPropertyPath::toDotPath)
245+
.toArray(String[]::new));
246+
}
247+
170248
/**
171249
* Returns a copy of this {@link ExampleMatcher} with ignore case sensitivity for the {@code propertyPaths}. This
172250
* instance is immutable and unaffected by this method call.

src/main/java/org/springframework/data/domain/Sort.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@
2929

3030
import org.jspecify.annotations.Nullable;
3131

32+
import org.springframework.data.core.PropertyPath;
33+
import org.springframework.data.core.TypedPropertyPath;
3234
import org.springframework.data.util.MethodInvocationRecorder;
3335
import org.springframework.data.util.MethodInvocationRecorder.Recorded;
34-
import org.springframework.data.util.PropertyPath;
3536
import org.springframework.data.util.Streamable;
36-
import org.springframework.data.util.TypedPropertyPath;
3737
import org.springframework.lang.CheckReturnValue;
3838
import org.springframework.lang.Contract;
3939
import org.springframework.util.Assert;
@@ -797,7 +797,7 @@ public String toString() {
797797
* @author Oliver Gierke
798798
* @since 2.2
799799
* @soundtrack The Intersphere - Linger (The Grand Delusion)
800-
* @deprecated since 4.1 in favor of {@link Sort#by(org.springframework.data.util.TypedPropertyPath...)}
800+
* @deprecated since 4.1 in favor of {@link Sort#by(org.springframework.data.core.TypedPropertyPath...)}
801801
*/
802802
@Deprecated(since = "4.1")
803803
public static class TypedSort<T> extends Sort {

src/test/java/org/springframework/data/mapping/TypedPropertyPathUnitTests.java renamed to src/test/java/org/springframework/data/core/TypedPropertyPathUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.springframework.data.mapping;
16+
package org.springframework.data.core;
1717

1818
import static org.assertj.core.api.Assertions.*;
1919

src/test/java/org/springframework/data/domain/ExampleMatcherUnitTests.java

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,15 @@ void ignoredPathsShouldReturnUniqueProperties() {
121121
assertThat(matcher.getIgnoredPaths()).hasSize(2);
122122
}
123123

124+
@Test //
125+
void ignoredPropertyPathsShouldReturnUniqueProperties() {
126+
127+
matcher = matching().withIgnorePaths(Person::getFirstname, Person::getLastname, Person::getFirstname);
128+
129+
assertThat(matcher.getIgnoredPaths()).contains("firstname", "lastname");
130+
assertThat(matcher.getIgnoredPaths()).hasSize(2);
131+
}
132+
124133
@Test // DATACMNS-810
125134
void withCreatesNewInstance() {
126135

@@ -160,11 +169,11 @@ void anyMatcherYieldsAnyMatching() {
160169
void shouldCompareUsingHashCodeAndEquals() {
161170

162171
matcher = matching() //
163-
.withIgnorePaths("foo", "bar", "baz") //
172+
.withIgnorePaths(Random::getFoo, Random::getBar, Random::getBaz) //
164173
.withNullHandler(NullHandler.IGNORE) //
165174
.withIgnoreCase("ignored-case") //
166-
.withMatcher("hello", GenericPropertyMatchers.contains().caseSensitive()) //
167-
.withMatcher("world", GenericPropertyMatcher::endsWith);
175+
.withMatcher(Random::getHello, GenericPropertyMatchers.contains().caseSensitive()) //
176+
.withMatcher(Random::getWorld, GenericPropertyMatcher::endsWith);
168177

169178
var sameAsMatcher = matching() //
170179
.withIgnorePaths("foo", "bar", "baz") //
@@ -182,8 +191,54 @@ void shouldCompareUsingHashCodeAndEquals() {
182191
assertThat(matcher).isEqualTo(sameAsMatcher).isNotEqualTo(different);
183192
}
184193

194+
static class Random {
195+
196+
String foo;
197+
String bar;
198+
String baz;
199+
String hello;
200+
String world;
201+
202+
public String getFoo() {
203+
return foo;
204+
}
205+
206+
public String getBar() {
207+
return bar;
208+
}
209+
210+
public String getBaz() {
211+
return baz;
212+
}
213+
214+
public String getHello() {
215+
return hello;
216+
}
217+
218+
public String getWorld() {
219+
return world;
220+
}
221+
}
222+
185223
static class Person {
186224

187225
String firstname;
226+
String lastname;
227+
228+
public String getFirstname() {
229+
return firstname;
230+
}
231+
232+
public void setFirstname(String firstname) {
233+
this.firstname = firstname;
234+
}
235+
236+
public String getLastname() {
237+
return lastname;
238+
}
239+
240+
public void setLastname(String lastname) {
241+
this.lastname = lastname;
242+
}
188243
}
189244
}

src/test/java/org/springframework/data/domain/SortUnitTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
import java.util.Collection;
2222

2323
import org.junit.jupiter.api.Test;
24+
25+
import org.springframework.data.core.TypedPropertyPath;
2426
import org.springframework.data.domain.Sort.Direction;
2527
import org.springframework.data.domain.Sort.Order;
2628
import org.springframework.data.geo.Circle;
2729
import org.springframework.data.mapping.Person;
28-
import org.springframework.data.util.TypedPropertyPath;
2930

3031
/**
3132
* Unit test for {@link Sort}.

0 commit comments

Comments
 (0)