• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.9
today-context/src/main/java/infra/context/properties/source/DefaultConfigurationPropertySource.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.context.properties.source;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.util.Locale;
23
import java.util.Map;
24
import java.util.Random;
25

26
import infra.context.properties.source.ConfigurationPropertyName.Form;
27
import infra.core.env.EnumerablePropertySource;
28
import infra.core.env.PropertySource;
29
import infra.core.env.StandardEnvironment;
30
import infra.core.env.SystemEnvironmentPropertySource;
31
import infra.lang.Assert;
32
import infra.origin.Origin;
33
import infra.origin.PropertySourceOrigin;
34

35
/**
36
 * {@link ConfigurationPropertySource} backed by a non-enumerable Framework
37
 * {@link PropertySource} or a restricted {@link EnumerablePropertySource} implementation
38
 * (such as a security restricted {@code systemEnvironment} source). A
39
 * {@link PropertySource} is adapted with the help of a {@link PropertyMapper} which
40
 * provides the mapping rules for individual properties.
41
 * <p>
42
 * Each {@link ConfigurationPropertySource#getConfigurationProperty
43
 * getConfigurationProperty} call attempts to
44
 * {@link PropertyMapper#map(ConfigurationPropertyName) map} the
45
 * {@link ConfigurationPropertyName} to one or more {@code String} based names. This
46
 * allows fast property resolution for well formed property sources.
47
 * <p>
48
 * When possible the {@link DefaultIterableConfigurationPropertySource} will be used in
49
 * preference to this implementation since it supports full "relaxed" style resolution.
50
 *
51
 * @author Phillip Webb
52
 * @author Madhura Bhave
53
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
54
 * @see #from(PropertySource)
55
 * @see PropertyMapper
56
 * @see DefaultIterableConfigurationPropertySource
57
 * @since 4.0
58
 */
