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}