Skip to content

Commit c531a8a

Browse files
committed
Nullability refinements and related polishing
See gh-32475
1 parent cd7ba18 commit c531a8a

File tree

58 files changed

+327
-257
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+327
-257
lines changed

spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -364,18 +364,18 @@ public static Object invokeJoinpointUsingReflection(@Nullable Object target, Met
364364
}
365365
}
366366

367+
367368
/**
368369
* Inner class to avoid a hard dependency on Kotlin at runtime.
369370
*/
370371
private static class KotlinDelegate {
371372

372-
public static Publisher<?> invokeSuspendingFunction(Method method, Object target, Object... args) {
373+
public static Publisher<?> invokeSuspendingFunction(Method method, @Nullable Object target, Object... args) {
373374
Continuation<?> continuation = (Continuation<?>) args[args.length -1];
374375
Assert.state(continuation != null, "No Continuation available");
375376
CoroutineContext context = continuation.getContext().minusKey(Job.Key);
376377
return CoroutinesUtils.invokeSuspendingFunction(context, method, target, args);
377378
}
378-
379379
}
380380

381381
}

spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java

+7-5
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.
@@ -845,8 +845,10 @@ protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(St
845845
* @return the PropertyAccessor instance, either cached or newly created
846846
*/
847847
private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
848-
if (this.nestedPropertyAccessors == null) {
849-
this.nestedPropertyAccessors = new HashMap<>();
848+
Map<String, AbstractNestablePropertyAccessor> nestedAccessors = this.nestedPropertyAccessors;
849+
if (nestedAccessors == null) {
850+
nestedAccessors = new HashMap<>();
851+
this.nestedPropertyAccessors = nestedAccessors;
850852
}
851853
// Get value of bean property.
852854
PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
@@ -862,7 +864,7 @@ private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nested
862864
}
863865

864866
// Lookup cached sub-PropertyAccessor, create new one if not found.
865-
AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);
867+
AbstractNestablePropertyAccessor nestedPa = nestedAccessors.get(canonicalName);
866868
if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
867869
if (logger.isTraceEnabled()) {
868870
logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
@@ -871,7 +873,7 @@ private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nested
871873
// Inherit all type-specific PropertyEditors.
872874
copyDefaultEditorsTo(nestedPa);
873875
copyCustomEditorsTo(nestedPa, canonicalName);
874-
this.nestedPropertyAccessors.put(canonicalName, nestedPa);
876+
nestedAccessors.put(canonicalName, nestedPa);
875877
}
876878
else {
877879
if (logger.isTraceEnabled()) {

spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java

+12-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.
@@ -54,6 +54,7 @@
5454
import org.springframework.core.io.Resource;
5555
import org.springframework.core.io.support.EncodedResource;
5656
import org.springframework.lang.Nullable;
57+
import org.springframework.util.Assert;
5758
import org.springframework.util.ObjectUtils;
5859
import org.springframework.util.StringUtils;
5960

@@ -250,6 +251,7 @@ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefin
250251
@SuppressWarnings("serial")
251252
Closure<Object> beans = new Closure<>(this) {
252253
@Override
254+
@Nullable
253255
public Object call(Object... args) {
254256
invokeBeanDefiningClosure((Closure<?>) args[0]);
255257
return null;
@@ -425,6 +427,7 @@ else if (args.length > 1 && args[args.length -1] instanceof Closure) {
425427

426428
private boolean addDeferredProperty(String property, Object newValue) {
427429
if (newValue instanceof List || newValue instanceof Map) {
430+
Assert.state(this.currentBeanDefinition != null, "No current bean definition set");
428431
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
429432
new DeferredProperty(this.currentBeanDefinition, property, newValue));
430433
return true;
@@ -640,6 +643,7 @@ else if (value instanceof Closure<?> callable) {
640643
this.currentBeanDefinition = current;
641644
}
642645
}
646+
Assert.state(this.currentBeanDefinition != null, "No current bean definition set");
643647
this.currentBeanDefinition.addProperty(name, value);
644648
}
645649

@@ -654,6 +658,7 @@ else if (value instanceof Closure<?> callable) {
654658
* </ul>
655659
*/
656660
@Override
661+
@Nullable
657662
public Object getProperty(String name) {
658663
Binding binding = getBinding();
659664
if (binding != null && binding.hasVariable(name)) {
@@ -727,9 +732,10 @@ private static class DeferredProperty {
727732

728733
private final String name;
729734

735+
@Nullable
730736
public Object value;
731737

732-
public DeferredProperty(GroovyBeanDefinitionWrapper beanDefinition, String name, Object value) {
738+
public DeferredProperty(GroovyBeanDefinitionWrapper beanDefinition, String name, @Nullable Object value) {
733739
this.beanDefinition = beanDefinition;
734740
this.name = name;
735741
this.value = value;
@@ -762,20 +768,18 @@ public MetaClass getMetaClass() {
762768
}
763769

764770
@Override
771+
@Nullable
765772
public Object getProperty(String property) {
766773
if (property.equals("beanName")) {
767774
return getBeanName();
768775
}
769776
else if (property.equals("source")) {
770777
return getSource();
771778
}
772-
else if (this.beanDefinition != null) {
779+
else {
773780
return new GroovyPropertyValue(
774781
property, this.beanDefinition.getBeanDefinition().getPropertyValues().get(property));
775782
}
776-
else {
777-
return this.metaClass.getProperty(this, property);
778-
}
779783
}
780784

781785
@Override
@@ -804,9 +808,10 @@ private class GroovyPropertyValue extends GroovyObjectSupport {
804808

805809
private final String propertyName;
806810

811+
@Nullable
807812
private final Object propertyValue;
808813

809-
public GroovyPropertyValue(String propertyName, Object propertyValue) {
814+
public GroovyPropertyValue(String propertyName, @Nullable Object propertyValue) {
810815
this.propertyName = propertyName;
811816
this.propertyValue = propertyValue;
812817
}

spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionWrapper.java

+9-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.
@@ -84,7 +84,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
8484
this(beanName, clazz, null);
8585
}
8686

87-
GroovyBeanDefinitionWrapper(@Nullable String beanName, Class<?> clazz, @Nullable Collection<?> constructorArgs) {
87+
GroovyBeanDefinitionWrapper(@Nullable String beanName, @Nullable Class<?> clazz, @Nullable Collection<?> constructorArgs) {
8888
this.beanName = beanName;
8989
this.clazz = clazz;
9090
this.constructorArgs = constructorArgs;
@@ -130,11 +130,12 @@ void setBeanDefinitionHolder(BeanDefinitionHolder holder) {
130130
}
131131

132132
BeanDefinitionHolder getBeanDefinitionHolder() {
133-
return new BeanDefinitionHolder(getBeanDefinition(), getBeanName());
133+
Assert.state(this.beanName != null, "Bean name must be set");
134+
return new BeanDefinitionHolder(getBeanDefinition(), this.beanName);
134135
}
135136

136-
void setParent(Object obj) {
137-
Assert.notNull(obj, "Parent bean cannot be set to a null runtime bean reference.");
137+
void setParent(@Nullable Object obj) {
138+
Assert.notNull(obj, "Parent bean cannot be set to a null runtime bean reference");
138139
if (obj instanceof String name) {
139140
this.parentName = name;
140141
}
@@ -148,7 +149,7 @@ else if (obj instanceof GroovyBeanDefinitionWrapper wrapper) {
148149
getBeanDefinition().setAbstract(false);
149150
}
150151

151-
GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
152+
GroovyBeanDefinitionWrapper addProperty(String propertyName, @Nullable Object propertyValue) {
152153
if (propertyValue instanceof GroovyBeanDefinitionWrapper wrapper) {
153154
propertyValue = wrapper.getBeanDefinition();
154155
}
@@ -158,6 +159,7 @@ GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValu
158159

159160

160161
@Override
162+
@Nullable
161163
public Object getProperty(String property) {
162164
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
163165
if (this.definitionWrapper.isReadableProperty(property)) {
@@ -170,7 +172,7 @@ else if (dynamicProperties.contains(property)) {
170172
}
171173

172174
@Override
173-
public void setProperty(String property, Object newValue) {
175+
public void setProperty(String property, @Nullable Object newValue) {
174176
if (PARENT.equals(property)) {
175177
setParent(newValue);
176178
}

spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java

+2-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.
@@ -638,7 +638,7 @@ boolean hasAnyExternallyManagedDestroyMethod(String destroyMethod) {
638638
}
639639
}
640640

641-
private static boolean hasAnyExternallyManagedMethod(Set<String> candidates, String methodName) {
641+
private static boolean hasAnyExternallyManagedMethod(@Nullable Set<String> candidates, String methodName) {
642642
if (candidates != null) {
643643
for (String candidate : candidates) {
644644
int indexOfDot = candidate.lastIndexOf('.');

spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 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.
@@ -126,9 +126,10 @@ protected void doRegisterBeanDefinitions(Element root) {
126126
// then ultimately reset this.delegate back to its original (parent) reference.
127127
// this behavior emulates a stack of delegates without actually necessitating one.
128128
BeanDefinitionParserDelegate parent = this.delegate;
129-
this.delegate = createDelegate(getReaderContext(), root, parent);
129+
BeanDefinitionParserDelegate current = createDelegate(getReaderContext(), root, parent);
130+
this.delegate = current;
130131

131-
if (this.delegate.isDefaultNamespace(root)) {
132+
if (current.isDefaultNamespace(root)) {
132133
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
133134
if (StringUtils.hasText(profileSpec)) {
134135
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
@@ -146,7 +147,7 @@ protected void doRegisterBeanDefinitions(Element root) {
146147
}
147148

148149
preProcessXml(root);
149-
parseBeanDefinitions(root, this.delegate);
150+
parseBeanDefinitions(root, current);
150151
postProcessXml(root);
151152

152153
this.delegate = parent;

spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java

+8-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.
@@ -1096,7 +1096,13 @@ public Object executeSynchronized(CacheOperationInvoker invoker, Method method,
10961096
}
10971097
}
10981098
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isSuspendingFunction(method)) {
1099-
return Mono.fromFuture(cache.retrieve(key, () -> ((Mono<?>) invokeOperation(invoker)).toFuture()));
1099+
return Mono.fromFuture(cache.retrieve(key, () -> {
1100+
Mono<?> mono = ((Mono<?>) invokeOperation(invoker));
1101+
if (mono == null) {
1102+
mono = Mono.empty();
1103+
}
1104+
return mono.toFuture();
1105+
}));
11001106
}
11011107
return NOT_HANDLED;
11021108
}

spring-context/src/main/java/org/springframework/cache/interceptor/CacheInterceptor.java

+3-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.
@@ -78,12 +78,13 @@ public Object invoke(final MethodInvocation invocation) throws Throwable {
7878
}
7979
}
8080

81+
8182
/**
8283
* Inner class to avoid a hard dependency on Kotlin at runtime.
8384
*/
8485
private static class KotlinDelegate {
8586

86-
public static Publisher<?> invokeSuspendingFunction(Method method, Object target, Object... args) {
87+
public static Publisher<?> invokeSuspendingFunction(Method method, @Nullable Object target, Object... args) {
8788
Continuation<?> continuation = (Continuation<?>) args[args.length - 1];
8889
CoroutineContext coroutineContext = continuation.getContext().minusKey(Job.Key);
8990
return CoroutinesUtils.invokeSuspendingFunction(coroutineContext, method, target, args);

spring-context/src/main/java/org/springframework/context/aot/AbstractAotProcessor.java

+5-5
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.
@@ -257,6 +257,7 @@ public Builder classOutput(Path classOutput) {
257257
* @return this builder for method chaining
258258
*/
259259
public Builder groupId(String groupId) {
260+
Assert.hasText(groupId, "'groupId' must not be empty");
260261
this.groupId = groupId;
261262
return this;
262263
}
@@ -268,6 +269,7 @@ public Builder groupId(String groupId) {
268269
* @return this builder for method chaining
269270
*/
270271
public Builder artifactId(String artifactId) {
272+
Assert.hasText(artifactId, "'artifactId' must not be empty");
271273
this.artifactId = artifactId;
272274
return this;
273275
}
@@ -279,14 +281,12 @@ public Settings build() {
279281
Assert.notNull(this.sourceOutput, "'sourceOutput' must not be null");
280282
Assert.notNull(this.resourceOutput, "'resourceOutput' must not be null");
281283
Assert.notNull(this.classOutput, "'classOutput' must not be null");
282-
Assert.hasText(this.groupId, "'groupId' must not be null or empty");
283-
Assert.hasText(this.artifactId, "'artifactId' must not be null or empty");
284+
Assert.notNull(this.groupId, "'groupId' must not be null");
285+
Assert.notNull(this.artifactId, "'artifactId' must not be null");
284286
return new Settings(this.sourceOutput, this.resourceOutput, this.classOutput,
285287
this.groupId, this.artifactId);
286288
}
287-
288289
}
289-
290290
}
291291

292292
}

spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java

+3-3
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.
@@ -318,8 +318,8 @@ else if (result instanceof org.springframework.util.concurrent.ListenableFuture<
318318
}
319319
}
320320

321-
private void publishEvents(Object result) {
322-
if (result.getClass().isArray()) {
321+
private void publishEvents(@Nullable Object result) {
322+
if (result != null && result.getClass().isArray()) {
323323
Object[] events = ObjectUtils.toObjectArray(result);
324324
for (Object event : events) {
325325
publishEvent(event);

spring-context/src/main/java/org/springframework/jmx/access/MBeanProxyFactoryBean.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 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.
@@ -83,18 +83,21 @@ public void setBeanClassLoader(ClassLoader classLoader) {
8383
public void afterPropertiesSet() throws MBeanServerNotFoundException, MBeanInfoRetrievalException {
8484
super.afterPropertiesSet();
8585

86+
Class<?> interfaceToUse;
8687
if (this.proxyInterface == null) {
87-
this.proxyInterface = getManagementInterface();
88-
if (this.proxyInterface == null) {
88+
interfaceToUse = getManagementInterface();
89+
if (interfaceToUse == null) {
8990
throw new IllegalArgumentException("Property 'proxyInterface' or 'managementInterface' is required");
9091
}
92+
this.proxyInterface = interfaceToUse;
9193
}
9294
else {
95+
interfaceToUse = this.proxyInterface;
9396
if (getManagementInterface() == null) {
94-
setManagementInterface(this.proxyInterface);
97+
setManagementInterface(interfaceToUse);
9598
}
9699
}
97-
this.mbeanProxy = new ProxyFactory(this.proxyInterface, this).getProxy(this.beanClassLoader);
100+
this.mbeanProxy = new ProxyFactory(interfaceToUse, this).getProxy(this.beanClassLoader);
98101
}
99102

100103

0 commit comments

Comments
 (0)