/*
 * Copyright 2002-2018 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
 *
 *      http://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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

Abstract base class representing a source of name/value property pairs. The underlying source object may be of any type T that encapsulates properties. Examples include Properties objects, Map objects, ServletContext and ServletConfig objects (for access to init parameters). Explore the PropertySource type hierarchy to see provided implementations.

PropertySource objects are not typically used in isolation, but rather through a PropertySources object, which aggregates property sources and in conjunction with a PropertyResolver implementation that can perform precedence-based searches across the set of PropertySources.

PropertySource identity is determined not based on the content of encapsulated properties, but rather based on the name of the PropertySource alone. This is useful for manipulating PropertySource objects when in collection contexts. See operations in MutablePropertySources as well as the named(String) and toString() methods for details.

Note that when working with @Configuration classes that the @PropertySource annotation provides a convenient and declarative way of adding property sources to the enclosing Environment.

Author:Chris Beams
Type parameters:
  • <T> – the source type
See Also:
Since:3.1
/** * Abstract base class representing a source of name/value property pairs. The underlying * {@linkplain #getSource() source object} may be of any type {@code T} that encapsulates * properties. Examples include {@link java.util.Properties} objects, {@link java.util.Map} * objects, {@code ServletContext} and {@code ServletConfig} objects (for access to init * parameters). Explore the {@code PropertySource} type hierarchy to see provided * implementations. * * <p>{@code PropertySource} objects are not typically used in isolation, but rather * through a {@link PropertySources} object, which aggregates property sources and in * conjunction with a {@link PropertyResolver} implementation that can perform * precedence-based searches across the set of {@code PropertySources}. * * <p>{@code PropertySource} identity is determined not based on the content of * encapsulated properties, but rather based on the {@link #getName() name} of the * {@code PropertySource} alone. This is useful for manipulating {@code PropertySource} * objects when in collection contexts. See operations in {@link MutablePropertySources} * as well as the {@link #named(String)} and {@link #toString()} methods for details. * * <p>Note that when working with @{@link * org.springframework.context.annotation.Configuration Configuration} classes that * the @{@link org.springframework.context.annotation.PropertySource PropertySource} * annotation provides a convenient and declarative way of adding property sources to the * enclosing {@code Environment}. * * @author Chris Beams * @since 3.1 * @param <T> the source type * @see PropertySources * @see PropertyResolver * @see PropertySourcesPropertyResolver * @see MutablePropertySources * @see org.springframework.context.annotation.PropertySource */
public abstract class PropertySource<T> { protected final Log logger = LogFactory.getLog(getClass()); protected final String name; protected final T source;
Create a new PropertySource with the given name and source object.
/** * Create a new {@code PropertySource} with the given name and source object. */
public PropertySource(String name, T source) { Assert.hasText(name, "Property source name must contain at least one character"); Assert.notNull(source, "Property source must not be null"); this.name = name; this.source = source; }
Create a new PropertySource with the given name and with a new Object instance as the underlying source.

Often useful in testing scenarios when creating anonymous implementations that never query an actual source but rather return hard-coded values.

/** * Create a new {@code PropertySource} with the given name and with a new * {@code Object} instance as the underlying source. * <p>Often useful in testing scenarios when creating anonymous implementations * that never query an actual source but rather return hard-coded values. */
@SuppressWarnings("unchecked") public PropertySource(String name) { this(name, (T) new Object()); }
Return the name of this PropertySource.
/** * Return the name of this {@code PropertySource}. */
public String getName() { return this.name; }
Return the underlying source object for this PropertySource.
/** * Return the underlying source object for this {@code PropertySource}. */
public T getSource() { return this.source; }
Return whether this PropertySource contains the given name.

This implementation simply checks for a null return value from getProperty(String). Subclasses may wish to implement a more efficient algorithm if possible.

Params:
  • name – the property name to find
/** * Return whether this {@code PropertySource} contains the given name. * <p>This implementation simply checks for a {@code null} return value * from {@link #getProperty(String)}. Subclasses may wish to implement * a more efficient algorithm if possible. * @param name the property name to find */
public boolean containsProperty(String name) { return (getProperty(name) != null); }
Return the value associated with the given name, or null if not found.
Params:
  • name – the property to find
See Also:
/** * Return the value associated with the given name, * or {@code null} if not found. * @param name the property to find * @see PropertyResolver#getRequiredProperty(String) */
@Nullable public abstract Object getProperty(String name);
This PropertySource object is equal to the given object if:
  • they are the same instance
  • the name properties for both objects are equal

No properties other than name are evaluated.

/** * This {@code PropertySource} object is equal to the given object if: * <ul> * <li>they are the same instance * <li>the {@code name} properties for both objects are equal * </ul> * <p>No properties other than {@code name} are evaluated. */
@Override public boolean equals(Object other) { return (this == other || (other instanceof PropertySource && ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) other).name))); }
Return a hash code derived from the name property of this PropertySource object.
/** * Return a hash code derived from the {@code name} property * of this {@code PropertySource} object. */
@Override public int hashCode() { return ObjectUtils.nullSafeHashCode(this.name); }
Produce concise output (type and name) if the current log level does not include debug. If debug is enabled, produce verbose output including the hash code of the PropertySource instance and every name/value property pair.

