Skip to content

Commit 62427f4

Browse files
committed
Incorporate design review feedback.
1 parent 68efb78 commit 62427f4

21 files changed

+339
-366
lines changed

src/jmh/java/org/springframework/data/core/SerializableLambdaReaderBenchmarks.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@
2828
@Testable
2929
public class SerializableLambdaReaderBenchmarks extends BenchmarkSettings {
3030

31-
private static final SerializableLambdaReader reader = new SerializableLambdaReader(MemberReference.class);
31+
private static final SerializableLambdaReader reader = new SerializableLambdaReader(PropertyReference.class);
3232

3333
@Benchmark
3434
public Object benchmarkMethodReference() {
3535

36-
MemberReference<Person, String> methodReference = Person::firstName;
36+
PropertyReference<Person, String> methodReference = Person::firstName;
3737
return reader.read(methodReference);
3838
}
3939

4040
@Benchmark
4141
public Object benchmarkLambda() {
4242

43-
MemberReference<Person, String> methodReference = person -> person.firstName();
43+
PropertyReference<Person, String> methodReference = person -> person.firstName();
4444
return reader.read(methodReference);
4545
}
4646

src/jmh/java/org/springframework/data/core/TypedPropertyPathBenchmarks.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,32 @@ public class TypedPropertyPathBenchmarks extends BenchmarkSettings {
2929

3030
@Benchmark
3131
public Object benchmarkMethodReference() {
32-
return TypedPropertyPath.ofProperty(Person::firstName);
32+
return TypedPropertyPath.path(Person::firstName);
3333
}
3434

3535
@Benchmark
3636
public Object benchmarkComposedMethodReference() {
37-
return TypedPropertyPath.ofProperty(Person::address).then(Address::city);
37+
return TypedPropertyPath.path(Person::address).then(Address::city);
3838
}
3939

4040
@Benchmark
4141
public TypedPropertyPath<Person, String> benchmarkLambda() {
42-
return TypedPropertyPath.ofProperty(person -> person.firstName());
42+
return TypedPropertyPath.path(person -> person.firstName());
4343
}
4444

4545
@Benchmark
4646
public TypedPropertyPath<Person, String> benchmarkComposedLambda() {
47-
return TypedPropertyPath.ofProperty((Person person) -> person.address()).then(address -> address.city());
47+
return TypedPropertyPath.path((Person person) -> person.address()).then(address -> address.city());
4848
}
4949

5050
@Benchmark
5151
public Object dotPath() {
52-
return TypedPropertyPath.ofProperty(Person::firstName).toDotPath();
52+
return TypedPropertyPath.path(Person::firstName).toDotPath();
5353
}
5454

5555
@Benchmark
5656
public Object composedDotPath() {
57-
return TypedPropertyPath.ofProperty(Person::address).then(Address::city).toDotPath();
57+
return TypedPropertyPath.path(Person::address).then(Address::city).toDotPath();
5858
}
5959

6060
record Person(String firstName, String lastName, Address address) {

src/main/java/org/springframework/data/convert/PropertyValueConverterRegistrar.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.function.Function;
2121

2222
import org.springframework.data.convert.PropertyValueConverter.FunctionPropertyValueConverter;
23+
import org.springframework.data.core.PropertyReference;
2324
import org.springframework.data.mapping.PersistentProperty;
2425
import org.springframework.data.util.MethodInvocationRecorder;
2526
import org.springframework.lang.Contract;
@@ -50,11 +51,25 @@ public class PropertyValueConverterRegistrar<P extends PersistentProperty<P>> {
5051
*
5152
* @param <T> the domain type
5253
* @param <S> the property type
53-
* @param type the domain type to obtain the property from
5454
* @param property a {@link Function} to describe the property to be referenced.
5555
* Usually a method handle to a getter.
5656
* @return will never be {@literal null}.
5757
*/
58+
public <T, S> WritingConverterRegistrationBuilder<T, S, P> registerConverter(PropertyReference<T, S> property) {
59+
return new WritingConverterRegistrationBuilder<>(property.getOwningType().getType(), property.getName(), this);
60+
}
61+
62+
/**
63+
* Starts a converter registration by pointing to a property of a domain type.
64+
*
65+
* @param <T> the domain type
66+
* @param <S> the property type
67+
* @param type the domain type to obtain the property from
68+
* @param property a {@link Function} to describe the property to be referenced. Usually a method handle to a getter.
69+
* @return will never be {@literal null}.
70+
* @deprecated since 4.1, use {@link #registerConverter(PropertyReference)} instead.
71+
*/
72+
@Deprecated(since = "4.1")
5873
public <T, S> WritingConverterRegistrationBuilder<T, S, P> registerConverter(Class<T> type, Function<T, S> property) {
5974

6075
String propertyName = MethodInvocationRecorder.forProxyOf(type).record(property).getPropertyPath()

src/main/java/org/springframework/data/core/MemberReference.java

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/main/java/org/springframework/data/core/PropertyPath.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@
2424

2525
/**
2626
* Abstraction of a {@link PropertyPath} within a domain class.
27+
* <p>
28+
* Property paths allow to navigate nested properties such as {@code address.city.name} and provide metadata for each
29+
* segment of the path. Paths are represented in dot-path notation and are resolved from an owning type, for example:
30+
*
31+
* <pre class="code">
32+
* PropertyPath.from("address.city.name", Person.class);
33+
* </pre>
34+
*
35+
* Paths are cached on a best-effort basis using a weak reference cache to avoid repeated introspection if GC pressure
36+
* permits.
37+
* <p>
38+
* A typed variant of {@link PropertyPath} is available as {@link TypedPropertyPath} through
39+
* {@link #of(PropertyReference)} to leverage method references for a type-safe usage across application code.
2740
*
2841
* @author Oliver Gierke
2942
* @author Christoph Strobl
@@ -79,10 +92,10 @@ static <T, P> TypedPropertyPath<T, P> ofMany(PropertyReference<T, ? extends Iter
7992
* For example:
8093
*
8194
* <pre class="code">
82-
* PropertyPath.from("a.b.c", Some.class).getSegment();
95+
* PropertyPath.from("address.city.name", Person.class).getSegment();
8396
* </pre>
8497
*
85-
* results in {@code a}.
98+
* results in {@code address}.
8699
*
87100
* @return the current property path segment.
88101
*/
@@ -149,10 +162,10 @@ default boolean isCollection() {
149162
* Returns the next {@code PropertyPath} segment in the property path chain.
150163
*
151164
* <pre class="code">
152-
* PropertyPath.from("a.b.c", Some.class).next().toDotPath();
165+
* PropertyPath.from("address.city.name", Person.class).next().toDotPath();
153166
* </pre>
154167
*
155-
* results in the output: {@code b.c}
168+
* results in the output: {@code city.name}.
156169
*
157170
* @return the next {@code PropertyPath} or {@literal null} if the path does not contain further segments.
158171
* @see #hasNext()
@@ -201,16 +214,16 @@ default PropertyPath nested(String path) {
201214
* Returns an {@link Iterator Iterator of PropertyPath} that iterates over all property path segments. For example:
202215
*
203216
* <pre class="code">
204-
* PropertyPath propertyPath = PropertyPath.from("a.b.c", Some.class);
205-
* propertyPath.forEach(p -> p.toDotPath());
217+
* PropertyPath path = PropertyPath.from("address.city.name", Person.class);
218+
* path.forEach(p -> p.toDotPath());
206219
* </pre>
207220
*
208221
* results in the dot paths:
209222
*
210223
* <pre class="code">
211-
* a.b.c (this object)
212-
* b.c (next() object)
213-
* c (next().next() object)
224+
* address.city.name (this object)
225+
* city.name (next() object)
226+
* city.name (next().next() object)
214227
* </pre>
215228
*/
216229
@Override

src/main/java/org/springframework/data/core/PropertyReference.java

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@
2222
/**
2323
* Interface providing type-safe property references.
2424
* <p>
25-
* This functional interface is typically implemented through method references and lambda expressions that allow for
26-
* compile-time type safety and refactoring support. Instead of string-based property names that are easy to miss when
27-
* changing the domain model, {@code PropertyReference} leverages Java's declarative method references and lambda
28-
* expressions to ensure type-safe property access.
25+
* This functional interface is typically implemented through method references that allow for compile-time type safety
26+
* and refactoring support. Instead of string-based property names that are easy to miss when changing the domain model,
27+
* {@code PropertyReference} leverages Java's declarative method references to ensure type-safe property access.
2928
* <p>
30-
* Create a typed property reference using the static factory method {@link #of(PropertyReference)} with a method
31-
* reference or lambda, for example:
29+
* Create a typed property reference using the static factory method {@link #property(PropertyReference)} with a method
30+
* reference, for example:
3231
*
3332
* <pre class="code">
3433
* PropertyReference&lt;Person, String&gt; name = PropertyReference.of(Person::getName);
@@ -64,11 +63,25 @@
6463
public interface PropertyReference<T, P extends @Nullable Object> extends Serializable {
6564

6665
/**
67-
* Syntax sugar to create a {@link PropertyReference} from a method reference or lambda.
66+
* Syntax sugar to create a {@link PropertyReference} from a method reference. Suitable for static imports.
6867
* <p>
69-
* This method returns a resolved {@link PropertyReference} by introspecting the given method reference or lambda.
68+
* This method returns a resolved {@link PropertyReference} by introspecting the given method reference.
7069
*
71-
* @param property the method reference or lambda.
70+
* @param property the method reference.
71+
* @param <T> owning type.
72+
* @param <P> property type.
73+
* @return the typed property reference.
74+
*/
75+
static <T, P extends @Nullable Object> PropertyReference<T, P> property(PropertyReference<T, P> property) {
76+
return of(property);
77+
}
78+
79+
/**
80+
* Syntax sugar to create a {@link PropertyReference} from a method reference.
81+
* <p>
82+
* This method returns a resolved {@link PropertyReference} by introspecting the given method reference.
83+
*
84+
* @param property the method reference.
7285
* @param <T> owning type.
7386
* @param <P> property type.
7487
* @return the typed property reference.
@@ -80,11 +93,11 @@ public interface PropertyReference<T, P extends @Nullable Object> extends Serial
8093
/**
8194
* Syntax sugar to create a {@link PropertyReference} from a method reference or lambda for a collection property.
8295
* <p>
83-
* This method returns a resolved {@link PropertyReference} by introspecting the given method reference or lambda.
84-
* Note that {@link #get(Object)} becomes unusable for collection properties as the property type adapted from
96+
* This method returns a resolved {@link PropertyReference} by introspecting the given method reference. Note that
97+
* {@link #get(Object)} becomes unusable for collection properties as the property type adapted from
8598
* {@code Iterable &lt;P&gt;} and a single {@code P} cannot represent a collection of items.
8699
*
87-
* @param property the method reference or lambda.
100+
* @param property the method reference.
88101
* @param <T> owning type.
89102
* @param <P> property type.
90103
* @return the typed property reference.
@@ -104,11 +117,11 @@ static <T, P> PropertyReference<T, P> ofMany(PropertyReference<T, ? extends Iter
104117
P get(T obj);
105118

106119
/**
107-
* Returns the owning type of the referenced property..
120+
* Returns the owning type of the referenced property.
108121
*
109122
* @return the owningType will never be {@literal null}.
110123
*/
111-
default TypeInformation<?> getOwningType() {
124+
default TypeInformation<T> getOwningType() {
112125
return PropertyReferences.of(this).getOwningType();
113126
}
114127

0 commit comments

Comments
 (0)