/*
* 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);
}
}
}