diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index f9c204d4225f..5f164c4db1d8 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -16,9 +16,11 @@ package org.springframework.context.annotation; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Annotation; +import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayDeque; import java.util.ArrayList; @@ -35,6 +37,8 @@ import java.util.Set; import java.util.StringJoiner; import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -455,6 +459,8 @@ private void processPropertySource(AnnotationAttributes propertySource) throws I PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ? DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass)); + locations = getWildcardLocations(locations); + for (String location : locations) { try { String resolvedLocation = this.environment.resolveRequiredPlaceholders(location); @@ -475,6 +481,32 @@ private void processPropertySource(AnnotationAttributes propertySource) throws I } } + /** + * Parse locations and expand those with wildcard + */ + private String[] getWildcardLocations(String[] locations) throws IOException { + List filesNames = new ArrayList<>(); + Pattern allFiles = Pattern.compile("(.*[/:])\\*(\\.[a-zA-Z0-9]*)$"); + for(String location : locations){ + Matcher matcher = allFiles.matcher(location); + if(matcher.matches()){ + String folderName = matcher.group(1); + String extension = matcher.group(2); + File folder = this.resourceLoader.getResource(folderName).getFile(); + File[] files = folder.listFiles(); + for (File file : files){ + if(file.getName().endsWith(extension)){ + filesNames.add("file:"+file.getPath()); + } + } + } else { + filesNames.add(location); + } + } + + return filesNames.toArray(new String[filesNames.size()]); + } + private void addPropertySource(PropertySource propertySource) { String name = propertySource.getName(); MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources(); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/PropertySource.java b/spring-context/src/main/java/org/springframework/context/annotation/PropertySource.java index ad7d3f410815..61682019be9f 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/PropertySource.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/PropertySource.java @@ -59,6 +59,28 @@ * configuration class and then used when populating the {@code TestBean} object. Given * the configuration above, a call to {@code testBean.getName()} will return "myTestBean". * + *

Given a folder with several files with the same extension containing the key/value pair + * {@code testbean.name=myTestBean}, the following {@code @Configuration} class + * uses {@code @PropertySource} to contribute all {@code *.properties} to the + * {@code Environment}'s set of {@code PropertySources}.

+ * + * + *
+ * @Configuration
+ * @PropertySource("classpath:/com/myco/*.properties")
+ * public class AppConfig {
+ *
+ *     @Autowired
+ *     Environment env;
+ *
+ *     @Bean
+ *     public TestBean testBean() {
+ *         TestBean testBean = new TestBean();
+ *         testBean.setName(env.getProperty("testbean.name"));
+ *         return testBean;
+ *     }
+ * }
+ * *

Resolving ${...} placeholders in {@code } and {@code @Value} annotations

* *

In order to resolve ${...} placeholders in {@code } definitions or {@code @Value} @@ -156,12 +178,12 @@ * @author Juergen Hoeller * @author Phillip Webb * @author Sam Brannen - * @since 3.1 * @see PropertySources * @see Configuration * @see org.springframework.core.env.PropertySource * @see org.springframework.core.env.ConfigurableEnvironment#getPropertySources() * @see org.springframework.core.env.MutablePropertySources + * @since 3.1 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -172,6 +194,7 @@ /** * Indicate the name of this property source. If omitted, a name will * be generated based on the description of the underlying resource. + * * @see org.springframework.core.env.PropertySource#getName() * @see org.springframework.core.io.Resource#getDescription() */ @@ -197,12 +220,14 @@ * ignored. *

{@code true} is appropriate if the properties file is completely optional. * Default is {@code false}. + * * @since 4.0 */ boolean ignoreResourceNotFound() default false; /** * A specific character encoding for the given resources, e.g. "UTF-8". + * * @since 4.3 */ String encoding() default ""; @@ -210,9 +235,10 @@ /** * Specify a custom {@link PropertySourceFactory}, if any. *

By default, a default factory for standard resource files will be used. - * @since 4.3 + * * @see org.springframework.core.io.support.DefaultPropertySourceFactory * @see org.springframework.core.io.support.ResourcePropertySource + * @since 4.3 */ Class factory() default PropertySourceFactory.class;