Skip to content

Commit 46add89

Browse files
committed
Move PropertyPath to data.util.
1 parent e9f27a9 commit 46add89

26 files changed

+429
-350
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.Optional;
1919
import java.util.function.Predicate;
2020

21+
import org.springframework.data.util.PropertyPath;
2122
import org.springframework.data.util.Streamable;
2223

2324
/**

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

Lines changed: 4 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -15,213 +15,17 @@
1515
*/
1616
package org.springframework.data.mapping;
1717

18-
import java.util.Iterator;
19-
import java.util.regex.Pattern;
20-
21-
import org.jspecify.annotations.Nullable;
22-
23-
import org.springframework.data.util.Streamable;
24-
import org.springframework.data.util.TypeInformation;
25-
import org.springframework.util.Assert;
26-
2718
/**
28-
* Abstraction of a {@link PropertyPath} within a domain class.
19+
* Abstraction of a {@code PropertyPath} within a domain class.
2920
*
3021
* @author Oliver Gierke
3122
* @author Christoph Strobl
3223
* @author Mark Paluch
3324
* @author Mariusz Mączkowski
3425
* @author Johannes Englmeier
26+
* @deprecated since 4.1, use its replacement that moved to {@code org.springframework.data.util} package.
3527
*/
36-
public interface PropertyPath extends Streamable<PropertyPath> {
37-
38-
/**
39-
* Syntax sugar to create a {@link TypedPropertyPath} from an existing one, ideal for method handles.
40-
*
41-
* @param propertyPath
42-
* @return
43-
* @param <T> owning type.
44-
* @param <R> property type.
45-
* @since xxx
46-
*/
47-
public static <T, R> TypedPropertyPath<T, R> of(TypedPropertyPath<T, R> propertyPath) {
48-
return TypedPropertyPath.of(propertyPath);
49-
}
50-
51-
/**
52-
* Returns the owning type of the {@link PropertyPath}.
53-
*
54-
* @return the owningType will never be {@literal null}.
55-
*/
56-
TypeInformation<?> getOwningType();
57-
58-
/**
59-
* Returns the first part of the {@link PropertyPath}. For example:
60-
*
61-
* <pre class="code">
62-
* PropertyPath.from("a.b.c", Some.class).getSegment();
63-
* </pre>
64-
*
65-
* results in {@code a}.
66-
*
67-
* @return the name will never be {@literal null}.
68-
*/
69-
String getSegment();
70-
71-
/**
72-
* Returns the leaf property of the {@link PropertyPath}.
73-
*
74-
* @return will never be {@literal null}.
75-
*/
76-
default PropertyPath getLeafProperty() {
77-
78-
PropertyPath result = this;
79-
80-
while (result != null && result.hasNext()) {
81-
result = result.next();
82-
}
83-
84-
return result == null ? this : result;
85-
}
86-
87-
/**
88-
* Returns the type of the leaf property of the current {@link PropertyPath}.
89-
*
90-
* @return will never be {@literal null}.
91-
*/
92-
default Class<?> getLeafType() {
93-
return getLeafProperty().getType();
94-
}
95-
96-
/**
97-
* Returns the actual type of the property. Will return the plain resolved type for simple properties, the component
98-
* type for any {@link Iterable} or the value type of a {@link java.util.Map}.
99-
*
100-
* @return the actual type of the property.
101-
*/
102-
default Class<?> getType() {
103-
return getTypeInformation().getRequiredActualType().getType();
104-
}
105-
106-
/**
107-
* Returns the type information of the property.
108-
*
109-
* @return the actual type of the property.
110-
*/
111-
TypeInformation<?> getTypeInformation();
112-
113-
/**
114-
* Returns the {@link PropertyPath} path that results from removing the first element of the current one. For example:
115-
*
116-
* <pre class="code">
117-
* PropertyPath.from("a.b.c", Some.class).next().toDotPath();
118-
* </pre>
119-
*
120-
* results in the output: {@code b.c}
121-
*
122-
* @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available.
123-
* @see #hasNext()
124-
*/
125-
@Nullable
126-
PropertyPath next();
127-
128-
/**
129-
* Returns whether there is a nested {@link PropertyPath}. If this returns {@literal true} you can expect
130-
* {@link #next()} to return a non- {@literal null} value.
131-
*
132-
* @return
133-
*/
134-
default boolean hasNext() {
135-
return next() != null;
136-
}
137-
138-
/**
139-
* Returns the {@link PropertyPath} in dot notation.
140-
*
141-
* @return the {@link PropertyPath} in dot notation.
142-
*/
143-
default String toDotPath() {
144-
145-
PropertyPath next = next();
146-
return next != null ? getSegment() + "." + next.toDotPath() : getSegment();
147-
}
148-
149-
/**
150-
* Returns whether the {@link PropertyPath} is actually a collection.
151-
*
152-
* @return {@literal true} whether the {@link PropertyPath} is actually a collection.
153-
*/
154-
default boolean isCollection() {
155-
return getTypeInformation().isCollectionLike();
156-
}
157-
158-
/**
159-
* Returns the {@link PropertyPath} for the path nested under the current property.
160-
*
161-
* @param path must not be {@literal null} or empty.
162-
* @return will never be {@literal null}.
163-
*/
164-
default PropertyPath nested(String path) {
165-
166-
Assert.hasText(path, "Path must not be null or empty");
167-
168-
String lookup = toDotPath().concat(".").concat(path);
169-
170-
return SimplePropertyPath.from(lookup, getOwningType());
171-
}
172-
173-
/**
174-
* Returns an {@link Iterator Iterator of PropertyPath} that iterates over all the partial property paths with the
175-
* same leaf type but decreasing length. For example:
176-
*
177-
* <pre class="code">
178-
* PropertyPath propertyPath = PropertyPath.from("a.b.c", Some.class);
179-
* propertyPath.forEach(p -> p.toDotPath());
180-
* </pre>
181-
*
182-
* results in the dot paths:
183-
*
184-
* <pre class="code">
185-
* a.b.c
186-
* b.c
187-
* c
188-
* </pre>
189-
*/
190-
@Override
191-
Iterator<PropertyPath> iterator();
192-
193-
/**
194-
* Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}. <br />
195-
* Uses {@code (?:[%s]?([%s]*?[^%s]+))} by default and {@code (?:[%s]?([%s]*?[^%s]+))} for
196-
* {@link Pattern#quote(String) quoted} literals.
197-
* <p>
198-
* Separate parts of the path may be separated by {@code "."} or by {@code "_"} or by camel case. When the match to
199-
* properties is ambiguous longer property names are preferred. So for {@code userAddressCity} the interpretation
200-
* {@code userAddress.city} is preferred over {@code user.address.city}.
201-
*
202-
* @param source a String denoting the property path, must not be {@literal null}.
203-
* @param type the owning type of the property path, must not be {@literal null}.
204-
* @return a new {@link PropertyPath} guaranteed to be not {@literal null}.
205-
*/
206-
static PropertyPath from(String source, Class<?> type) {
207-
return from(source, TypeInformation.of(type));
208-
}
209-
210-
/**
211-
* Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}. <br />
212-
* Uses {@code (?:[%s]?([%s]*?[^%s]+))} by default and {@code (?:[%s]?([%s]*?[^%s]+))} for
213-
* {@link Pattern#quote(String) quoted} literals.
214-
* <p>
215-
* Separate parts of the path may be separated by {@code "."} or by {@code "_"} or by camel case. When the match to
216-
* properties is ambiguous longer property names are preferred. So for {@code userAddressCity} the interpretation
217-
* {@code userAddress.city} is preferred over {@code user.address.city}.
218-
*
219-
* @param source a String denoting the property path, must not be {@literal null}.
220-
* @param type the owning type of the property path, must not be {@literal null}.
221-
* @return a new {@link PropertyPath} guaranteed to be not {@literal null}.
222-
*/
223-
static PropertyPath from(String source, TypeInformation<?> type) {
224-
return SimplePropertyPath.from(source, type);
225-
}
28+
@Deprecated
29+
public interface PropertyPath extends org.springframework.data.util.PropertyPath {
22630

22731
}

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

Lines changed: 7 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -16,140 +16,34 @@
1616
package org.springframework.data.mapping;
1717

1818
import java.io.Serial;
19-
import java.util.Arrays;
20-
import java.util.Collection;
21-
import java.util.HashSet;
2219
import java.util.List;
23-
import java.util.Set;
2420

25-
import org.jspecify.annotations.Nullable;
26-
27-
import org.springframework.beans.PropertyMatches;
28-
import org.springframework.data.util.Lazy;
21+
import org.springframework.data.util.PropertyPath;
2922
import org.springframework.data.util.TypeInformation;
30-
import org.springframework.util.Assert;
31-
import org.springframework.util.StringUtils;
3223

3324
/**
3425
* Exception being thrown when creating {@link PropertyPath} instances.
3526
*
3627
* @author Oliver Gierke
3728
* @author Christoph Strobl
3829
* @author John Blum
30+
* @since 4.1, use its replacement from the {@code org.springframework.data.util} package.
3931
*/
40-
public class PropertyReferenceException extends RuntimeException {
32+
@Deprecated(since = "4.1")
33+
public class PropertyReferenceException extends org.springframework.data.util.PropertyReferenceException {
4134

4235
private static final @Serial long serialVersionUID = -5254424051438976570L;
4336

44-
static final String ERROR_TEMPLATE = "No property '%s' found for type '%s'";
45-
static final String HINTS_TEMPLATE = "Did you mean %s";
46-
47-
private final String propertyName;
48-
private final TypeInformation<?> type;
49-
private final List<? extends PropertyPath> alreadyResolvedPath;
50-
private final Lazy<Set<String>> propertyMatches;
51-
5237
/**
5338
* Creates a new {@link PropertyReferenceException}.
5439
*
5540
* @param propertyName the name of the property not found on the given type, must not be {@literal null} or empty.
5641
* @param type the type the property could not be found on, must not be {@literal null}.
57-
* @param alreadyResolvedPah the previously calculated {@link PropertyPath}s, must not be {@literal null}.
42+
* @param alreadyResolvedPaths the previously calculated {@link PropertyPath}s, must not be {@literal null}.
5843
*/
5944
public PropertyReferenceException(String propertyName, TypeInformation<?> type,
60-
List<? extends PropertyPath> alreadyResolvedPah) {
61-
62-
Assert.hasText(propertyName, "Property name must not be null");
63-
Assert.notNull(type, "Type must not be null");
64-
Assert.notNull(alreadyResolvedPah, "Already resolved paths must not be null");
65-
66-
this.propertyName = propertyName;
67-
this.type = type;
68-
this.alreadyResolvedPath = alreadyResolvedPah;
69-
this.propertyMatches = Lazy.of(() -> detectPotentialMatches(propertyName, type.getType()));
70-
}
71-
72-
/**
73-
* Returns the name of the property not found.
74-
*
75-
* @return will not be {@literal null} or empty.
76-
*/
77-
public String getPropertyName() {
78-
return propertyName;
79-
}
80-
81-
/**
82-
* Returns the type the property could not be found on.
83-
*
84-
* @return will never be {@literal null}.
85-
*/
86-
public TypeInformation<?> getType() {
87-
return type;
88-
}
89-
90-
/**
91-
* Returns the properties that the invalid property might have been meant to be referred to.
92-
*
93-
* @return will never be {@literal null}.
94-
*/
95-
Collection<String> getPropertyMatches() {
96-
return propertyMatches.get();
97-
}
98-
99-
@Override
100-
public String getMessage() {
101-
102-
StringBuilder builder = new StringBuilder(
103-
String.format(ERROR_TEMPLATE, propertyName, type.getType().getSimpleName()));
104-
105-
Collection<String> potentialMatches = getPropertyMatches();
106-
if (!potentialMatches.isEmpty()) {
107-
String matches = StringUtils.collectionToDelimitedString(potentialMatches, ",", "'", "'");
108-
builder.append("; ");
109-
builder.append(String.format(HINTS_TEMPLATE, matches));
110-
}
111-
112-
if (!alreadyResolvedPath.isEmpty()) {
113-
builder.append("; Traversed path: ");
114-
builder.append(alreadyResolvedPath.get(0).toString());
115-
}
116-
117-
return builder.toString();
45+
List<? extends PropertyPath> alreadyResolvedPaths) {
46+
super(propertyName, type, alreadyResolvedPaths);
11847
}
11948

120-
/**
121-
* Returns the {@link PropertyPath} which could be resolved so far.
122-
*
123-
* @return
124-
*/
125-
public @Nullable PropertyPath getBaseProperty() {
126-
return alreadyResolvedPath.isEmpty() ? null : alreadyResolvedPath.get(alreadyResolvedPath.size() - 1);
127-
}
128-
129-
/**
130-
* Returns whether the given {@link PropertyReferenceException} has a deeper resolution depth (i.e. a longer path of
131-
* already resolved properties) than the current exception.
132-
*
133-
* @param exception must not be {@literal null}.
134-
* @return
135-
*/
136-
public boolean hasDeeperResolutionDepthThan(PropertyReferenceException exception) {
137-
return this.alreadyResolvedPath.size() > exception.alreadyResolvedPath.size();
138-
}
139-
140-
/**
141-
* Detects all potential matches for the given property name and type.
142-
*
143-
* @param propertyName must not be {@literal null} or empty.
144-
* @param type must not be {@literal null}.
145-
* @return
146-
*/
147-
private static Set<String> detectPotentialMatches(String propertyName, Class<?> type) {
148-
149-
Set<String> result = new HashSet<>();
150-
result.addAll(Arrays.asList(PropertyMatches.forField(propertyName, type).getPossibleMatches()));
151-
result.addAll(Arrays.asList(PropertyMatches.forProperty(propertyName, type).getPossibleMatches()));
152-
153-
return result;
154-
}
15549
}

src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
import org.springframework.data.mapping.PersistentProperty;
5757
import org.springframework.data.mapping.PersistentPropertyPath;
5858
import org.springframework.data.mapping.PersistentPropertyPaths;
59-
import org.springframework.data.mapping.PropertyPath;
6059
import org.springframework.data.mapping.model.ClassGeneratingPropertyAccessorFactory;
6160
import org.springframework.data.mapping.model.EntityInstantiators;
6261
import org.springframework.data.mapping.model.InstantiationAwarePropertyAccessorFactory;
@@ -70,6 +69,7 @@
7069
import org.springframework.data.util.KotlinReflectionUtils;
7170
import org.springframework.data.util.NullableWrapperConverters;
7271
import org.springframework.data.util.Optionals;
72+
import org.springframework.data.util.PropertyPath;
7373
import org.springframework.data.util.Streamable;
7474
import org.springframework.data.util.TypeInformation;
7575
import org.springframework.util.Assert;

src/main/java/org/springframework/data/mapping/context/MappingContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.springframework.data.mapping.PersistentProperty;
2626
import org.springframework.data.mapping.PersistentPropertyPath;
2727
import org.springframework.data.mapping.PersistentPropertyPaths;
28-
import org.springframework.data.mapping.PropertyPath;
28+
import org.springframework.data.util.PropertyPath;
2929
import org.springframework.data.util.TypeInformation;
3030

3131
/**

0 commit comments

Comments
 (0)