This variable verbosity is useful as a property source such as system properties or environment variables may contain an arbitrary number of property pairs, potentially leading to difficult to read exception and log messages.

See Also:
  • isDebugEnabled.isDebugEnabled()
/** * Produce concise output (type and name) if the current log level does not include * debug. If debug is enabled, produce verbose output including the hash code of the * PropertySource instance and every name/value property pair. * <p>This variable verbosity is useful as a property source such as system properties * or environment variables may contain an arbitrary number of property pairs, * potentially leading to difficult to read exception and log messages. * @see Log#isDebugEnabled() */
@Override public String toString() { if (logger.isDebugEnabled()) { return getClass().getSimpleName() + "@" + System.identityHashCode(this) + " {name='" + this.name + "', properties=" + this.source + "}"; } else { return getClass().getSimpleName() + " {name='" + this.name + "'}"; } }
Return a PropertySource implementation intended for collection comparison purposes only.

Primarily for internal use, but given a collection of PropertySource objects, may be used as follows:

List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
sources.add(new MapPropertySource("sourceA", mapA));
sources.add(new MapPropertySource("sourceB", mapB));
assert sources.contains(PropertySource.named("sourceA"));
assert sources.contains(PropertySource.named("sourceB"));
assert !sources.contains(PropertySource.named("sourceC"));
The returned PropertySource will throw UnsupportedOperationException if any methods other than equals(Object), hashCode(), and toString() are called.
Params:
  • name – the name of the comparison PropertySource to be created and returned.
/** * Return a {@code PropertySource} implementation intended for collection comparison purposes only. * <p>Primarily for internal use, but given a collection of {@code PropertySource} objects, may be * used as follows: * <pre class="code"> * {@code List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>(); * sources.add(new MapPropertySource("sourceA", mapA)); * sources.add(new MapPropertySource("sourceB", mapB)); * assert sources.contains(PropertySource.named("sourceA")); * assert sources.contains(PropertySource.named("sourceB")); * assert !sources.contains(PropertySource.named("sourceC")); * }</pre> * The returned {@code PropertySource} will throw {@code UnsupportedOperationException} * if any methods other than {@code equals(Object)}, {@code hashCode()}, and {@code toString()} * are called. * @param name the name of the comparison {@code PropertySource} to be created and returned. */
public static PropertySource<?> named(String name) { return new ComparisonPropertySource(name); }
PropertySource to be used as a placeholder in cases where an actual property source cannot be eagerly initialized at application context creation time. For example, a ServletContext-based property source must wait until the ServletContext object is available to its enclosing ApplicationContext. In such cases, a stub should be used to hold the intended default position/order of the property source, then be replaced during context refresh.
See Also:
  • initPropertySources.initPropertySources()
  • StandardServletEnvironment
  • ServletContextPropertySource
/** * {@code PropertySource} to be used as a placeholder in cases where an actual * property source cannot be eagerly initialized at application context * creation time. For example, a {@code ServletContext}-based property source * must wait until the {@code ServletContext} object is available to its enclosing * {@code ApplicationContext}. In such cases, a stub should be used to hold the * intended default position/order of the property source, then be replaced * during context refresh. * @see org.springframework.context.support.AbstractApplicationContext#initPropertySources() * @see org.springframework.web.context.support.StandardServletEnvironment * @see org.springframework.web.context.support.ServletContextPropertySource */
public static class StubPropertySource extends PropertySource<Object> { public StubPropertySource(String name) { super(name, new Object()); }
Always returns null.
/** * Always returns {@code null}. */
@Override @Nullable public String getProperty(String name) { return null; } }
A PropertySource implementation intended for collection comparison purposes.
See Also:
/** * A {@code PropertySource} implementation intended for collection comparison * purposes. * * @see PropertySource#named(String) */
static class ComparisonPropertySource extends StubPropertySource { private static final String USAGE_ERROR = "ComparisonPropertySource instances are for use with collection comparison only"; public ComparisonPropertySource(String name) { super(name); } @Override public Object getSource() { throw new UnsupportedOperationException(USAGE_ERROR); } @Override public boolean containsProperty(String name) { throw new UnsupportedOperationException(USAGE_ERROR); } @Override @Nullable public String getProperty(String name) { throw new UnsupportedOperationException(USAGE_ERROR); } } }