23
23
import java .util .Collections ;
24
24
import java .util .Comparator ;
25
25
import java .util .HashMap ;
26
+ import java .util .HashSet ;
26
27
import java .util .Iterator ;
28
+ import java .util .LinkedHashMap ;
27
29
import java .util .LinkedHashSet ;
28
30
import java .util .Map ;
31
+ import java .util .Map .Entry ;
29
32
import java .util .Set ;
30
33
import java .util .Stack ;
31
34
76
79
*
77
80
* @author Chris Beams
78
81
* @author Juergen Hoeller
82
+ * @author Rob Winch
79
83
* @since 3.0
80
84
* @see ConfigurationClassBeanDefinitionReader
81
85
*/
@@ -89,8 +93,8 @@ class ConfigurationClassParser {
89
93
90
94
private final Set <String > knownSuperclasses = new LinkedHashSet <String >();
91
95
92
- private final Set < ConfigurationClass > configurationClasses =
93
- new LinkedHashSet < ConfigurationClass >();
96
+ private final Map < ConfigurationClass , ConfigurationClass > configurationClasses =
97
+ new LinkedHashMap < ConfigurationClass , ConfigurationClass >();
94
98
95
99
private final Stack <PropertySource <?>> propertySources =
96
100
new Stack <PropertySource <?>>();
@@ -157,13 +161,60 @@ protected void processConfigurationClass(ConfigurationClass configClass) throws
157
161
}
158
162
while (metadata != null );
159
163
160
- if (this . configurationClasses .contains (configClass ) && configClass .getBeanName () != null ) {
164
+ if (getConfigurationClasses () .contains (configClass ) && configClass .getBeanName () != null ) {
161
165
// Explicit bean definition found, probably replacing an import.
162
166
// Let's remove the old one and go with the new one.
163
- this .configurationClasses .remove (configClass );
167
+ ConfigurationClass originalConfigClass = removeConfigurationClass (configClass );
168
+
169
+ mergeFromOriginalConfig (originalConfigClass ,configClass );
164
170
}
165
171
166
- this .configurationClasses .add (configClass );
172
+ addConfigurationClass (configClass );
173
+ }
174
+
175
+
176
+ /**
177
+ * Merges from the original {@link ConfigurationClass} to the new
178
+ * {@link ConfigurationClass}. This is necessary if parent classes have already been
179
+ * processed.
180
+ *
181
+ * @param originalConfigClass the original {@link ConfigurationClass} that may have
182
+ * additional metadata
183
+ * @param configClass the new {@link ConfigurationClass} that will have metadata added
184
+ * to it if necessary
185
+ */
186
+ private void mergeFromOriginalConfig (ConfigurationClass originalConfigClass ,
187
+ ConfigurationClass configClass ) {
188
+
189
+ Set <String > beanMethodNames = new HashSet <String >();
190
+ for (BeanMethod beanMethod : configClass .getBeanMethods ()) {
191
+ beanMethodNames .add (createBeanMethodName (beanMethod ));
192
+ }
193
+
194
+ for (BeanMethod originalBeanMethod : originalConfigClass .getBeanMethods ()) {
195
+ String originalBeanMethodName = createBeanMethodName (originalBeanMethod );
196
+ if (!beanMethodNames .contains (originalBeanMethodName )) {
197
+ configClass .addBeanMethod (new BeanMethod (originalBeanMethod .getMetadata (), configClass ));
198
+ }
199
+ }
200
+ for (Entry <String , Class <? extends BeanDefinitionReader >> originalImportedEntry : originalConfigClass .getImportedResources ().entrySet ()) {
201
+ if (!configClass .getImportedResources ().containsKey (originalImportedEntry .getKey ())) {
202
+ configClass .addImportedResource (originalImportedEntry .getKey (), originalImportedEntry .getValue ());
203
+ }
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Converts a {@link BeanMethod} into the fully qualified name of the Method
209
+ *
210
+ * @param beanMethod
211
+ * @return fully qualified name of the {@link BeanMethod}
212
+ */
213
+ private String createBeanMethodName (BeanMethod beanMethod ) {
214
+ String hashDelim = "#" ;
215
+ String dClassName = beanMethod .getMetadata ().getDeclaringClassName ();
216
+ String methodName = beanMethod .getMetadata ().getMethodName ();
217
+ return dClassName + hashDelim + methodName ;
167
218
}
168
219
169
220
/**
@@ -251,6 +302,14 @@ else if (superclass.startsWith("java")) {
251
302
return null ;
252
303
}
253
304
305
+ private void addConfigurationClass (ConfigurationClass configClass ) {
306
+ this .configurationClasses .put (configClass ,configClass );
307
+ }
308
+
309
+ private ConfigurationClass removeConfigurationClass (ConfigurationClass configClass ) {
310
+ return this .configurationClasses .remove (configClass );
311
+ }
312
+
254
313
/**
255
314
* Register member (nested) classes that happen to be configuration classes themselves.
256
315
* @param metadata the metadata representation of the containing class
@@ -441,13 +500,13 @@ private void invokeAwareMethods(ImportBeanDefinitionRegistrar registrar) {
441
500
* @see ConfigurationClass#validate
442
501
*/
443
502
public void validate () {
444
- for (ConfigurationClass configClass : this . configurationClasses ) {
503
+ for (ConfigurationClass configClass : getConfigurationClasses () ) {
445
504
configClass .validate (this .problemReporter );
446
505
}
447
506
}
448
507
449
508
public Set <ConfigurationClass > getConfigurationClasses () {
450
- return this .configurationClasses ;
509
+ return this .configurationClasses . keySet () ;
451
510
}
452
511
453
512
public Stack <PropertySource <?>> getPropertySources () {
0 commit comments