001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core.env;
018
019import org.springframework.lang.Nullable;
020
021/**
022 * {@link PropertyResolver} implementation that resolves property values against
023 * an underlying set of {@link PropertySources}.
024 *
025 * @author Chris Beams
026 * @author Juergen Hoeller
027 * @since 3.1
028 * @see PropertySource
029 * @see PropertySources
030 * @see AbstractEnvironment
031 */
032public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
033
034        @Nullable
035        private final PropertySources propertySources;
036
037
038        /**
039         * Create a new resolver against the given property sources.
040         * @param propertySources the set of {@link PropertySource} objects to use
041         */
042        public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {
043                this.propertySources = propertySources;
044        }
045
046
047        @Override
048        public boolean containsProperty(String key) {
049                if (this.propertySources != null) {
050                        for (PropertySource<?> propertySource : this.propertySources) {
051                                if (propertySource.containsProperty(key)) {
052                                        return true;
053                                }
054                        }
055                }
056                return false;
057        }
058
059        @Override
060        @Nullable
061        public String getProperty(String key) {
062                return getProperty(key, String.class, true);
063        }
064
065        @Override
066        @Nullable
067        public <T> T getProperty(String key, Class<T> targetValueType) {
068                return getProperty(key, targetValueType, true);
069        }
070
071        @Override
072        @Nullable
073        protected String getPropertyAsRawString(String key) {
074                return getProperty(key, String.class, false);
075        }
076
077        @Nullable
078        protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
079                if (this.propertySources != null) {
080                        for (PropertySource<?> propertySource : this.propertySources) {
081                                if (logger.isTraceEnabled()) {
082                                        logger.trace("Searching for key '" + key + "' in PropertySource '" +
083                                                        propertySource.getName() + "'");
084                                }
085                                Object value = propertySource.getProperty(key);
086                                if (value != null) {
087                                        if (resolveNestedPlaceholders && value instanceof String) {
088                                                value = resolveNestedPlaceholders((String) value);
089                                        }
090                                        logKeyFound(key, propertySource, value);
091                                        return convertValueIfNecessary(value, targetValueType);
092                                }
093                        }
094                }
095                if (logger.isTraceEnabled()) {
096                        logger.trace("Could not find key '" + key + "' in any property source");
097                }
098                return null;
099        }
100
101        /**
102         * Log the given key as found in the given {@link PropertySource}, resulting in
103         * the given value.
104         * <p>The default implementation writes a debug log message with key and source.
105         * As of 4.3.3, this does not log the value anymore in order to avoid accidental
106         * logging of sensitive settings. Subclasses may override this method to change
107         * the log level and/or log message, including the property's value if desired.
108         * @param key the key found
109         * @param propertySource the {@code PropertySource} that the key has been found in
110         * @param value the corresponding value
111         * @since 4.3.1
112         */
113        protected void logKeyFound(String key, PropertySource<?> propertySource, Object value) {
114                if (logger.isDebugEnabled()) {
115                        logger.debug("Found key '" + key + "' in PropertySource '" + propertySource.getName() +
116                                        "' with value of type " + value.getClass().getSimpleName());
117                }
118        }
119
120}