All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.test.context.support.TestPropertySourceUtils Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * 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
 *
 *      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.test.context.support;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.util.TestContextResourceUtils;
import org.springframework.test.util.MetaAnnotationUtils.AnnotationDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptor;

/**
 * Utility methods for working with {@link TestPropertySource @TestPropertySource}
 * and adding test {@link PropertySource PropertySources} to the {@code Environment}.
 *
 * 

Primarily intended for use within the framework. * * @author Sam Brannen * @since 4.1 * @see TestPropertySource */ public abstract class TestPropertySourceUtils { /** * The name of the {@link MapPropertySource} created from inlined properties. * @since 4.1.5 * @see #addInlinedPropertiesToEnvironment */ public static final String INLINED_PROPERTIES_PROPERTY_SOURCE_NAME = "Inlined Test Properties"; private static final Log logger = LogFactory.getLog(TestPropertySourceUtils.class); static MergedTestPropertySources buildMergedTestPropertySources(Class testClass) { Class annotationType = TestPropertySource.class; AnnotationDescriptor descriptor = findAnnotationDescriptor(testClass, annotationType); if (descriptor == null) { return new MergedTestPropertySources(); } List attributesList = resolveTestPropertySourceAttributes(testClass); String[] locations = mergeLocations(attributesList); String[] properties = mergeProperties(attributesList); return new MergedTestPropertySources(locations, properties); } private static List resolveTestPropertySourceAttributes(Class testClass) { Assert.notNull(testClass, "Class must not be null"); List attributesList = new ArrayList<>(); Class annotationType = TestPropertySource.class; AnnotationDescriptor descriptor = findAnnotationDescriptor(testClass, annotationType); Assert.notNull(descriptor, String.format( "Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType.getName(), testClass.getName())); while (descriptor != null) { TestPropertySource testPropertySource = descriptor.synthesizeAnnotation(); Class rootDeclaringClass = descriptor.getRootDeclaringClass(); if (logger.isTraceEnabled()) { logger.trace(String.format("Retrieved @TestPropertySource [%s] for declaring class [%s].", testPropertySource, rootDeclaringClass.getName())); } TestPropertySourceAttributes attributes = new TestPropertySourceAttributes(rootDeclaringClass, testPropertySource); if (logger.isTraceEnabled()) { logger.trace("Resolved TestPropertySource attributes: " + attributes); } attributesList.add(attributes); descriptor = findAnnotationDescriptor(rootDeclaringClass.getSuperclass(), annotationType); } return attributesList; } private static String[] mergeLocations(List attributesList) { List locations = new ArrayList<>(); for (TestPropertySourceAttributes attrs : attributesList) { if (logger.isTraceEnabled()) { logger.trace(String.format("Processing locations for TestPropertySource attributes %s", attrs)); } String[] locationsArray = TestContextResourceUtils.convertToClasspathResourcePaths( attrs.getDeclaringClass(), attrs.getLocations()); locations.addAll(0, Arrays.asList(locationsArray)); if (!attrs.isInheritLocations()) { break; } } return StringUtils.toStringArray(locations); } private static String[] mergeProperties(List attributesList) { List properties = new ArrayList<>(); for (TestPropertySourceAttributes attrs : attributesList) { if (logger.isTraceEnabled()) { logger.trace(String.format("Processing inlined properties for TestPropertySource attributes %s", attrs)); } String[] attrProps = attrs.getProperties(); if (attrProps != null) { properties.addAll(0, Arrays.asList(attrProps)); } if (!attrs.isInheritProperties()) { break; } } return StringUtils.toStringArray(properties); } /** * Add the {@link Properties} files from the given resource {@code locations} * to the {@link Environment} of the supplied {@code context}. *

This method simply delegates to * {@link #addPropertiesFilesToEnvironment(ConfigurableEnvironment, ResourceLoader, String...)}. * @param context the application context whose environment should be updated; * never {@code null} * @param locations the resource locations of {@code Properties} files to add * to the environment; potentially empty but never {@code null} * @throws IllegalStateException if an error occurs while processing a properties file * @since 4.1.5 * @see ResourcePropertySource * @see TestPropertySource#locations * @see #addPropertiesFilesToEnvironment(ConfigurableEnvironment, ResourceLoader, String...) */ public static void addPropertiesFilesToEnvironment(ConfigurableApplicationContext context, String... locations) { Assert.notNull(context, "'context' must not be null"); Assert.notNull(locations, "'locations' must not be null"); addPropertiesFilesToEnvironment(context.getEnvironment(), context, locations); } /** * Add the {@link Properties} files from the given resource {@code locations} * to the supplied {@link ConfigurableEnvironment environment}. *

Property placeholders in resource locations (i.e., ${...}) * will be {@linkplain Environment#resolveRequiredPlaceholders(String) resolved} * against the {@code Environment}. *

Each properties file will be converted to a {@link ResourcePropertySource} * that will be added to the {@link PropertySources} of the environment with * highest precedence. * @param environment the environment to update; never {@code null} * @param resourceLoader the {@code ResourceLoader} to use to load each resource; * never {@code null} * @param locations the resource locations of {@code Properties} files to add * to the environment; potentially empty but never {@code null} * @throws IllegalStateException if an error occurs while processing a properties file * @since 4.3 * @see ResourcePropertySource * @see TestPropertySource#locations * @see #addPropertiesFilesToEnvironment(ConfigurableApplicationContext, String...) */ public static void addPropertiesFilesToEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader, String... locations) { Assert.notNull(environment, "'environment' must not be null"); Assert.notNull(resourceLoader, "'resourceLoader' must not be null"); Assert.notNull(locations, "'locations' must not be null"); try { for (String location : locations) { String resolvedLocation = environment.resolveRequiredPlaceholders(location); Resource resource = resourceLoader.getResource(resolvedLocation); environment.getPropertySources().addFirst(new ResourcePropertySource(resource)); } } catch (IOException ex) { throw new IllegalStateException("Failed to add PropertySource to Environment", ex); } } /** * Add the given inlined properties to the {@link Environment} of the * supplied {@code context}. *

This method simply delegates to * {@link #addInlinedPropertiesToEnvironment(ConfigurableEnvironment, String[])}. * @param context the application context whose environment should be updated; * never {@code null} * @param inlinedProperties the inlined properties to add to the environment; * potentially empty but never {@code null} * @since 4.1.5 * @see TestPropertySource#properties * @see #addInlinedPropertiesToEnvironment(ConfigurableEnvironment, String[]) */ public static void addInlinedPropertiesToEnvironment(ConfigurableApplicationContext context, String... inlinedProperties) { Assert.notNull(context, "'context' must not be null"); Assert.notNull(inlinedProperties, "'inlinedProperties' must not be null"); addInlinedPropertiesToEnvironment(context.getEnvironment(), inlinedProperties); } /** * Add the given inlined properties (in the form of key-value * pairs) to the supplied {@link ConfigurableEnvironment environment}. *

All key-value pairs will be added to the {@code Environment} as a * single {@link MapPropertySource} with the highest precedence. *

For details on the parsing of inlined properties, consult the * Javadoc for {@link #convertInlinedPropertiesToMap}. * @param environment the environment to update; never {@code null} * @param inlinedProperties the inlined properties to add to the environment; * potentially empty but never {@code null} * @since 4.1.5 * @see MapPropertySource * @see #INLINED_PROPERTIES_PROPERTY_SOURCE_NAME * @see TestPropertySource#properties * @see #convertInlinedPropertiesToMap */ public static void addInlinedPropertiesToEnvironment(ConfigurableEnvironment environment, String... inlinedProperties) { Assert.notNull(environment, "'environment' must not be null"); Assert.notNull(inlinedProperties, "'inlinedProperties' must not be null"); if (!ObjectUtils.isEmpty(inlinedProperties)) { if (logger.isDebugEnabled()) { logger.debug("Adding inlined properties to environment: " + ObjectUtils.nullSafeToString(inlinedProperties)); } MapPropertySource ps = (MapPropertySource) environment.getPropertySources().get(INLINED_PROPERTIES_PROPERTY_SOURCE_NAME); if (ps == null) { ps = new MapPropertySource(INLINED_PROPERTIES_PROPERTY_SOURCE_NAME, new LinkedHashMap<>()); environment.getPropertySources().addFirst(ps); } ps.getSource().putAll(convertInlinedPropertiesToMap(inlinedProperties)); } } /** * Convert the supplied inlined properties (in the form of key-value * pairs) into a map keyed by property name, preserving the ordering of property names * in the returned map. *

Parsing of the key-value pairs is achieved by converting all pairs * into virtual properties files in memory and delegating to * {@link Properties#load(java.io.Reader)} to parse each virtual file. *

For a full discussion of inlined properties, consult the Javadoc * for {@link TestPropertySource#properties}. * @param inlinedProperties the inlined properties to convert; potentially empty * but never {@code null} * @return a new, ordered map containing the converted properties * @throws IllegalStateException if a given key-value pair cannot be parsed, or if * a given inlined property contains multiple key-value pairs * @since 4.1.5 * @see #addInlinedPropertiesToEnvironment(ConfigurableEnvironment, String[]) */ public static Map convertInlinedPropertiesToMap(String... inlinedProperties) { Assert.notNull(inlinedProperties, "'inlinedProperties' must not be null"); Map map = new LinkedHashMap<>(); Properties props = new Properties(); for (String pair : inlinedProperties) { if (!StringUtils.hasText(pair)) { continue; } try { props.load(new StringReader(pair)); } catch (Exception ex) { throw new IllegalStateException("Failed to load test environment property from [" + pair + "]", ex); } Assert.state(props.size() == 1, () -> "Failed to load exactly one test environment property from [" + pair + "]"); for (String name : props.stringPropertyNames()) { map.put(name, props.getProperty(name)); } props.clear(); } return map; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy