Merge branch '6.1.x'
# Conflicts: # spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -53,7 +53,7 @@ public class DefaultMethodReference implements MethodReference {
|
||||
public CodeBlock toCodeBlock() {
|
||||
String methodName = this.method.name;
|
||||
if (isStatic()) {
|
||||
Assert.state(this.declaringClass != null, "static method reference must define a declaring class");
|
||||
Assert.state(this.declaringClass != null, "Static method reference must define a declaring class");
|
||||
return CodeBlock.of("$T::$L", this.declaringClass, methodName);
|
||||
}
|
||||
else {
|
||||
@@ -64,11 +64,12 @@ public class DefaultMethodReference implements MethodReference {
|
||||
@Override
|
||||
public CodeBlock toInvokeCodeBlock(ArgumentCodeGenerator argumentCodeGenerator,
|
||||
@Nullable ClassName targetClassName) {
|
||||
|
||||
String methodName = this.method.name;
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
if (isStatic()) {
|
||||
Assert.state(this.declaringClass != null, "static method reference must define a declaring class");
|
||||
if (isSameDeclaringClass(targetClassName)) {
|
||||
Assert.state(this.declaringClass != null, "Static method reference must define a declaring class");
|
||||
if (this.declaringClass.equals(targetClassName)) {
|
||||
code.add("$L", methodName);
|
||||
}
|
||||
else {
|
||||
@@ -76,7 +77,7 @@ public class DefaultMethodReference implements MethodReference {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!isSameDeclaringClass(targetClassName)) {
|
||||
if (this.declaringClass != null && !this.declaringClass.equals(targetClassName)) {
|
||||
code.add(instantiateDeclaringClass(this.declaringClass));
|
||||
}
|
||||
code.add("$L", methodName);
|
||||
@@ -117,10 +118,6 @@ public class DefaultMethodReference implements MethodReference {
|
||||
return this.method.modifiers.contains(Modifier.STATIC);
|
||||
}
|
||||
|
||||
private boolean isSameDeclaringClass(ClassName declaringClass) {
|
||||
return this.declaringClass == null || this.declaringClass.equals(declaringClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String methodName = this.method.name;
|
||||
@@ -128,7 +125,7 @@ public class DefaultMethodReference implements MethodReference {
|
||||
return this.declaringClass + "::" + methodName;
|
||||
}
|
||||
else {
|
||||
return ((this.declaringClass != null) ?
|
||||
return (this.declaringClass != null ?
|
||||
"<" + this.declaringClass + ">" : "<instance>") + "::" + methodName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -194,6 +194,7 @@ public class ReflectionHintsPredicates {
|
||||
return new FieldHintPredicate(field);
|
||||
}
|
||||
|
||||
|
||||
public static class TypeHintPredicate implements Predicate<RuntimeHints> {
|
||||
|
||||
private final TypeReference type;
|
||||
@@ -212,7 +213,6 @@ public class ReflectionHintsPredicates {
|
||||
return getTypeHint(hints) != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refine the current predicate to only match if the given {@link MemberCategory} is present.
|
||||
* @param memberCategory the member category
|
||||
@@ -220,7 +220,10 @@ public class ReflectionHintsPredicates {
|
||||
*/
|
||||
public Predicate<RuntimeHints> withMemberCategory(MemberCategory memberCategory) {
|
||||
Assert.notNull(memberCategory, "'memberCategory' must not be null");
|
||||
return this.and(hints -> getTypeHint(hints).getMemberCategories().contains(memberCategory));
|
||||
return and(hints -> {
|
||||
TypeHint hint = getTypeHint(hints);
|
||||
return (hint != null && hint.getMemberCategories().contains(memberCategory));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +233,10 @@ public class ReflectionHintsPredicates {
|
||||
*/
|
||||
public Predicate<RuntimeHints> withMemberCategories(MemberCategory... memberCategories) {
|
||||
Assert.notEmpty(memberCategories, "'memberCategories' must not be empty");
|
||||
return this.and(hints -> getTypeHint(hints).getMemberCategories().containsAll(Arrays.asList(memberCategories)));
|
||||
return and(hints -> {
|
||||
TypeHint hint = getTypeHint(hints);
|
||||
return (hint != null && hint.getMemberCategories().containsAll(Arrays.asList(memberCategories)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,12 +246,15 @@ public class ReflectionHintsPredicates {
|
||||
*/
|
||||
public Predicate<RuntimeHints> withAnyMemberCategory(MemberCategory... memberCategories) {
|
||||
Assert.notEmpty(memberCategories, "'memberCategories' must not be empty");
|
||||
return this.and(hints -> Arrays.stream(memberCategories)
|
||||
.anyMatch(memberCategory -> getTypeHint(hints).getMemberCategories().contains(memberCategory)));
|
||||
return and(hints -> {
|
||||
TypeHint hint = getTypeHint(hints);
|
||||
return (hint != null && Arrays.stream(memberCategories)
|
||||
.anyMatch(memberCategory -> hint.getMemberCategories().contains(memberCategory)));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public abstract static class ExecutableHintPredicate<T extends Executable> implements Predicate<RuntimeHints> {
|
||||
|
||||
protected final T executable;
|
||||
@@ -289,6 +298,7 @@ public class ReflectionHintsPredicates {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ConstructorHintPredicate extends ExecutableHintPredicate<Constructor<?>> {
|
||||
|
||||
ConstructorHintPredicate(Constructor<?> constructor) {
|
||||
@@ -322,15 +332,17 @@ public class ReflectionHintsPredicates {
|
||||
|
||||
@Override
|
||||
Predicate<RuntimeHints> exactMatch() {
|
||||
return hints -> (hints.reflection().getTypeHint(this.executable.getDeclaringClass()) != null) &&
|
||||
hints.reflection().getTypeHint(this.executable.getDeclaringClass()).constructors().anyMatch(executableHint -> {
|
||||
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
||||
return includes(executableHint, "<init>", parameters, this.executableMode);
|
||||
});
|
||||
return hints -> {
|
||||
TypeHint hint = hints.reflection().getTypeHint(this.executable.getDeclaringClass());
|
||||
return (hint != null && hint.constructors().anyMatch(executableHint -> {
|
||||
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
||||
return includes(executableHint, "<init>", parameters, this.executableMode);
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class MethodHintPredicate extends ExecutableHintPredicate<Method> {
|
||||
|
||||
MethodHintPredicate(Method method) {
|
||||
@@ -367,15 +379,17 @@ public class ReflectionHintsPredicates {
|
||||
|
||||
@Override
|
||||
Predicate<RuntimeHints> exactMatch() {
|
||||
return hints -> (hints.reflection().getTypeHint(this.executable.getDeclaringClass()) != null) &&
|
||||
hints.reflection().getTypeHint(this.executable.getDeclaringClass()).methods().anyMatch(executableHint -> {
|
||||
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
||||
return includes(executableHint, this.executable.getName(), parameters, this.executableMode);
|
||||
});
|
||||
return hints -> {
|
||||
TypeHint hint = hints.reflection().getTypeHint(this.executable.getDeclaringClass());
|
||||
return (hint != null && hint.methods().anyMatch(executableHint -> {
|
||||
List<TypeReference> parameters = TypeReference.listOf(this.executable.getParameterTypes());
|
||||
return includes(executableHint, this.executable.getName(), parameters, this.executableMode);
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class FieldHintPredicate implements Predicate<RuntimeHints> {
|
||||
|
||||
private final Field field;
|
||||
@@ -406,7 +420,6 @@ public class ReflectionHintsPredicates {
|
||||
return typeHint.fields().anyMatch(fieldHint ->
|
||||
this.field.getName().equals(fieldHint.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -63,6 +64,7 @@ public abstract class CoroutinesUtils {
|
||||
|
||||
private static final KType publisherType = KClassifiers.getStarProjectedType(JvmClassMappingKt.getKotlinClass(Publisher.class));
|
||||
|
||||
|
||||
/**
|
||||
* Convert a {@link Deferred} instance to a {@link Mono}.
|
||||
*/
|
||||
@@ -90,8 +92,7 @@ public abstract class CoroutinesUtils {
|
||||
* @return the method invocation result as reactive stream
|
||||
* @throws IllegalArgumentException if {@code method} is not a suspending function
|
||||
*/
|
||||
public static Publisher<?> invokeSuspendingFunction(Method method, Object target,
|
||||
Object... args) {
|
||||
public static Publisher<?> invokeSuspendingFunction(Method method, Object target, Object... args) {
|
||||
return invokeSuspendingFunction(Dispatchers.getUnconfined(), method, target, args);
|
||||
}
|
||||
|
||||
@@ -108,9 +109,10 @@ public abstract class CoroutinesUtils {
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "DataFlowIssue"})
|
||||
public static Publisher<?> invokeSuspendingFunction(CoroutineContext context, Method method, Object target,
|
||||
Object... args) {
|
||||
Assert.isTrue(KotlinDetector.isSuspendingFunction(method), "'method' must be a suspending function");
|
||||
public static Publisher<?> invokeSuspendingFunction(
|
||||
CoroutineContext context, Method method, @Nullable Object target, Object... args) {
|
||||
|
||||
Assert.isTrue(KotlinDetector.isSuspendingFunction(method), "Method must be a suspending function");
|
||||
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
|
||||
Assert.notNull(function, () -> "Failed to get Kotlin function for method: " + method);
|
||||
if (method.isAccessible() && !KCallablesJvm.isAccessible(function)) {
|
||||
|
||||
@@ -650,11 +650,10 @@ public abstract class AnnotationUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (Class<?>) MergedAnnotations.from(clazz, SearchStrategy.SUPERCLASS)
|
||||
.stream()
|
||||
MergedAnnotation<?> merged = MergedAnnotations.from(clazz, SearchStrategy.SUPERCLASS).stream()
|
||||
.filter(MergedAnnotationPredicates.typeIn(annotationTypes).and(MergedAnnotation::isDirectlyPresent))
|
||||
.map(MergedAnnotation::getSource)
|
||||
.findFirst().orElse(null);
|
||||
return (merged != null && merged.getSource() instanceof Class<?> sourceClass ? sourceClass : null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -167,19 +167,21 @@ final class MergedAnnotationsCollection implements MergedAnnotations {
|
||||
MergedAnnotation<A> result = null;
|
||||
for (int i = 0; i < this.annotations.length; i++) {
|
||||
MergedAnnotation<?> root = this.annotations[i];
|
||||
AnnotationTypeMappings mappings = this.mappings[i];
|
||||
for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
|
||||
AnnotationTypeMapping mapping = mappings.get(mappingIndex);
|
||||
if (!isMappingForType(mapping, requiredType)) {
|
||||
continue;
|
||||
}
|
||||
MergedAnnotation<A> candidate = (mappingIndex == 0 ? (MergedAnnotation<A>) root :
|
||||
TypeMappedAnnotation.createIfPossible(mapping, root, IntrospectionFailureLogger.INFO));
|
||||
if (candidate != null && (predicate == null || predicate.test(candidate))) {
|
||||
if (selector.isBestCandidate(candidate)) {
|
||||
return candidate;
|
||||
if (root != null) {
|
||||
AnnotationTypeMappings mappings = this.mappings[i];
|
||||
for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
|
||||
AnnotationTypeMapping mapping = mappings.get(mappingIndex);
|
||||
if (!isMappingForType(mapping, requiredType)) {
|
||||
continue;
|
||||
}
|
||||
MergedAnnotation<A> candidate = (mappingIndex == 0 ? (MergedAnnotation<A>) root :
|
||||
TypeMappedAnnotation.createIfPossible(mapping, root, IntrospectionFailureLogger.INFO));
|
||||
if (candidate != null && (predicate == null || predicate.test(candidate))) {
|
||||
if (selector.isBestCandidate(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
result = (result != null ? selector.select(result, candidate) : candidate);
|
||||
}
|
||||
result = (result != null ? selector.select(result, candidate) : candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.lang.Nullable;
|
||||
* @author Sebastien Deleuze
|
||||
* @since 6.1
|
||||
*/
|
||||
class StringToRegexConverter implements Converter<String, Regex> {
|
||||
final class StringToRegexConverter implements Converter<String, Regex> {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
|
||||
@@ -1113,13 +1113,13 @@ public abstract class DataBufferUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Attachment attachment) {
|
||||
public void failed(Throwable ex, Attachment attachment) {
|
||||
attachment.iterator().close();
|
||||
release(attachment.dataBuffer());
|
||||
|
||||
closeChannel(this.channel);
|
||||
this.state.set(State.DISPOSED);
|
||||
this.sink.error(exc);
|
||||
this.sink.error(ex);
|
||||
}
|
||||
|
||||
private enum State {
|
||||
@@ -1178,7 +1178,6 @@ public abstract class DataBufferUtils {
|
||||
public Context currentContext() {
|
||||
return Context.of(this.sink.contextView());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1273,13 +1272,13 @@ public abstract class DataBufferUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Attachment attachment) {
|
||||
public void failed(Throwable ex, Attachment attachment) {
|
||||
attachment.iterator().close();
|
||||
|
||||
this.sink.next(attachment.dataBuffer());
|
||||
this.writing.set(false);
|
||||
|
||||
this.sink.error(exc);
|
||||
this.sink.error(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1288,9 +1287,6 @@ public abstract class DataBufferUtils {
|
||||
}
|
||||
|
||||
private record Attachment(ByteBuffer byteBuffer, DataBuffer dataBuffer, DataBuffer.ByteBufferIterator iterator) {}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -180,13 +180,14 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||
if (isCancelled(previousState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTerminated(previousState)) {
|
||||
// failure due to illegal requestN
|
||||
this.actual.onError(this.error);
|
||||
return;
|
||||
Throwable error = this.error;
|
||||
if (error != null) {
|
||||
this.actual.onError(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.actual.onError(ex);
|
||||
return;
|
||||
}
|
||||
@@ -195,13 +196,14 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||
if (isCancelled(previousState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTerminated(previousState)) {
|
||||
// failure due to illegal requestN
|
||||
this.actual.onError(this.error);
|
||||
return;
|
||||
Throwable error = this.error;
|
||||
if (error != null) {
|
||||
this.actual.onError(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.actual.onComplete();
|
||||
}
|
||||
|
||||
@@ -211,16 +213,13 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||
if (n <= 0) {
|
||||
this.error = new IllegalArgumentException("request should be a positive number");
|
||||
long previousState = tryTerminate();
|
||||
|
||||
if (isTerminated(previousState) || isCancelled(previousState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousState > 0) {
|
||||
// error should eventually be observed and propagated
|
||||
return;
|
||||
}
|
||||
|
||||
// resume parked thread, so it can observe error and propagate it
|
||||
resume();
|
||||
return;
|
||||
@@ -278,11 +277,9 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||
private long tryCancel() {
|
||||
while (true) {
|
||||
long r = this.requested.get();
|
||||
|
||||
if (isCancelled(r)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (this.requested.compareAndSet(r, Long.MIN_VALUE)) {
|
||||
return r;
|
||||
}
|
||||
@@ -292,11 +289,9 @@ final class OutputStreamPublisher implements Publisher<DataBuffer> {
|
||||
private long tryTerminate() {
|
||||
while (true) {
|
||||
long r = this.requested.get();
|
||||
|
||||
if (isCancelled(r) || isTerminated(r)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (this.requested.compareAndSet(r, Long.MIN_VALUE | Long.MAX_VALUE)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ public abstract class ClassUtils {
|
||||
* @see Void
|
||||
* @see Void#TYPE
|
||||
*/
|
||||
public static boolean isVoidType(Class<?> type) {
|
||||
public static boolean isVoidType(@Nullable Class<?> type) {
|
||||
return (type == void.class || type == Void.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -99,7 +99,9 @@ public abstract class SerializationUtils {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Serializable> T clone(T object) {
|
||||
return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
|
||||
Object result = SerializationUtils.deserialize(SerializationUtils.serialize(object));
|
||||
Assert.state(result != null, "Deserialized object must not be null");
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -88,7 +88,7 @@ class DefaultMethodReferenceTests {
|
||||
MethodSpec method = createTestMethod("methodName", new TypeName[0], Modifier.STATIC);
|
||||
MethodReference methodReference = new DefaultMethodReference(method, null);
|
||||
assertThatIllegalStateException().isThrownBy(methodReference::toCodeBlock)
|
||||
.withMessage("static method reference must define a declaring class");
|
||||
.withMessage("Static method reference must define a declaring class");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user