From c4e9ce8d0ead9a02679ebf262fd8d57b7658619c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 14 Mar 2018 18:53:50 +0100 Subject: [PATCH] Clarified repeatable PropertySource annotation vs use as meta-annotation Issue: SPR-16592 --- .../annotation/AnnotationConfigUtils.java | 11 ++++++++--- .../context/annotation/PropertySource.java | 18 +++++++++++++----- src/docs/asciidoc/core/core-beans.adoc | 9 +++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index 4865d054ba..5a32e6c144 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * 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. @@ -298,18 +298,23 @@ public class AnnotationConfigUtils { } @SuppressWarnings("unchecked") - static Set attributesForRepeatable(AnnotationMetadata metadata, - String containerClassName, String annotationClassName) { + static Set attributesForRepeatable( + AnnotationMetadata metadata, String containerClassName, String annotationClassName) { Set result = new LinkedHashSet<>(); + + // Direct annotation present? addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false)); + // Container annotation present? Map container = metadata.getAnnotationAttributes(containerClassName, false); if (container != null && container.containsKey("value")) { for (Map containedAttributes : (Map[]) container.get("value")) { addAttributesIfNotNull(result, containedAttributes); } } + + // Return merged result return Collections.unmodifiableSet(result); } 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 e423711065..51ca200ebe 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -42,6 +42,7 @@ import org.springframework.core.io.support.PropertySourceFactory; * @Configuration * @PropertySource("classpath:/com/myco/app.properties") * public class AppConfig { + * * @Autowired * Environment env; * @@ -53,8 +54,8 @@ import org.springframework.core.io.support.PropertySourceFactory; * } * } * - * Notice that the {@code Environment} object is @{@link - * org.springframework.beans.factory.annotation.Autowired Autowired} into the + * Notice that the {@code Environment} object is + * {@link org.springframework.beans.factory.annotation.Autowired @Autowired} into the * configuration class and then used when populating the {@code TestBean} object. Given * the configuration above, a call to {@code testBean.getName()} will return "myTestBean". * @@ -79,6 +80,7 @@ import org.springframework.core.io.support.PropertySourceFactory; * @Configuration * @PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties") * public class AppConfig { + * * @Autowired * Environment env; * @@ -118,9 +120,9 @@ import org.springframework.core.io.support.PropertySourceFactory; * * The override ordering depends on the order in which these classes are registered * with the application context. + * *
- * AnnotationConfigApplicationContext ctx =
- *     new AnnotationConfigApplicationContext();
+ * AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
  * ctx.register(ConfigA.class);
  * ctx.register(ConfigB.class);
  * ctx.refresh();
@@ -139,6 +141,12 @@ import org.springframework.core.io.support.PropertySourceFactory;
  * and {@link org.springframework.core.env.MutablePropertySources MutablePropertySources}
  * javadocs for details.
  *
+ * 

NOTE: This annotation is repeatable according to Java 8 conventions. + * However, all such {@code @PropertySource} annotations need to be declared at the same + * level: either directly on the configuration class or as meta-annotations within the + * same custom annotation. Mixing of direct annotations and meta-annotations is not + * recommended since direct annotations will effectively override meta-annotations. + * * @author Chris Beams * @author Juergen Hoeller * @author Phillip Webb diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 9a65fdbcd1..b8651e2878 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -8011,6 +8011,15 @@ be resolved to the corresponding value. If not, then "default/path" will be used as a default. If no default is specified and a property cannot be resolved, an `IllegalArgumentException` will be thrown. +[NOTE] +==== +The `@PropertySource` annotation is repeatable according to Java 8 conventions. +However, all such `@PropertySource` annotations need to be declared at the same +level: either directly on the configuration class or as meta-annotations within the +same custom annotation. Mixing of direct annotations and meta-annotations is not +recommended since direct annotations will effectively override meta-annotations. +==== + === Placeholder resolution in statements -- GitLab