|
15 | 15 | */ |
16 | 16 | package org.springframework.data.core; |
17 | 17 |
|
| 18 | +import java.io.Serializable; |
| 19 | +import java.lang.invoke.SerializedLambda; |
| 20 | +import java.lang.reflect.Method; |
18 | 21 | import java.util.Objects; |
19 | 22 |
|
20 | 23 | import org.jspecify.annotations.Nullable; |
21 | 24 |
|
| 25 | +import org.springframework.dao.InvalidDataAccessApiUsageException; |
| 26 | +import org.springframework.util.Assert; |
| 27 | +import org.springframework.util.ReflectionUtils; |
| 28 | + |
22 | 29 | /** |
23 | 30 | * Utility class for {@link PropertyPath} and {@link PropertyReference} implementations. |
24 | 31 | * |
25 | 32 | * @author Mark Paluch |
26 | 33 | * @since 4.1 |
27 | 34 | */ |
28 | | -class PropertyUtil { |
| 35 | +public class PropertyPathUtil { |
| 36 | + |
| 37 | + /** |
| 38 | + * Resolve a {@link PropertyPath} from a {@link Serializable} lambda implementing a functional interface accepting a |
| 39 | + * single method argument and returning a value. The form of the interface must follow a design aligned with |
| 40 | + * {@link org.springframework.core.convert.converter.Converter} or {@link java.util.function.Function}. |
| 41 | + * |
| 42 | + * @param obj the serializable lambda object. |
| 43 | + * @return the resolved property path. |
| 44 | + */ |
| 45 | + public static PropertyPath resolve(Object obj) { |
| 46 | + |
| 47 | + Assert.isInstanceOf(Serializable.class, obj, "Object must be Serializable"); |
| 48 | + |
| 49 | + return TypedPropertyPaths.of(new SerializableWrapper((Serializable) obj)); |
| 50 | + } |
| 51 | + |
| 52 | + private record SerializableWrapper(Serializable serializable) implements PropertyReference<Object, Object> { |
| 53 | + |
| 54 | + @Override |
| 55 | + public @Nullable Object get(Object obj) { |
| 56 | + return null; |
| 57 | + } |
| 58 | + |
| 59 | + // serializable bridge |
| 60 | + public SerializedLambda writeReplace() { |
| 61 | + |
| 62 | + Method method = ReflectionUtils.findMethod(serializable.getClass(), "writeReplace"); |
| 63 | + |
| 64 | + if (method == null) { |
| 65 | + throw new InvalidDataAccessApiUsageException( |
| 66 | + "Cannot find writeReplace method on " + serializable.getClass().getName()); |
| 67 | + } |
| 68 | + |
| 69 | + ReflectionUtils.makeAccessible(method); |
| 70 | + return (SerializedLambda) ReflectionUtils.invokeMethod(method, serializable); |
| 71 | + } |
| 72 | + |
| 73 | + } |
29 | 74 |
|
30 | 75 | /** |
31 | 76 | * Compute the hash code for the given {@link PropertyPath} based on its {@link Object#toString() string} |
|
0 commit comments