Skip to content

Commit 6df2764

Browse files
committed
Merge branch '6.1.x'
2 parents 2f2c418 + cd7ba18 commit 6df2764

16 files changed

+109
-101
lines changed

spring-core/src/main/java/org/springframework/core/ReactiveTypeDescriptor.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -98,7 +98,9 @@ public boolean supportsEmpty() {
9898
*/
9999
public Object getEmptyValue() {
100100
Assert.state(this.emptySupplier != null, "Empty values not supported");
101-
return this.emptySupplier.get();
101+
Object emptyValue = this.emptySupplier.get();
102+
Assert.notNull(emptyValue, "Invalid null return value from emptySupplier");
103+
return emptyValue;
102104
}
103105

104106
/**

spring-core/src/main/java/org/springframework/core/ResolvableType.java

+11-12
Original file line numberDiff line numberDiff line change
@@ -1170,22 +1170,21 @@ public static ResolvableType forClassWithGenerics(Class<?> clazz, Class<?>... ge
11701170
* @return a {@code ResolvableType} for the specific class and generics
11711171
* @see #forClassWithGenerics(Class, Class...)
11721172
*/
1173-
public static ResolvableType forClassWithGenerics(Class<?> clazz, ResolvableType... generics) {
1173+
public static ResolvableType forClassWithGenerics(Class<?> clazz, @Nullable ResolvableType... generics) {
11741174
Assert.notNull(clazz, "Class must not be null");
1175-
Assert.notNull(generics, "Generics array must not be null");
11761175
TypeVariable<?>[] variables = clazz.getTypeParameters();
1177-
Assert.isTrue(variables.length == generics.length,
1178-
() -> "Mismatched number of generics specified for " + clazz.toGenericString());
1179-
1180-
Type[] arguments = new Type[generics.length];
1181-
for (int i = 0; i < generics.length; i++) {
1182-
ResolvableType generic = generics[i];
1176+
if (generics != null) {
1177+
Assert.isTrue(variables.length == generics.length,
1178+
() -> "Mismatched number of generics specified for " + clazz.toGenericString());
1179+
}
1180+
Type[] arguments = new Type[variables.length];
1181+
for (int i = 0; i < variables.length; i++) {
1182+
ResolvableType generic = (generics != null ? generics[i] : null);
11831183
Type argument = (generic != null ? generic.getType() : null);
11841184
arguments[i] = (argument != null && !(argument instanceof TypeVariable) ? argument : variables[i]);
11851185
}
1186-
1187-
ParameterizedType syntheticType = new SyntheticParameterizedType(clazz, arguments);
1188-
return forType(syntheticType, new TypeVariablesVariableResolver(variables, generics));
1186+
return forType(new SyntheticParameterizedType(clazz, arguments),
1187+
(generics != null ? new TypeVariablesVariableResolver(variables, generics) : null));
11891188
}
11901189

11911190
/**
@@ -1440,7 +1439,7 @@ static ResolvableType forMethodParameter(
14401439
*/
14411440
public static ResolvableType forArrayComponent(ResolvableType componentType) {
14421441
Assert.notNull(componentType, "Component type must not be null");
1443-
Class<?> arrayType = componentType.resolve().arrayType();
1442+
Class<?> arrayType = componentType.toClass().arrayType();
14441443
return new ResolvableType(arrayType, componentType, null, null);
14451444
}
14461445

spring-core/src/main/java/org/springframework/core/annotation/AnnotatedMethod.java

+1
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ public Class<?> getContainingClass() {
278278
}
279279

280280
@Override
281+
@Nullable
281282
public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) {
282283
return AnnotatedMethod.this.getMethodAnnotation(annotationType);
283284
}

spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java

+29-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -114,19 +114,6 @@ public AnnotationAttributes(Class<? extends Annotation> annotationType) {
114114
this(annotationType, false);
115115
}
116116

117-
/**
118-
* Create a new, empty {@link AnnotationAttributes} instance for the
119-
* specified {@code annotationType}.
120-
* @param annotationType the annotation type name represented by this
121-
* {@code AnnotationAttributes} instance; never {@code null}
122-
* @param classLoader the ClassLoader to try to load the annotation type on,
123-
* or {@code null} to just store the annotation type name
124-
* @since 4.3.2
125-
*/
126-
public AnnotationAttributes(String annotationType, @Nullable ClassLoader classLoader) {
127-
this(getAnnotationType(annotationType, classLoader), false);
128-
}
129-
130117
/**
131118
* Create a possibly already validated new, empty
132119
* {@link AnnotationAttributes} instance for the specified
@@ -143,6 +130,21 @@ public AnnotationAttributes(String annotationType, @Nullable ClassLoader classLo
143130
this.validated = validated;
144131
}
145132

133+
/**
134+
* Create a new, empty {@link AnnotationAttributes} instance for the
135+
* specified {@code annotationType}.
136+
* @param annotationType the annotation type name represented by this
137+
* {@code AnnotationAttributes} instance; never {@code null}
138+
* @param classLoader the ClassLoader to try to load the annotation type on,
139+
* or {@code null} to just store the annotation type name
140+
* @since 4.3.2
141+
*/
142+
public AnnotationAttributes(String annotationType, @Nullable ClassLoader classLoader) {
143+
Assert.notNull(annotationType, "'annotationType' must not be null");
144+
this.annotationType = getAnnotationType(annotationType, classLoader);
145+
this.displayName = annotationType;
146+
this.validated = false;
147+
}
146148

147149
@SuppressWarnings("unchecked")
148150
@Nullable
@@ -349,39 +351,29 @@ public <A extends Annotation> A[] getAnnotationArray(String attributeName, Class
349351
private <T> T getRequiredAttribute(String attributeName, Class<T> expectedType) {
350352
Assert.hasText(attributeName, "'attributeName' must not be null or empty");
351353
Object value = get(attributeName);
352-
assertAttributePresence(attributeName, value);
353-
assertNotException(attributeName, value);
354+
if (value == null) {
355+
throw new IllegalArgumentException(String.format(
356+
"Attribute '%s' not found in attributes for annotation [%s]",
357+
attributeName, this.displayName));
358+
}
359+
if (value instanceof Throwable throwable) {
360+
throw new IllegalArgumentException(String.format(
361+
"Attribute '%s' for annotation [%s] was not resolvable due to exception [%s]",
362+
attributeName, this.displayName, value), throwable);
363+
}
354364
if (!expectedType.isInstance(value) && expectedType.isArray() &&
355365
expectedType.componentType().isInstance(value)) {
356366
Object array = Array.newInstance(expectedType.componentType(), 1);
357367
Array.set(array, 0, value);
358368
value = array;
359369
}
360-
assertAttributeType(attributeName, value, expectedType);
361-
return (T) value;
362-
}
363-
364-
private void assertAttributePresence(String attributeName, Object attributeValue) {
365-
Assert.notNull(attributeValue, () -> String.format(
366-
"Attribute '%s' not found in attributes for annotation [%s]",
367-
attributeName, this.displayName));
368-
}
369-
370-
private void assertNotException(String attributeName, Object attributeValue) {
371-
if (attributeValue instanceof Throwable throwable) {
372-
throw new IllegalArgumentException(String.format(
373-
"Attribute '%s' for annotation [%s] was not resolvable due to exception [%s]",
374-
attributeName, this.displayName, attributeValue), throwable);
375-
}
376-
}
377-
378-
private void assertAttributeType(String attributeName, Object attributeValue, Class<?> expectedType) {
379-
if (!expectedType.isInstance(attributeValue)) {
370+
if (!expectedType.isInstance(value)) {
380371
throw new IllegalArgumentException(String.format(
381372
"Attribute '%s' is of type %s, but %s was expected in attributes for annotation [%s]",
382-
attributeName, attributeValue.getClass().getSimpleName(), expectedType.getSimpleName(),
373+
attributeName, value.getClass().getSimpleName(), expectedType.getSimpleName(),
383374
this.displayName));
384375
}
376+
return (T) value;
385377
}
386378

387379
@Override

spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -985,8 +985,12 @@ public static void postProcessAnnotationAttributes(@Nullable Object annotatedEle
985985
}
986986
}
987987

988-
private static Object getAttributeValueForMirrorResolution(Method attribute, Object attributes) {
989-
Object result = ((AnnotationAttributes) attributes).get(attribute.getName());
988+
@Nullable
989+
private static Object getAttributeValueForMirrorResolution(Method attribute, @Nullable Object attributes) {
990+
if (!(attributes instanceof AnnotationAttributes annotationAttributes)) {
991+
return null;
992+
}
993+
Object result = annotationAttributes.get(attribute.getName());
990994
return (result instanceof DefaultValueHolder defaultValueHolder ? defaultValueHolder.defaultValue : result);
991995
}
992996

spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java

+21-19
Original file line numberDiff line numberDiff line change
@@ -127,29 +127,31 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
127127
if (result != null) {
128128
return result;
129129
}
130-
Annotation[] declaredAnnotations = getDeclaredAnnotations(source, true);
131-
if (relevant == null && declaredAnnotations.length > 0) {
132-
relevant = root.getAnnotations();
133-
remaining = relevant.length;
134-
}
135-
for (int i = 0; i < declaredAnnotations.length; i++) {
136-
if (declaredAnnotations[i] != null) {
137-
boolean isRelevant = false;
138-
for (int relevantIndex = 0; relevantIndex < relevant.length; relevantIndex++) {
139-
if (relevant[relevantIndex] != null &&
140-
declaredAnnotations[i].annotationType() == relevant[relevantIndex].annotationType()) {
141-
isRelevant = true;
142-
relevant[relevantIndex] = null;
143-
remaining--;
144-
break;
130+
Annotation[] declaredAnns = getDeclaredAnnotations(source, true);
131+
if (declaredAnns.length > 0) {
132+
if (relevant == null) {
133+
relevant = root.getAnnotations();
134+
remaining = relevant.length;
135+
}
136+
for (int i = 0; i < declaredAnns.length; i++) {
137+
if (declaredAnns[i] != null) {
138+
boolean isRelevant = false;
139+
for (int relevantIndex = 0; relevantIndex < relevant.length; relevantIndex++) {
140+
if (relevant[relevantIndex] != null &&
141+
declaredAnns[i].annotationType() == relevant[relevantIndex].annotationType()) {
142+
isRelevant = true;
143+
relevant[relevantIndex] = null;
144+
remaining--;
145+
break;
146+
}
147+
}
148+
if (!isRelevant) {
149+
declaredAnns[i] = null;
145150
}
146-
}
147-
if (!isRelevant) {
148-
declaredAnnotations[i] = null;
149151
}
150152
}
151153
}
152-
result = processor.doWithAnnotations(context, aggregateIndex, source, declaredAnnotations);
154+
result = processor.doWithAnnotations(context, aggregateIndex, source, declaredAnns);
153155
if (result != null) {
154156
return result;
155157
}

spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -322,12 +322,13 @@ private <T extends Map<String, Object>> Object adaptValueForMapOptions(Method at
322322
@SuppressWarnings("unchecked")
323323
protected A createSynthesizedAnnotation() {
324324
// Check root annotation
325-
if (isTargetAnnotation(this.rootAttributes) && !isSynthesizable((Annotation) this.rootAttributes)) {
326-
return (A) this.rootAttributes;
325+
if (this.rootAttributes instanceof Annotation ann && isTargetAnnotation(ann) && !isSynthesizable(ann)) {
326+
return (A) ann;
327327
}
328328
// Check meta-annotation
329-
else if (isTargetAnnotation(this.mapping.getAnnotation()) && !isSynthesizable(this.mapping.getAnnotation())) {
330-
return (A) this.mapping.getAnnotation();
329+
Annotation meta = this.mapping.getAnnotation();
330+
if (meta != null && isTargetAnnotation(meta) && !isSynthesizable(meta)) {
331+
return (A) meta;
331332
}
332333
return SynthesizedMergedAnnotationInvocationHandler.createProxy(this, getType());
333334
}
@@ -338,7 +339,7 @@ else if (isTargetAnnotation(this.mapping.getAnnotation()) && !isSynthesizable(th
338339
* @param obj the object to check
339340
* @since 5.3.22
340341
*/
341-
private boolean isTargetAnnotation(@Nullable Object obj) {
342+
private boolean isTargetAnnotation(Object obj) {
342343
return getType().isInstance(obj);
343344
}
344345

@@ -432,7 +433,7 @@ private Object getValueFromMetaAnnotation(int attributeIndex, boolean forMirrorR
432433
}
433434

434435
@Nullable
435-
private Object getValueForMirrorResolution(Method attribute, Object annotation) {
436+
private Object getValueForMirrorResolution(Method attribute, @Nullable Object annotation) {
436437
int attributeIndex = this.mapping.getAttributes().indexOf(attribute);
437438
boolean valueAttribute = VALUE.equals(attribute.getName());
438439
return getValue(attributeIndex, !valueAttribute, true);

spring-core/src/main/java/org/springframework/core/codec/Decoder.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -95,20 +95,19 @@ default T decode(DataBuffer buffer, ResolvableType targetType,
9595
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {
9696

9797
CompletableFuture<T> future = decodeToMono(Mono.just(buffer), targetType, mimeType, hints).toFuture();
98-
Assert.state(future.isDone(), "DataBuffer decoding should have completed.");
98+
Assert.state(future.isDone(), "DataBuffer decoding should have completed");
9999

100-
Throwable failure;
101100
try {
102101
return future.get();
103102
}
104103
catch (ExecutionException ex) {
105-
failure = ex.getCause();
104+
Throwable cause = ex.getCause();
105+
throw (cause instanceof CodecException codecException ? codecException :
106+
new DecodingException("Failed to decode: " + (cause != null ? cause.getMessage() : ex), cause));
106107
}
107108
catch (InterruptedException ex) {
108-
failure = ex;
109+
throw new DecodingException("Interrupted during decode", ex);
109110
}
110-
throw (failure instanceof CodecException codecException ? codecException :
111-
new DecodingException("Failed to decode: " + failure.getMessage(), failure));
112111
}
113112

114113
/**

spring-core/src/main/java/org/springframework/core/codec/ResourceDecoder.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -80,6 +80,7 @@ public Resource decode(DataBuffer dataBuffer, ResolvableType elementType,
8080
if (clazz == InputStreamResource.class) {
8181
return new InputStreamResource(new ByteArrayInputStream(bytes)) {
8282
@Override
83+
@Nullable
8384
public String getFilename() {
8485
return filename;
8586
}
@@ -92,6 +93,7 @@ public long contentLength() {
9293
else if (Resource.class.isAssignableFrom(clazz)) {
9394
return new ByteArrayResource(bytes) {
9495
@Override
96+
@Nullable
9597
public String getFilename() {
9698
return filename;
9799
}

spring-core/src/main/java/org/springframework/core/convert/support/ObjectToObjectConverter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -136,7 +136,7 @@ static boolean hasConversionMethodOrConstructor(Class<?> targetClass, Class<?> s
136136
@Nullable
137137
private static Executable getValidatedExecutable(Class<?> targetClass, Class<?> sourceClass) {
138138
Executable executable = conversionExecutableCache.get(targetClass);
139-
if (isApplicable(executable, sourceClass)) {
139+
if (executable != null && isApplicable(executable, sourceClass)) {
140140
return executable;
141141
}
142142

spring-core/src/main/java/org/springframework/core/convert/support/StringToPatternConverter.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.util.regex.Pattern;
2020

2121
import org.springframework.core.convert.converter.Converter;
22+
import org.springframework.lang.Nullable;
2223

2324
/**
2425
* Converts from a String to a {@link java.util.regex.Pattern}.
@@ -30,6 +31,7 @@
3031
final class StringToPatternConverter implements Converter<String, Pattern> {
3132

3233
@Override
34+
@Nullable
3335
public Pattern convert(String source) {
3436
if (source.isEmpty()) {
3537
return null;

0 commit comments

Comments
 (0)