Nullability refinements and related polishing

See gh-32475
This commit is contained in:
Juergen Hoeller
2024-03-19 09:58:44 +01:00
parent cd7ba1835c
commit c531a8a705
58 changed files with 327 additions and 257 deletions

View File

@@ -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;
}
}

View File

@@ -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()));
}
}
}

View File

@@ -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);

View File

@@ -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);
}
/**

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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) {}
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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