41
41
* {@code TestPropertySourceAttributes} also enforces configuration rules.
42
42
*
43
43
* @author Sam Brannen
44
+ * @author Phillip Webb
44
45
* @since 4.1
45
46
* @see TestPropertySource
46
47
* @see MergedTestPropertySources
@@ -54,54 +55,85 @@ class TestPropertySourceAttributes {
54
55
55
56
private final Class <?> declaringClass ;
56
57
57
- private final List <String > locations ;
58
+ private final MergedAnnotation <?> rootAnnotation ;
59
+
60
+ private final List <String > locations = new ArrayList <>();
58
61
59
62
private final boolean inheritLocations ;
60
63
61
- private final List <String > properties ;
64
+ private final List <String > properties = new ArrayList <>() ;
62
65
63
66
private final boolean inheritProperties ;
64
67
65
68
66
69
TestPropertySourceAttributes (MergedAnnotation <TestPropertySource > annotation ) {
67
70
this .aggregateIndex = annotation .getAggregateIndex ();
68
- this .declaringClass = (Class <?>) annotation .getSource ();
71
+ this .declaringClass = declaringClass (annotation );
72
+ this .rootAnnotation = annotation .getRoot ();
69
73
this .inheritLocations = annotation .getBoolean ("inheritLocations" );
70
74
this .inheritProperties = annotation .getBoolean ("inheritProperties" );
71
- this .properties = new ArrayList <>();
72
- this .locations = new ArrayList <>();
73
75
mergePropertiesAndLocations (annotation );
74
76
}
75
77
76
78
77
- boolean canMerge (MergedAnnotation <TestPropertySource > annotation ) {
79
+ /**
80
+ * Determine if the annotation represented by this
81
+ * {@code TestPropertySourceAttributes} instance can be merged with the
82
+ * supplied {@code annotation}.
83
+ * <p>This method effectively checks that two annotations are declared at
84
+ * the same level in the type hierarchy (i.e., have the same
85
+ * {@linkplain MergedAnnotation#getAggregateIndex() aggregate index}).
86
+ * @since 5.2
87
+ * @see #mergeWith(MergedAnnotation)
88
+ */
89
+ boolean canMergeWith (MergedAnnotation <TestPropertySource > annotation ) {
78
90
return annotation .getAggregateIndex () == this .aggregateIndex ;
79
91
}
80
92
81
- void merge (MergedAnnotation <TestPropertySource > annotation ) {
82
- Assert .state ((Class <?>) annotation .getSource () == this .declaringClass ,
93
+ /**
94
+ * Merge this {@code TestPropertySourceAttributes} instance with the
95
+ * supplied {@code annotation}, asserting that the two sets of test property
96
+ * source attributes have identical values for the
97
+ * {@link TestPropertySource#inheritLocations} and
98
+ * {@link TestPropertySource#inheritProperties} flags and that the two
99
+ * underlying annotations were declared on the same class.
100
+ * <p>This method should only be invoked if {@link #canMergeWith(MergedAnnotation)}
101
+ * returns {@code true}.
102
+ * @since 5.2
103
+ * @see #canMergeWith(MergedAnnotation)
104
+ */
105
+ void mergeWith (MergedAnnotation <TestPropertySource > annotation ) {
106
+ Class <?> source = declaringClass (annotation );
107
+ Assert .state (source == this .declaringClass ,
83
108
() -> "Detected @TestPropertySource declarations within an aggregate index "
84
- + "with different source : " + this .declaringClass + " and "
85
- + annotation . getSource ());
109
+ + "with different sources : " + this .declaringClass . getName () + " and "
110
+ + source . getName ());
86
111
logger .trace (LogMessage .format ("Retrieved %s for declaring class [%s]." ,
87
112
annotation , this .declaringClass .getName ()));
88
113
assertSameBooleanAttribute (this .inheritLocations , annotation , "inheritLocations" );
89
114
assertSameBooleanAttribute (this .inheritProperties , annotation , "inheritProperties" );
90
115
mergePropertiesAndLocations (annotation );
91
116
}
92
117
93
- private void assertSameBooleanAttribute (boolean expected ,
94
- MergedAnnotation <TestPropertySource > annotation , String attribute ) {
118
+ private void assertSameBooleanAttribute (boolean expected , MergedAnnotation <TestPropertySource > annotation ,
119
+ String attribute ) {
120
+
95
121
Assert .isTrue (expected == annotation .getBoolean (attribute ), () -> String .format (
96
- "Classes %s and %s must declare the same value for '%s' as other directly " +
97
- "present or meta-present @TestPropertySource annotations" , this .declaringClass .getName (),
98
- ((Class <?>) annotation .getSource ()).getName (), attribute ));
122
+ "@%s on %s and @%s on %s must declare the same value for '%s' as other " +
123
+ "directly present or meta-present @TestPropertySource annotations" ,
124
+ this .rootAnnotation .getType ().getSimpleName (), this .declaringClass .getSimpleName (),
125
+ annotation .getRoot ().getType ().getSimpleName (), declaringClass (annotation ).getSimpleName (),
126
+ attribute ));
99
127
}
100
128
101
- private void mergePropertiesAndLocations (
102
- MergedAnnotation <TestPropertySource > annotation ) {
129
+ private void mergePropertiesAndLocations (MergedAnnotation <TestPropertySource > annotation ) {
103
130
String [] locations = annotation .getStringArray ("locations" );
104
131
String [] properties = annotation .getStringArray ("properties" );
132
+ // If the meta-distance is positive, that means the annotation is
133
+ // meta-present and should therefore have lower priority than directly
134
+ // present annotations (i.e., it should be prepended to the list instead
135
+ // of appended). This follows the rule of last-one-wins for overriding
136
+ // properties.
105
137
boolean prepend = annotation .getDistance () > 0 ;
106
138
if (ObjectUtils .isEmpty (locations ) && ObjectUtils .isEmpty (properties )) {
107
139
addAll (prepend , this .locations , detectDefaultPropertiesFile (annotation ));
@@ -112,20 +144,28 @@ private void mergePropertiesAndLocations(
112
144
}
113
145
}
114
146
115
- private void addAll (boolean prepend , List <String > list , String ... additions ) {
116
- list .addAll (prepend ? 0 : list .size (), Arrays .asList (additions ));
147
+ /**
148
+ * Add all of the supplied elements to the provided list, honoring the
149
+ * {@code prepend} flag.
150
+ * <p>If the {@code prepend} flag is {@code false}, the elements will appended
151
+ * to the list.
152
+ * @param prepend whether the elements should be prepended to the list
153
+ * @param list the list to which to add the elements
154
+ * @param elements the elements to add to the list
155
+ */
156
+ private void addAll (boolean prepend , List <String > list , String ... elements ) {
157
+ list .addAll ((prepend ? 0 : list .size ()), Arrays .asList (elements ));
117
158
}
118
159
119
- private String detectDefaultPropertiesFile (
120
- MergedAnnotation <TestPropertySource > annotation ) {
121
- Class <?> testClass = (Class <?>) annotation .getSource ();
160
+ private String detectDefaultPropertiesFile (MergedAnnotation <TestPropertySource > annotation ) {
161
+ Class <?> testClass = declaringClass (annotation );
122
162
String resourcePath = ClassUtils .convertClassNameToResourcePath (testClass .getName ()) + ".properties" ;
123
163
ClassPathResource classPathResource = new ClassPathResource (resourcePath );
124
164
if (!classPathResource .exists ()) {
125
165
String msg = String .format (
126
- "Could not detect default properties file for test class [%s]: "
127
- + "%s does not exist. Either declare the 'locations' or 'properties' attributes "
128
- + "of @TestPropertySource or make the default properties file available." ,
166
+ "Could not detect default properties file for test class [%s]: " +
167
+ "%s does not exist. Either declare the 'locations' or 'properties' attributes " +
168
+ "of @TestPropertySource or make the default properties file available." ,
129
169
testClass .getName (), classPathResource );
130
170
logger .error (msg );
131
171
throw new IllegalStateException (msg );
@@ -195,7 +235,7 @@ boolean isInheritProperties() {
195
235
*/
196
236
@ Override
197
237
public String toString () {
198
- return new ToStringCreator (this )//
238
+ return new ToStringCreator (this )
199
239
.append ("declaringClass" , this .declaringClass .getName ())
200
240
.append ("locations" , this .locations )
201
241
.append ("inheritLocations" , this .inheritLocations )
@@ -204,4 +244,8 @@ public String toString() {
204
244
.toString ();
205
245
}
206
246
247
+ private static Class <?> declaringClass (MergedAnnotation <?> mergedAnnotation ) {
248
+ return (Class <?>) mergedAnnotation .getSource ();
249
+ }
250
+
207
251
}
0 commit comments