Skip to content

Commit e9f27a9

Browse files
committed
Hacking.
1 parent 60685d8 commit e9f27a9

File tree

6 files changed

+528
-128
lines changed

6 files changed

+528
-128
lines changed

src/main/java/org/springframework/data/mapping/ComposedPropertyPath.java

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

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ public interface PropertyPath extends Streamable<PropertyPath> {
4545
* @since xxx
4646
*/
4747
public static <T, R> TypedPropertyPath<T, R> of(TypedPropertyPath<T, R> propertyPath) {
48-
PropertyPathExtractor.getPropertyPathInformation(propertyPath);
49-
return propertyPath;
48+
return TypedPropertyPath.of(propertyPath);
5049
}
5150

5251
/**

src/main/java/org/springframework/data/mapping/TypedPropertyPath.java

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,89 @@
2020
import java.util.Iterator;
2121

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

2625
/**
26+
* Type-safe representation of a property path expressed through method references.
27+
* <p>
28+
* This functional interface extends {@link PropertyPath} to provide compile-time type safety when declaring property
29+
* paths. Instead of using {@link PropertyPath#from(String, TypeInformation) string-based property paths} that represent
30+
* references to properties textually and that are prone to refactoring issues, {@code TypedPropertyPath} leverages
31+
* Java's declarative method references and lambda expressions to ensure type-safe property access.
32+
* <p>
33+
* Typed property paths can be created directly they are accepted used or conveniently using the static factory method
34+
* {@link #of(TypedPropertyPath)} with method references:
35+
*
36+
* <pre class="code">
37+
* PropertyPath.of(Person::getName);
38+
* </pre>
39+
*
40+
* Property paths can be composed to navigate nested properties using {@link #then(TypedPropertyPath)}:
41+
*
42+
* <pre class="code">
43+
* PropertyPath.of(Person::getAddress).then(Address::getCountry).then(Country::getName);
44+
* </pre>
45+
* <p>
46+
* The interface maintains type information throughout the property path chain: the {@code T} type parameter represents
47+
* its owning type (root type for composed paths), while {@code P} represents the property value type at this path
48+
* segment.
49+
* <p>
50+
* As a functional interface, {@code TypedPropertyPath} should be implemented as method reference (recommended).
51+
* Alternatively, the interface can be implemented as lambda extracting a property value from an object of type
52+
* {@code T}. Implementations must ensure that the method reference or lambda correctly represents a property access
53+
* through a method invocation or by field access. Arbitrary calls to non-getter methods (i.e. methods accepting
54+
* parameters or arbitrary method calls on types other than the owning type are not allowed and will fail with
55+
* {@link org.springframework.dao.InvalidDataAccessApiUsageException}.
56+
* <p>
57+
* Note that using lambda expressions requires bytecode analysis of the declaration site classes and therefore presence
58+
* of their class files.
59+
*
60+
* @param <T> the owning type of the property path segment, but typically the root type for composed property paths.
61+
* @param <P> the property value type at this path segment.
2762
* @author Mark Paluch
63+
* @see PropertyPath
64+
* @see #of(TypedPropertyPath)
65+
* @see #then(TypedPropertyPath)
2866
*/
2967
@FunctionalInterface
30-
public interface TypedPropertyPath<T, R> extends Serializable, PropertyPath {
68+
public interface TypedPropertyPath<T, P> extends PropertyPath, Serializable {
3169

32-
R get(T obj);
70+
/**
71+
* Syntax sugar to create a {@link TypedPropertyPath} from a method reference or lambda.
72+
* <p>
73+
* This method returns a resolved {@link TypedPropertyPath} by introspecting the given lambda.
74+
*
75+
* @param lambda the method reference or lambda.
76+
* @param <T> owning type.
77+
* @param <P> property type.
78+
* @return the typed property path.
79+
*/
80+
static <T, P> TypedPropertyPath<T, P> of(TypedPropertyPath<T, P> lambda) {
81+
return TypedPropertyPaths.of(lambda);
82+
}
83+
84+
/**
85+
* Get the property value for the given object.
86+
*
87+
* @param obj the object to get the property value from.
88+
* @return the property value.
89+
*/
90+
@Nullable
91+
P get(T obj);
3392

3493
@Override
3594
default TypeInformation<?> getOwningType() {
36-
return PropertyPathExtractor.getPropertyPathInformation(this).owner();
95+
return TypedPropertyPaths.getPropertyPathInformation(this).owner();
3796
}
3897

3998
@Override
4099
default String getSegment() {
41-
return PropertyPathExtractor.getPropertyPathInformation(this).property().getName();
100+
return TypedPropertyPaths.getPropertyPathInformation(this).property().getName();
42101
}
43102

44103
@Override
45104
default TypeInformation<?> getTypeInformation() {
46-
return PropertyPathExtractor.getPropertyPathInformation(this).propertyType();
105+
return TypedPropertyPaths.getPropertyPathInformation(this).propertyType();
47106
}
48107

49108
@Override
@@ -62,8 +121,14 @@ default Iterator<PropertyPath> iterator() {
62121
return Collections.singletonList((PropertyPath) this).iterator();
63122
}
64123

65-
default <N> TypedPropertyPath<T, N> then(TypedPropertyPath<R, N> next) {
66-
return new ComposedPropertyPath<>(this, next);
124+
/**
125+
* Extend the property path by appending the {@code next} path segment and returning a new property path instance..
126+
*
127+
* @param next the next property path segment accepting a property path owned by the {@code P} type.
128+
* @param <N> the new property value type.
129+
* @return a new composed {@code TypedPropertyPath}.
130+
*/
131+
default <N> TypedPropertyPath<T, N> then(TypedPropertyPath<P, N> next) {
132+
return TypedPropertyPaths.compose(this, of(next));
67133
}
68-
69134
}

0 commit comments

Comments
 (0)