Add nullability annotations to core/spring-boot-properties-migrator

See gh-46587
This commit is contained in:
Moritz Halbritter 2025-07-22 14:02:21 +02:00
parent cb2a26ceec
commit 4ad5d26cda
5 changed files with 32 additions and 16 deletions

View File

@ -21,6 +21,7 @@ import java.io.InputStream;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;
@ -44,7 +45,7 @@ class PropertiesMigrationListener implements ApplicationListener<SpringApplicati
private static final Log logger = LogFactory.getLog(PropertiesMigrationListener.class); private static final Log logger = LogFactory.getLog(PropertiesMigrationListener.class);
private PropertiesMigrationReport report; private @Nullable PropertiesMigrationReport report;
private boolean reported; private boolean reported;

View File

@ -23,6 +23,8 @@ import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
/** /**
* Provides a properties migration report. * Provides a properties migration report.
* *
@ -38,7 +40,7 @@ class PropertiesMigrationReport {
* properties were found, return {@code null}. * properties were found, return {@code null}.
* @return a report with the configurations keys that should be renamed * @return a report with the configurations keys that should be renamed
*/ */
String getWarningReport() { @Nullable String getWarningReport() {
Map<String, List<PropertyMigration>> content = getContent(LegacyProperties::getRenamed); Map<String, List<PropertyMigration>> content = getContent(LegacyProperties::getRenamed);
if (content.isEmpty()) { if (content.isEmpty()) {
return null; return null;
@ -60,7 +62,7 @@ class PropertiesMigrationReport {
* properties were found, return {@code null}. * properties were found, return {@code null}.
* @return a report with the configurations keys that are no longer supported * @return a report with the configurations keys that are no longer supported
*/ */
String getErrorReport() { @Nullable String getErrorReport() {
Map<String, List<PropertyMigration>> content = getContent(LegacyProperties::getUnsupported); Map<String, List<PropertyMigration>> content = getContent(LegacyProperties::getUnsupported);
if (content.isEmpty()) { if (content.isEmpty()) {
return null; return null;

View File

@ -26,6 +26,8 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
import org.springframework.boot.context.properties.source.ConfigurationProperty; import org.springframework.boot.context.properties.source.ConfigurationProperty;
@ -38,6 +40,7 @@ import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.PropertySourceOrigin; import org.springframework.boot.origin.PropertySourceOrigin;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -109,7 +112,9 @@ class PropertiesMigrationReporter {
if (source.getUnderlyingSource() instanceof PropertySource<?> underlyingSource) { if (source.getUnderlyingSource() instanceof PropertySource<?> underlyingSource) {
return underlyingSource.getName(); return underlyingSource.getName();
} }
return source.getUnderlyingSource().toString(); Object underlyingSource = source.getUnderlyingSource();
Assert.state(underlyingSource != null, "'underlyingSource' must not be null");
return underlyingSource.toString();
} }
private List<PropertyMigration> getMigrations(ConfigurationPropertySource propertySource, private List<PropertyMigration> getMigrations(ConfigurationPropertySource propertySource,
@ -149,7 +154,8 @@ class PropertiesMigrationReporter {
&& Objects.equals(propertySourceOrigin.getPropertyName(), replacement.getId()); && Objects.equals(propertySourceOrigin.getPropertyName(), replacement.getId());
} }
private ConfigurationMetadataProperty determineReplacementMetadata(ConfigurationMetadataProperty metadata) { private @Nullable ConfigurationMetadataProperty determineReplacementMetadata(
ConfigurationMetadataProperty metadata) {
String replacementId = metadata.getDeprecation().getReplacement(); String replacementId = metadata.getDeprecation().getReplacement();
if (StringUtils.hasText(replacementId)) { if (StringUtils.hasText(replacementId)) {
ConfigurationMetadataProperty replacement = this.allProperties.get(replacementId); ConfigurationMetadataProperty replacement = this.allProperties.get(replacementId);
@ -161,7 +167,7 @@ class PropertiesMigrationReporter {
return null; return null;
} }
private ConfigurationMetadataProperty detectMapValueReplacement(String fullId) { private @Nullable ConfigurationMetadataProperty detectMapValueReplacement(String fullId) {
int lastDot = fullId.lastIndexOf('.'); int lastDot = fullId.lastIndexOf('.');
if (lastDot == -1) { if (lastDot == -1) {
return null; return null;
@ -178,7 +184,7 @@ class PropertiesMigrationReporter {
return type != null && type.startsWith(Map.class.getName()); return type != null && type.startsWith(Map.class.getName());
} }
private PropertySource<?> mapPropertiesWithReplacement(PropertiesMigrationReport report, String name, private @Nullable PropertySource<?> mapPropertiesWithReplacement(PropertiesMigrationReport report, String name,
List<PropertyMigration> properties) { List<PropertyMigration> properties) {
report.add(name, properties); report.add(name, properties);
List<PropertyMigration> renamed = properties.stream().filter(PropertyMigration::isCompatibleType).toList(); List<PropertyMigration> renamed = properties.stream().filter(PropertyMigration::isCompatibleType).toList();
@ -229,7 +235,7 @@ class PropertiesMigrationReporter {
} }
@Override @Override
public Object getProperty(String name) { public @Nullable Object getProperty(String name) {
this.accessedNames.add(name); this.accessedNames.add(name);
return null; return null;
} }

View File

@ -20,6 +20,8 @@ import java.time.Duration;
import java.util.Comparator; import java.util.Comparator;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
import org.springframework.boot.configurationmetadata.Deprecation; import org.springframework.boot.configurationmetadata.Deprecation;
import org.springframework.boot.context.properties.source.ConfigurationProperty; import org.springframework.boot.context.properties.source.ConfigurationProperty;
@ -43,11 +45,11 @@ class PropertyMigration {
private final ConfigurationProperty property; private final ConfigurationProperty property;
private final Integer lineNumber; private final @Nullable Integer lineNumber;
private final ConfigurationMetadataProperty metadata; private final ConfigurationMetadataProperty metadata;
private final ConfigurationMetadataProperty replacementMetadata; private final @Nullable ConfigurationMetadataProperty replacementMetadata;
/** /**
* Whether this migration happened from a map type. * Whether this migration happened from a map type.
@ -57,7 +59,7 @@ class PropertyMigration {
private final boolean compatibleType; private final boolean compatibleType;
PropertyMigration(ConfigurationProperty property, ConfigurationMetadataProperty metadata, PropertyMigration(ConfigurationProperty property, ConfigurationMetadataProperty metadata,
ConfigurationMetadataProperty replacementMetadata, boolean mapMigration) { @Nullable ConfigurationMetadataProperty replacementMetadata, boolean mapMigration) {
this.property = property; this.property = property;
this.lineNumber = determineLineNumber(property); this.lineNumber = determineLineNumber(property);
this.metadata = metadata; this.metadata = metadata;
@ -66,7 +68,7 @@ class PropertyMigration {
this.compatibleType = determineCompatibleType(metadata, replacementMetadata); this.compatibleType = determineCompatibleType(metadata, replacementMetadata);
} }
private static Integer determineLineNumber(ConfigurationProperty property) { private static @Nullable Integer determineLineNumber(ConfigurationProperty property) {
Origin origin = property.getOrigin(); Origin origin = property.getOrigin();
if (origin instanceof PropertySourceOrigin propertySourceOrigin) { if (origin instanceof PropertySourceOrigin propertySourceOrigin) {
origin = propertySourceOrigin.getOrigin(); origin = propertySourceOrigin.getOrigin();
@ -80,7 +82,7 @@ class PropertyMigration {
} }
private static boolean determineCompatibleType(ConfigurationMetadataProperty metadata, private static boolean determineCompatibleType(ConfigurationMetadataProperty metadata,
ConfigurationMetadataProperty replacementMetadata) { @Nullable ConfigurationMetadataProperty replacementMetadata) {
String currentType = determineType(metadata); String currentType = determineType(metadata);
String replacementType = determineType(replacementMetadata); String replacementType = determineType(replacementMetadata);
if (currentType == null || replacementType == null) { if (currentType == null || replacementType == null) {
@ -93,7 +95,7 @@ class PropertyMigration {
&& (currentType.equals(Long.class.getName()) || currentType.equals(Integer.class.getName())); && (currentType.equals(Long.class.getName()) || currentType.equals(Integer.class.getName()));
} }
private static String determineType(ConfigurationMetadataProperty metadata) { private static @Nullable String determineType(@Nullable ConfigurationMetadataProperty metadata) {
if (metadata == null || metadata.getType() == null) { if (metadata == null || metadata.getType() == null) {
return null; return null;
} }
@ -112,7 +114,7 @@ class PropertyMigration {
return this.property; return this.property;
} }
Integer getLineNumber() { @Nullable Integer getLineNumber() {
return this.lineNumber; return this.lineNumber;
} }
@ -126,7 +128,9 @@ class PropertyMigration {
String getNewPropertyName() { String getNewPropertyName() {
if (this.mapMigration) { if (this.mapMigration) {
return getNewMapPropertyName(this.property, this.metadata, this.replacementMetadata).toString(); ConfigurationMetadataProperty replacementMetadata = this.replacementMetadata;
Assert.state(replacementMetadata != null, "'replacementMetadata' must not be null");
return getNewMapPropertyName(this.property, this.metadata, replacementMetadata).toString();
} }
return this.metadata.getDeprecation().getReplacement(); return this.metadata.getDeprecation().getReplacement();
} }

View File

@ -17,4 +17,7 @@
/** /**
* Support for migrating legacy Spring Boot properties. * Support for migrating legacy Spring Boot properties.
*/ */
@NullMarked
package org.springframework.boot.context.properties.migrator; package org.springframework.boot.context.properties.migrator;
import org.jspecify.annotations.NullMarked;