org.springframework.core.env.PropertySource Maven / Gradle / Ivy
/*
* Copyright 2002-2017 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 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
* {@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.
*
* {@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}.
*
*
{@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.
*
*
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
* @see PropertySources
* @see PropertyResolver
* @see PropertySourcesPropertyResolver
* @see MutablePropertySources
* @see org.springframework.context.annotation.PropertySource
*/
public abstract class PropertySource {
protected final Log logger = LogFactory.getLog(getClass());
protected final String name;
protected final T source;
/**
* 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 {@code PropertySource} with the given name and with a new
* {@code 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.
*/
@SuppressWarnings("unchecked")
public PropertySource(String name) {
this(name, (T) new Object());
}
/**
* Return the name of this {@code PropertySource}
*/
public String getName() {
return this.name;
}
/**
* Return the underlying source object for this {@code PropertySource}.
*/
public T getSource() {
return this.source;
}
/**
* Return whether this {@code PropertySource} contains the given name.
*
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 {@code null} if not found.
* @param name the property to find
* @see PropertyResolver#getRequiredProperty(String)
*/
@Nullable
public abstract Object getProperty(String name);
/**
* This {@code PropertySource} object is equal to the given object if:
*
* - they are the same instance
*
- the {@code name} properties for both objects are equal
*
* 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 {@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 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 {@code PropertySource} implementation intended for collection comparison purposes only.
*
Primarily for internal use, but given a collection of {@code PropertySource} objects, may be
* used as follows:
*
* {@code List> sources = new ArrayList>();
* 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 {@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);
}
/**
* {@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