Remove `isImmutable` and `getPrefix` from `OriginLookup`

Drop `isImmutable` and `getPrefix` from `OriginLookup` since
they're not really Origin concerns. Now that `env` is a
foundational layer we can add a dedicated `PropertySourceInfo`
interface and add that to the `o.s.b.env` package without
creating a package tangle.

Closes gh-45547
This commit is contained in:
Phillip Webb 2025-09-16 21:57:03 -07:00
parent 24c25aeae4
commit fc68b001d8
12 changed files with 77 additions and 59 deletions

View File

@ -45,6 +45,9 @@
<subpackage name="ssl">
<disallow pkg="org.springframework.boot" exact-match="true"/>
</subpackage>
<subpackage name="origin">
<disallow pkg="org.springframework.boot" exact-match="true"/>
</subpackage>
<subpackage name="util">
<disallow pkg="org.springframework.boot" exact-match="true"/>
</subpackage>

View File

@ -21,8 +21,7 @@ import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.boot.system.ApplicationPid;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
@ -36,7 +35,7 @@ import org.springframework.util.StringUtils;
*
* @author Moritz Halbritter
*/
class ApplicationInfoPropertySource extends MapPropertySource implements OriginLookup<String> {
class ApplicationInfoPropertySource extends MapPropertySource implements PropertySourceInfo {
static final String NAME = "applicationInfo";
@ -48,11 +47,6 @@ class ApplicationInfoPropertySource extends MapPropertySource implements OriginL
super(NAME, getProperties(applicationVersion));
}
@Override
public @Nullable Origin getOrigin(String key) {
return null;
}
@Override
public boolean isImmutable() {
return true;

View File

@ -31,7 +31,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
@ -454,8 +454,8 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
private static @Nullable ConfigurationPropertySource asConfigurationPropertySource(
PropertySource<?> propertySource) {
ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(propertySource);
if (configurationPropertySource != null && propertySource instanceof OriginLookup<?> originLookup) {
configurationPropertySource = configurationPropertySource.withPrefix(originLookup.getPrefix());
if (configurationPropertySource != null && propertySource instanceof PropertySourceInfo propertySourceInfo) {
configurationPropertySource = configurationPropertySource.withPrefix(propertySourceInfo.getPrefix());
}
return configurationPropertySource;
}

View File

@ -25,7 +25,7 @@ import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
@ -69,8 +69,8 @@ class SpringConfigurationPropertySources implements Iterable<ConfigurationProper
return result;
}
result = SpringConfigurationPropertySource.from(source);
if (source instanceof OriginLookup<?> originLookup) {
result = result.withPrefix(originLookup.getPrefix());
if (source instanceof PropertySourceInfo propertySourceInfo) {
result = result.withPrefix(propertySourceInfo.getPrefix());
}
this.cache.put(source, result);
return result;

View File

@ -32,8 +32,8 @@ import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.origin.PropertySourceOrigin;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.MapPropertySource;
@ -202,8 +202,8 @@ class SpringIterableConfigurationPropertySource extends SpringConfigurationPrope
boolean isImmutablePropertySource() {
EnumerablePropertySource<?> source = getPropertySource();
if (source instanceof OriginLookup<?> originLookup) {
return originLookup.isImmutable();
if (source instanceof PropertySourceInfo propertySourceInfo) {
return propertySourceInfo.isImmutable();
}
if (StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME.equals(source.getName())) {
return source.getSource() == System.getenv();

View File

@ -76,7 +76,8 @@ import org.springframework.util.StringUtils;
* @author Phillip Webb
* @since 2.4.0
*/
public class ConfigTreePropertySource extends EnumerablePropertySource<Path> implements OriginLookup<String> {
public class ConfigTreePropertySource extends EnumerablePropertySource<Path>
implements PropertySourceInfo, OriginLookup<String> {
private static final int MAX_DEPTH = 100;

View File

@ -34,7 +34,8 @@ import org.springframework.core.env.MapPropertySource;
* @since 2.0.0
* @see OriginTrackedValue
*/
public final class OriginTrackedMapPropertySource extends MapPropertySource implements OriginLookup<String> {
public final class OriginTrackedMapPropertySource extends MapPropertySource
implements PropertySourceInfo, OriginLookup<String> {
private final boolean immutable;

View File

@ -0,0 +1,53 @@
/*
* Copyright 2012-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.env;
import org.jspecify.annotations.Nullable;
import org.springframework.core.env.PropertySource;
/**
* Interface that can be optionally implemented by a {@link PropertySource} to provide
* additional information.
*
* @author Phillip Webb
* @since 4.0.0
*/
public interface PropertySourceInfo {
/**
* Return {@code true} if this lookup is immutable and has contents that will never
* change.
* @return if the lookup is immutable
*/
default boolean isImmutable() {
return false;
}
/**
* Return the implicit prefix that is applied when performing a lookup or {@code null}
* if no prefix is used. Prefixes can be used to disambiguate keys that would
* otherwise clash. For example, if multiple applications are running on the same
* machine a different prefix can be set on each application to ensure that different
* environment variables are used.
* @return the prefix applied by the lookup class or {@code null}.
*/
default @Nullable String getPrefix() {
return null;
}
}

View File

@ -37,29 +37,6 @@ public interface OriginLookup<K> {
*/
@Nullable Origin getOrigin(K key);
/**
* Return {@code true} if this lookup is immutable and has contents that will never
* change.
* @return if the lookup is immutable
* @since 2.2.0
*/
default boolean isImmutable() {
return false;
}
/**
* Return the implicit prefix that is applied when performing a lookup or {@code null}
* if no prefix is used. Prefixes can be used to disambiguate keys that would
* otherwise clash. For example, if multiple applications are running on the same
* machine a different prefix can be set on each application to ensure that different
* environment variables are used.
* @return the prefix applied by the lookup class or {@code null}.
* @since 2.5.0
*/
default @Nullable String getPrefix() {
return null;
}
/**
* Attempt to look up the origin from the given source. If the source is not a
* {@link OriginLookup} or if an exception occurs during lookup then {@code null} is

View File

@ -22,6 +22,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.boot.EnvironmentPostProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.origin.SystemEnvironmentOrigin;
@ -81,7 +82,7 @@ public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements
* {@link SystemEnvironmentPropertySource} that also tracks {@link Origin}.
*/
protected static class OriginAwareSystemEnvironmentPropertySource extends SystemEnvironmentPropertySource
implements OriginLookup<String> {
implements PropertySourceInfo, OriginLookup<String> {
private final @Nullable String prefix;

View File

@ -25,8 +25,7 @@ import java.util.function.Function;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
@ -207,7 +206,7 @@ class ConfigurationPropertySourcesTests {
return total;
}
static class TestPropertySource extends MapPropertySource implements OriginLookup<String> {
static class TestPropertySource extends MapPropertySource implements PropertySourceInfo {
private final boolean immutable;
@ -226,11 +225,6 @@ class ConfigurationPropertySourcesTests {
return map;
}
@Override
public Origin getOrigin(String key) {
return null;
}
@Override
public boolean isImmutable() {
return this.immutable;

View File

@ -26,8 +26,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.env.PropertySourceInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.AbstractApplicationContext;
@ -116,7 +115,7 @@ public final class ManagementContextAutoConfiguration {
* {@link EnumerablePropertySource} providing {@code local.management.port} support.
*/
static class LocalManagementPortPropertySource extends EnumerablePropertySource<Object>
implements OriginLookup<String> {
implements PropertySourceInfo {
private static final Map<String, String> PROPERTY_MAPPINGS = Map.of("local.management.port",
"local.server.port");
@ -141,11 +140,6 @@ public final class ManagementContextAutoConfiguration {
return (mapped != null) ? this.environment.getProperty(mapped) : null;
}
@Override
public @Nullable Origin getOrigin(String key) {
return null;
}
@Override
public boolean isImmutable() {
return true;