Browse Source

Expose PropertyPathUtil.

Allow generic parsing of property paths from serialized lambdas.
issue/3400
Mark Paluch 4 weeks ago
parent
commit
f383e78c40
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 47
      src/main/java/org/springframework/data/core/PropertyPathUtil.java
  2. 63
      src/test/java/org/springframework/data/core/PropertyPathUtilUnitTests.java

47
src/main/java/org/springframework/data/core/PropertyUtil.java → src/main/java/org/springframework/data/core/PropertyPathUtil.java

@ -15,17 +15,62 @@
*/ */
package org.springframework.data.core; package org.springframework.data.core;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Objects; import java.util.Objects;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/** /**
* Utility class for {@link PropertyPath} and {@link PropertyReference} implementations. * Utility class for {@link PropertyPath} and {@link PropertyReference} implementations.
* *
* @author Mark Paluch * @author Mark Paluch
* @since 4.1 * @since 4.1
*/ */
class PropertyUtil { public class PropertyPathUtil {
/**
* Resolve a {@link PropertyPath} from a {@link Serializable} lambda implementing a functional interface accepting a
* single method argument and returning a value. The form of the interface must follow a design aligned with
* {@link org.springframework.core.convert.converter.Converter} or {@link java.util.function.Function}.
*
* @param obj the serializable lambda object.
* @return the resolved property path.
*/
public static PropertyPath resolve(Object obj) {
Assert.isInstanceOf(Serializable.class, obj, "Object must be Serializable");
return TypedPropertyPaths.of(new SerializableWrapper((Serializable) obj));
}
private record SerializableWrapper(Serializable serializable) implements PropertyReference<Object, Object> {
@Override
public @Nullable Object get(Object obj) {
return null;
}
// serializable bridge
public SerializedLambda writeReplace() {
Method method = ReflectionUtils.findMethod(serializable.getClass(), "writeReplace");
if (method == null) {
throw new InvalidDataAccessApiUsageException(
"Cannot find writeReplace method on " + serializable.getClass().getName());
}
ReflectionUtils.makeAccessible(method);
return (SerializedLambda) ReflectionUtils.invokeMethod(method, serializable);
}
}
/** /**
* Compute the hash code for the given {@link PropertyPath} based on its {@link Object#toString() string} * Compute the hash code for the given {@link PropertyPath} based on its {@link Object#toString() string}

63
src/test/java/org/springframework/data/core/PropertyPathUtilUnitTests.java

@ -0,0 +1,63 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.core;
import java.io.Serializable;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.converter.Converter;
/**
* Unit test {@link PropertyPathUtil}.
*
* @author Mark Paluch
*/
class PropertyPathUtilUnitTests {
@Test
void shouldResolvePropertyPath() {
Converter<Person, String> c = convert(Person::getName);
System.out.println(PropertyPathUtil.resolve(c));
}
static <T, P, C extends Converter<T, P> & Serializable> Serializable of(C mapping) {
return mapping;
}
static <A, B, T extends Converter<A, B> & Serializable> T convert(T converter) {
return converter;
}
static class Person {
private String name;
private @Nullable Integer age;
// Getters
public String getName() {
return name;
}
public @Nullable Integer getAge() {
return age;
}
}
}
Loading…
Cancel
Save