/*
 * Copyright 2002-2015 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.core.env;

import java.util.Map;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

Specialization of MapPropertySource designed for use with system environment variables. Compensates for constraints in Bash and other shells that do not allow for variables containing the period character and/or hyphen character; also allows for uppercase variations on property names for more idiomatic shell use.

For example, a call to getProperty("foo.bar") will attempt to find a value for the original property or any 'equivalent' property, returning the first found:

  • foo.bar - the original name
  • foo_bar - with underscores for periods (if any)
  • FOO.BAR - original, with upper case
  • FOO_BAR - with underscores and upper case
Any hyphen variant of the above would work as well, or even mix dot/hyphen variants.

The same applies for calls to containsProperty(String), which returns true if any of the above properties are present, otherwise false.

This feature is particularly useful when specifying active or default profiles as environment variables. The following is not allowable under Bash:

spring.profiles.active=p1 java -classpath ... MyApp
However, the following syntax is permitted and is also more conventional:
SPRING_PROFILES_ACTIVE=p1 java -classpath ... MyApp

Enable debug- or trace-level logging for this class (or package) for messages explaining when these 'property name resolutions' occur.

This property source is included by default in StandardEnvironment and all its subclasses.

Author:Chris Beams, Juergen Hoeller
See Also:
Since:3.1
/** * Specialization of {@link MapPropertySource} designed for use with * {@linkplain AbstractEnvironment#getSystemEnvironment() system environment variables}. * Compensates for constraints in Bash and other shells that do not allow for variables * containing the period character and/or hyphen character; also allows for uppercase * variations on property names for more idiomatic shell use. * * <p>For example, a call to {@code getProperty("foo.bar")} will attempt to find a value * for the original property or any 'equivalent' property, returning the first found: * <ul> * <li>{@code foo.bar} - the original name</li> * <li>{@code foo_bar} - with underscores for periods (if any)</li> * <li>{@code FOO.BAR} - original, with upper case</li> * <li>{@code FOO_BAR} - with underscores and upper case</li> * </ul> * Any hyphen variant of the above would work as well, or even mix dot/hyphen variants. * * <p>The same applies for calls to {@link #containsProperty(String)}, which returns * {@code true} if any of the above properties are present, otherwise {@code false}. * * <p>This feature is particularly useful when specifying active or default profiles as * environment variables. The following is not allowable under Bash: * * <pre class="code">spring.profiles.active=p1 java -classpath ... MyApp</pre> * * However, the following syntax is permitted and is also more conventional: * * <pre class="code">SPRING_PROFILES_ACTIVE=p1 java -classpath ... MyApp</pre> * * <p>Enable debug- or trace-level logging for this class (or package) for messages * explaining when these 'property name resolutions' occur. * * <p>This property source is included by default in {@link StandardEnvironment} * and all its subclasses. * * @author Chris Beams * @author Juergen Hoeller * @since 3.1 * @see StandardEnvironment * @see AbstractEnvironment#getSystemEnvironment() * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME */
public class SystemEnvironmentPropertySource extends MapPropertySource {
Create a new SystemEnvironmentPropertySource with the given name and delegating to the given MapPropertySource.
/** * Create a new {@code SystemEnvironmentPropertySource} with the given name and * delegating to the given {@code MapPropertySource}. */
public SystemEnvironmentPropertySource(String name, Map<String, Object> source) { super(name, source); }
Return true if a property with the given name or any underscore/uppercase variant thereof exists in this property source.
/** * Return {@code true} if a property with the given name or any underscore/uppercase variant * thereof exists in this property source. */
@Override public boolean containsProperty(String name) { return (getProperty(name) != null); }
This implementation returns true if a property with the given name or any underscore/uppercase variant thereof exists in this property source.
/** * This implementation returns {@code true} if a property with the given name or * any underscore/uppercase variant thereof exists in this property source. */
@Override @Nullable public Object getProperty(String name) { String actualName = resolvePropertyName(name); if (logger.isDebugEnabled() && !name.equals(actualName)) { logger.debug("PropertySource '" + getName() + "' does not contain property '" + name + "', but found equivalent '" + actualName + "'"); } return super.getProperty(actualName); }
Check to see if this property source contains a property with the given name, or any underscore / uppercase variation thereof. Return the resolved name if one is found or otherwise the original name. Never returns null.
/** * Check to see if this property source contains a property with the given name, or * any underscore / uppercase variation thereof. Return the resolved name if one is * found or otherwise the original name. Never returns {@code null}. */
protected final String resolvePropertyName(String name) { Assert.notNull(name, "Property name must not be null"); String resolvedName = checkPropertyName(name); if (resolvedName != null) { return resolvedName; } String uppercasedName = name.toUpperCase(); if (!name.equals(uppercasedName)) { resolvedName = checkPropertyName(uppercasedName); if (resolvedName != null) { return resolvedName; } } return name; } @Nullable private String checkPropertyName(String name) { // Check name as-is if (containsKey(name)) { return name; } // Check name with just dots replaced String noDotName = name.replace('.', '_'); if (!name.equals(noDotName) && containsKey(noDotName)) { return noDotName; } // Check name with just hyphens replaced String noHyphenName = name.replace('-', '_'); if (!name.equals(noHyphenName) && containsKey(noHyphenName)) { return noHyphenName; } // Check name with dots and hyphens replaced String noDotNoHyphenName = noDotName.replace('-', '_'); if (!noDotName.equals(noDotNoHyphenName) && containsKey(noDotNoHyphenName)) { return noDotNoHyphenName; } // Give up return null; } private boolean containsKey(String name) { return (isSecurityManagerPresent() ? this.source.keySet().contains(name) : this.source.containsKey(name)); } protected boolean isSecurityManagerPresent() { return (System.getSecurityManager() != null); } }