Skip to content

Commit

Permalink
Nullability refinements
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoeller committed Mar 18, 2024
1 parent 42a4f28 commit 5dc6a16
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 99 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -98,7 +98,9 @@ public boolean supportsEmpty() {
*/
public Object getEmptyValue() {
Assert.state(this.emptySupplier != null, "Empty values not supported");
return this.emptySupplier.get();
Object emptyValue = this.emptySupplier.get();
Assert.notNull(emptyValue, "Invalid null return value from emptySupplier");
return emptyValue;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1118,22 +1118,21 @@ public static ResolvableType forClassWithGenerics(Class<?> clazz, Class<?>... ge
* @return a {@code ResolvableType} for the specific class and generics
* @see #forClassWithGenerics(Class, Class...)
*/
public static ResolvableType forClassWithGenerics(Class<?> clazz, ResolvableType... generics) {
public static ResolvableType forClassWithGenerics(Class<?> clazz, @Nullable ResolvableType... generics) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(generics, "Generics array must not be null");
TypeVariable<?>[] variables = clazz.getTypeParameters();
Assert.isTrue(variables.length == generics.length,
() -> "Mismatched number of generics specified for " + clazz.toGenericString());

Type[] arguments = new Type[generics.length];
for (int i = 0; i < generics.length; i++) {
ResolvableType generic = generics[i];
if (generics != null) {
Assert.isTrue(variables.length == generics.length,
() -> "Mismatched number of generics specified for " + clazz.toGenericString());
}
Type[] arguments = new Type[variables.length];
for (int i = 0; i < variables.length; i++) {
ResolvableType generic = (generics != null ? generics[i] : null);
Type argument = (generic != null ? generic.getType() : null);
arguments[i] = (argument != null && !(argument instanceof TypeVariable) ? argument : variables[i]);
}

ParameterizedType syntheticType = new SyntheticParameterizedType(clazz, arguments);
return forType(syntheticType, new TypeVariablesVariableResolver(variables, generics));
return forType(new SyntheticParameterizedType(clazz, arguments),
(generics != null ? new TypeVariablesVariableResolver(variables, generics) : null));
}

/**
Expand Down Expand Up @@ -1388,7 +1387,7 @@ static ResolvableType forMethodParameter(
*/
public static ResolvableType forArrayComponent(ResolvableType componentType) {
Assert.notNull(componentType, "Component type must not be null");
Class<?> arrayType = componentType.resolve().arrayType();
Class<?> arrayType = componentType.toClass().arrayType();
return new ResolvableType(arrayType, componentType, null, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ public Class<?> getContainingClass() {
}

@Override
@Nullable
public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) {
return AnnotatedMethod.this.getMethodAnnotation(annotationType);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -114,19 +114,6 @@ public AnnotationAttributes(Class<? extends Annotation> annotationType) {
this(annotationType, false);
}

/**
* Create a new, empty {@link AnnotationAttributes} instance for the
* specified {@code annotationType}.
* @param annotationType the annotation type name represented by this
* {@code AnnotationAttributes} instance; never {@code null}
* @param classLoader the ClassLoader to try to load the annotation type on,
* or {@code null} to just store the annotation type name
* @since 4.3.2
*/
public AnnotationAttributes(String annotationType, @Nullable ClassLoader classLoader) {
this(getAnnotationType(annotationType, classLoader), false);
}

/**
* Create a possibly already validated new, empty
* {@link AnnotationAttributes} instance for the specified
Expand All @@ -143,6 +130,21 @@ public AnnotationAttributes(String annotationType, @Nullable ClassLoader classLo
this.validated = validated;
}

/**
* Create a new, empty {@link AnnotationAttributes} instance for the
* specified {@code annotationType}.
* @param annotationType the annotation type name represented by this
* {@code AnnotationAttributes} instance; never {@code null}
* @param classLoader the ClassLoader to try to load the annotation type on,
* or {@code null} to just store the annotation type name
* @since 4.3.2
*/
public AnnotationAttributes(String annotationType, @Nullable ClassLoader classLoader) {
Assert.notNull(annotationType, "'annotationType' must not be null");
this.annotationType = getAnnotationType(annotationType, classLoader);
this.displayName = annotationType;
this.validated = false;
}

@SuppressWarnings("unchecked")
@Nullable
Expand Down Expand Up @@ -349,39 +351,29 @@ public <A extends Annotation> A[] getAnnotationArray(String attributeName, Class
private <T> T getRequiredAttribute(String attributeName, Class<T> expectedType) {
Assert.hasText(attributeName, "'attributeName' must not be null or empty");
Object value = get(attributeName);
assertAttributePresence(attributeName, value);
assertNotException(attributeName, value);
if (value == null) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' not found in attributes for annotation [%s]",
attributeName, this.displayName));
}
if (value instanceof Throwable throwable) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' for annotation [%s] was not resolvable due to exception [%s]",
attributeName, this.displayName, value), throwable);
}
if (!expectedType.isInstance(value) && expectedType.isArray() &&
expectedType.componentType().isInstance(value)) {
Object array = Array.newInstance(expectedType.componentType(), 1);
Array.set(array, 0, value);
value = array;
}
assertAttributeType(attributeName, value, expectedType);
return (T) value;
}

private void assertAttributePresence(String attributeName, Object attributeValue) {
Assert.notNull(attributeValue, () -> String.format(
"Attribute '%s' not found in attributes for annotation [%s]",
attributeName, this.displayName));
}

private void assertNotException(String attributeName, Object attributeValue) {
if (attributeValue instanceof Throwable throwable) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' for annotation [%s] was not resolvable due to exception [%s]",
attributeName, this.displayName, attributeValue), throwable);
}
}