59
@SuppressWarnings("NullAway")
60
class DefaultConfigurationPropertySource implements ConfigurationPropertySource {
61

62
  private static final PropertyMapper[] DEFAULT_MAPPERS = {
7✔
63
          DefaultPropertyMapper.INSTANCE
64
  };
65

66
  private static final PropertyMapper[] SYSTEM_ENVIRONMENT_MAPPERS = {
12✔
67
          SystemEnvironmentPropertyMapper.INSTANCE,
68
          DefaultPropertyMapper.INSTANCE
69
  };
70

71
  private final PropertySource<?> propertySource;
72

73
  private final boolean systemEnvironmentSource;
74

75
  private final PropertyMapper[] mappers;
76

77
  /**
78
   * Create a new {@link DefaultConfigurationPropertySource} implementation.
79
   *
80
   * @param propertySource the source property source
81
   * @param mappers the property mappers
82
   */
83
  DefaultConfigurationPropertySource(PropertySource<?> propertySource, boolean systemEnvironmentSource, PropertyMapper... mappers) {
2✔
84
    Assert.notNull(propertySource, "PropertySource is required");
3✔
85
    Assert.isTrue(mappers.length > 0, "Mappers must contain at least one item");
7!
86
    this.systemEnvironmentSource = systemEnvironmentSource;
3✔
87
    this.propertySource = propertySource;
3✔
88
    this.mappers = mappers;
3✔
89
  }
1✔
90

91
  @Nullable
92
  @Override
93
  public ConfigurationProperty getConfigurationProperty(@Nullable ConfigurationPropertyName name) {
94
    if (name == null) {
2!
95
      return null;
×
96
    }
97
    for (PropertyMapper mapper : this.mappers) {
17✔
98
      try {
99
        for (String candidate : mapper.map(name)) {
12✔
100
          Object value = getPropertySourceProperty(candidate);
4✔
101
          if (value != null) {
2✔
102
            Origin origin = PropertySourceOrigin.get(this.propertySource, candidate);
5✔
103
            return ConfigurationProperty.of(this, name, value, origin);
6✔
104
          }
105
        }
1✔
106
      }
107
      catch (Exception ignored) {
×
108
      }
1✔
109
    }
110
    return null;
2✔
111
  }
112

113
  @Nullable
114
  protected final Object getPropertySourceProperty(String name) {
115
    // Save calls to SystemEnvironmentPropertySource.resolvePropertyName(...)
116
    // since we've already done the mapping
117
    PropertySource<?> propertySource = getPropertySource();
3✔
118
    return (!this.systemEnvironmentSource) ? propertySource.getProperty(name)
8✔
119
            : getSystemEnvironmentProperty(((SystemEnvironmentPropertySource) propertySource).getSource(), name);
7✔
120
  }
121

122
  Object getSystemEnvironmentProperty(Map<String, Object> systemEnvironment, String name) {
123
    Object value = systemEnvironment.get(name);
×
124
    return value != null ? value : systemEnvironment.get(name.toLowerCase(Locale.ROOT));
×
125
  }
126

127
  @Override
128
  public ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {
129
    PropertySource<?> source = getPropertySource();
3✔
130
    if (source.getSource() instanceof Random) {
4✔
131
      return containsDescendantOfForRandom("random", name);
4✔
132
    }
133
    if (source.getSource() instanceof PropertySource<?>
5✔
134
            && ((PropertySource<?>) source.getSource()).getSource() instanceof Random) {
5!
135
      // Assume wrapped random sources use the source name as the prefix
136
      return containsDescendantOfForRandom(source.getName(), name);
5✔
137
    }
138
    return ConfigurationPropertyState.UNKNOWN;
2✔
139
  }
140

141
  private static ConfigurationPropertyState containsDescendantOfForRandom(
142
          String prefix, ConfigurationPropertyName name) {
143
    if (name.getNumberOfElements() > 1 && name.getElement(0, Form.DASHED).equals(prefix)) {
11✔
144
      return ConfigurationPropertyState.PRESENT;
2✔
145
    }
146
    return ConfigurationPropertyState.ABSENT;
2✔
147
  }
148

149
  @Override
150
  public Object getUnderlyingSource() {
151
    return this.propertySource;
3✔
152
  }
153

154
  protected PropertySource<?> getPropertySource() {
155
    return this.propertySource;
3✔
156
  }
157

158
  protected final boolean isSystemEnvironmentSource() {
159
    return this.systemEnvironmentSource;
3✔
160
  }
161

162
  protected final PropertyMapper[] getMappers() {
163
    return this.mappers;
3✔
164
  }
165

166
  @Override
167
  public String toString() {
168
    return this.propertySource.toString();
×
169
  }
170

171
  /**
172
   * Create a new {@link DefaultConfigurationPropertySource} for the specified
173
   * {@link PropertySource}.
174
   *
175
   * @param source the source Framework {@link PropertySource}
176
   * @return a {@link DefaultConfigurationPropertySource} or
177
   * {@link DefaultIterableConfigurationPropertySource} instance
178
   */
179
  static DefaultConfigurationPropertySource from(PropertySource<?> source) {
180
    Assert.notNull(source, "Source is required");
3✔
181
    boolean systemEnvironmentSource = isSystemEnvironmentPropertySource(source);
3✔
182
    PropertyMapper[] mappers = (!systemEnvironmentSource) ? DEFAULT_MAPPERS : SYSTEM_ENVIRONMENT_MAPPERS;
6✔
183
    return (!isFullEnumerable(source))
4✔
184
            ? new DefaultConfigurationPropertySource(source, systemEnvironmentSource, mappers)
7✔
185
            : new DefaultIterableConfigurationPropertySource((EnumerablePropertySource<?>) source,
7✔
186
                    systemEnvironmentSource, mappers);
187
  }
188

189
  private static boolean isSystemEnvironmentPropertySource(PropertySource<?> source) {
190
    String name = source.getName();
3✔
191
    return (source instanceof SystemEnvironmentPropertySource)
6✔
192
            && (StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME.equals(name)
4✔
193
            || name.endsWith("-" + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME));
5✔
194
  }
195

196
  private static boolean isFullEnumerable(PropertySource<?> source) {
197
    PropertySource<?> rootSource = getRootSource(source);
3✔
198
    if (rootSource.getSource() instanceof Map map) {
9✔
199
      // Check we're not security restricted
200
      try {
201
        map.size();
3✔
202
      }
203
      catch (UnsupportedOperationException ex) {
1✔
204
        return false;
2✔
205
      }
1✔
206
    }
207
    return (source instanceof EnumerablePropertySource);
3✔
208
  }
209

210
  private static PropertySource<?> getRootSource(PropertySource<?> source) {
211
    while (source.getSource() instanceof PropertySource) {
4✔
212
      source = (PropertySource<?>) source.getSource();
5✔
213
    }
214
    return source;
2✔
215
  }
216

217
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc