Nullability refinements and related polishing
See gh-32475
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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,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;
|
||||
|
||||
@@ -64,6 +65,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}.
|
||||
*/
|
||||
@@ -109,9 +111,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 = Objects.requireNonNull(ReflectJvmMapping.getKotlinFunction(method));
|
||||
if (method.isAccessible() && !KCallablesJvm.isAccessible(function)) {
|
||||
KCallablesJvm.setAccessible(function, true);
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -178,13 +178,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;
|
||||
}
|
||||
@@ -193,13 +194,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();
|
||||
}
|
||||
|
||||
@@ -209,16 +211,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;
|
||||
@@ -276,11 +275,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;
|
||||
}
|
||||
@@ -290,11 +287,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