private void assertAttributeType(String attributeName, Object attributeValue, Class<?> expectedType) {
if (!expectedType.isInstance(attributeValue)) {
if (!expectedType.isInstance(value)) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' is of type %s, but %s was expected in attributes for annotation [%s]",
attributeName, attributeValue.getClass().getSimpleName(), expectedType.getSimpleName(),
attributeName, value.getClass().getSimpleName(), expectedType.getSimpleName(),
this.displayName));
}
return (T) value;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -985,8 +985,12 @@ public static void postProcessAnnotationAttributes(@Nullable Object annotatedEle
}
}

private static Object getAttributeValueForMirrorResolution(Method attribute, Object attributes) {
Object result = ((AnnotationAttributes) attributes).get(attribute.getName());
@Nullable
private static Object getAttributeValueForMirrorResolution(Method attribute, @Nullable Object attributes) {
if (!(attributes instanceof AnnotationAttributes annotationAttributes)) {
return null;
}
Object result = annotationAttributes.get(attribute.getName());
return (result instanceof DefaultValueHolder defaultValueHolder ? defaultValueHolder.defaultValue : result);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,29 +127,31 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
if (result != null) {
return result;
}
Annotation[] declaredAnnotations = getDeclaredAnnotations(source, true);
if (relevant == null && declaredAnnotations.length > 0) {
relevant = root.getAnnotations();
remaining = relevant.length;
}
for (int i = 0; i < declaredAnnotations.length; i++) {
if (declaredAnnotations[i] != null) {
boolean isRelevant = false;
for (int relevantIndex = 0; relevantIndex < relevant.length; relevantIndex++) {
if (relevant[relevantIndex] != null &&
declaredAnnotations[i].annotationType() == relevant[relevantIndex].annotationType()) {
isRelevant = true;
relevant[relevantIndex] = null;
remaining--;
break;
Annotation[] declaredAnns = getDeclaredAnnotations(source, true);
if (declaredAnns.length > 0) {
if (relevant == null) {
relevant = root.getAnnotations();
remaining = relevant.length;
}
for (int i = 0; i < declaredAnns.length; i++) {
if (declaredAnns[i] != null) {
boolean isRelevant = false;
for (int relevantIndex = 0; relevantIndex < relevant.length; relevantIndex++) {
if (relevant[relevantIndex] != null &&
declaredAnns[i].annotationType() == relevant[relevantIndex].annotationType()) {
isRelevant = true;
relevant[relevantIndex] = null;
remaining--;
break;
}
}
if (!isRelevant) {
declaredAnns[i] = null;
}
}
if (!isRelevant) {
declaredAnnotations[i] = null;
}
}
}
result = processor.doWithAnnotations(context, aggregateIndex, source, declaredAnnotations);
result = processor.doWithAnnotations(context, aggregateIndex, source, declaredAnns);
if (result != null) {
return result;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -322,12 +322,13 @@ private <T extends Map<String, Object>> Object adaptValueForMapOptions(Method at
@SuppressWarnings("unchecked")
protected A createSynthesizedAnnotation() {
// Check root annotation
if (isTargetAnnotation(this.rootAttributes) && !isSynthesizable((Annotation) this.rootAttributes)) {
return (A) this.rootAttributes;
if (this.rootAttributes instanceof Annotation ann && isTargetAnnotation(ann) && !isSynthesizable(ann)) {
return (A) ann;
}
// Check meta-annotation
else if (isTargetAnnotation(this.mapping.getAnnotation()) && !isSynthesizable(this.mapping.getAnnotation())) {
return (A) this.mapping.getAnnotation();
Annotation meta = this.mapping.getAnnotation();
if (meta != null && isTargetAnnotation(meta) && !isSynthesizable(meta)) {
return (A) meta;
}
return SynthesizedMergedAnnotationInvocationHandler.createProxy(this, getType());
}
Expand All @@ -338,7 +339,7 @@ else if (isTargetAnnotation(this.mapping.getAnnotation()) && !isSynthesizable(th
* @param obj the object to check
* @since 5.3.22
*/
private boolean isTargetAnnotation(@Nullable Object obj) {
private boolean isTargetAnnotation(Object obj) {
return getType().isInstance(obj);
}

Expand Down Expand Up @@ -432,7 +433,7 @@ private Object getValueFromMetaAnnotation(int attributeIndex, boolean forMirrorR
}

@Nullable
private Object getValueForMirrorResolution(Method attribute, Object annotation) {
private Object getValueForMirrorResolution(Method attribute, @Nullable Object annotation) {
int attributeIndex = this.mapping.getAttributes().indexOf(attribute);
boolean valueAttribute = VALUE.equals(attribute.getName());
return getValue(attributeIndex, !valueAttribute, true);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -95,20 +95,19 @@ default T decode(DataBuffer buffer, ResolvableType targetType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {

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

Throwable failure;
try {
return future.get();
}
catch (ExecutionException ex) {
failure = ex.getCause();
Throwable cause = ex.getCause();
throw (cause instanceof CodecException codecException ? codecException :
new DecodingException("Failed to decode: " + (cause != null ? cause.getMessage() : ex), cause));
}
catch (InterruptedException ex) {
failure = ex;
throw new DecodingException("Interrupted during decode", ex);
}
throw (failure instanceof CodecException codecException ? codecException :
new DecodingException("Failed to decode: " + failure.getMessage(), failure));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -80,6 +80,7 @@ public Resource decode(DataBuffer dataBuffer, ResolvableType elementType,
if (clazz == InputStreamResource.class) {
return new InputStreamResource(new ByteArrayInputStream(bytes)) {
@Override
@Nullable
public String getFilename() {
return filename;
}
Expand All @@ -92,6 +93,7 @@ public long contentLength() {
else if (Resource.class.isAssignableFrom(clazz)) {
return new ByteArrayResource(bytes) {
@Override
@Nullable
public String getFilename() {
return filename;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -136,7 +136,7 @@ static boolean hasConversionMethodOrConstructor(Class<?> targetClass, Class<?> s
@Nullable
private static Executable getValidatedExecutable(Class<?> targetClass, Class<?> sourceClass) {
Executable executable = conversionExecutableCache.get(targetClass);
if (isApplicable(executable, sourceClass)) {
if (executable != null && isApplicable(executable, sourceClass)) {
return executable;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -19,6 +19,7 @@
import java.util.regex.Pattern;

import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;

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

@Override
@Nullable
public Pattern convert(String source) {
if (source.isEmpty()) {
return null;
Expand Down

0 comments on commit 5dc6a16

Please sign in to comment.