Reverse engineer documentation for Bean Override internals
This commit is contained in:
		
							parent
							
								
									ded5c13e19
								
							
						
					
					
						commit
						c3ff6cf319
					
				| 
						 | 
					@ -104,19 +104,6 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Copy certain details of a {@link BeanDefinition} to the definition created by
 | 
					 | 
				
			||||||
	 * this processor for a given {@link OverrideMetadata}.
 | 
					 | 
				
			||||||
	 * <p>The default implementation copies the {@linkplain BeanDefinition#isPrimary()
 | 
					 | 
				
			||||||
	 * primary flag}, @{@linkplain BeanDefinition#isFallback() fallback flag}
 | 
					 | 
				
			||||||
	 * and the {@linkplain BeanDefinition#getScope() scope}.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	protected void copyBeanDefinitionDetails(BeanDefinition from, RootBeanDefinition to) {
 | 
					 | 
				
			||||||
		to.setPrimary(from.isPrimary());
 | 
					 | 
				
			||||||
		to.setFallback(from.isFallback());
 | 
					 | 
				
			||||||
		to.setScope(from.getScope());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
 | 
						private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
 | 
				
			||||||
			OverrideMetadata overrideMetadata) {
 | 
								OverrideMetadata overrideMetadata) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,6 +119,8 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
 | 
				
			||||||
	private void registerReplaceDefinition(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
 | 
						private void registerReplaceDefinition(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
 | 
				
			||||||
			OverrideMetadata overrideMetadata, boolean enforceExistingDefinition) {
 | 
								OverrideMetadata overrideMetadata, boolean enforceExistingDefinition) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// The following is a "dummy" bean definition which should not be used to
 | 
				
			||||||
 | 
							// create an actual bean instance.
 | 
				
			||||||
		RootBeanDefinition beanDefinition = createBeanDefinition(overrideMetadata);
 | 
							RootBeanDefinition beanDefinition = createBeanDefinition(overrideMetadata);
 | 
				
			||||||
		String beanName = overrideMetadata.getBeanName();
 | 
							String beanName = overrideMetadata.getBeanName();
 | 
				
			||||||
		String beanNameIncludingFactory;
 | 
							String beanNameIncludingFactory;
 | 
				
			||||||
| 
						 | 
					@ -157,22 +146,27 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
 | 
				
			||||||
			beanNameIncludingFactory = beanName;
 | 
								beanNameIncludingFactory = beanName;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Process existing bean definition.
 | 
				
			||||||
		if (existingBeanDefinition != null) {
 | 
							if (existingBeanDefinition != null) {
 | 
				
			||||||
			copyBeanDefinitionDetails(existingBeanDefinition, beanDefinition);
 | 
								copyBeanDefinitionProperties(existingBeanDefinition, beanDefinition);
 | 
				
			||||||
			registry.removeBeanDefinition(beanName);
 | 
								registry.removeBeanDefinition(beanName);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// At this point, we either removed an existing bean definition above, or
 | 
				
			||||||
 | 
							// there was no bean definition to begin with. So, we register the dummy bean
 | 
				
			||||||
 | 
							// definition to ensure that a bean definition exists for the given bean name.
 | 
				
			||||||
		registry.registerBeanDefinition(beanName, beanDefinition);
 | 
							registry.registerBeanDefinition(beanName, beanDefinition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
 | 
							Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
 | 
				
			||||||
		if (beanFactory.isSingleton(beanNameIncludingFactory)) {
 | 
					 | 
				
			||||||
			// Now we have an instance (the override) that we can register.
 | 
					 | 
				
			||||||
			// At this stage we don't expect a singleton instance to be present,
 | 
					 | 
				
			||||||
			// and this call will throw if there is such an instance already.
 | 
					 | 
				
			||||||
			beanFactory.registerSingleton(beanName, override);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		overrideMetadata.track(override, beanFactory);
 | 
							overrideMetadata.track(override, beanFactory);
 | 
				
			||||||
		this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanNameIncludingFactory);
 | 
							this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanNameIncludingFactory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (beanFactory.isSingleton(beanNameIncludingFactory)) {
 | 
				
			||||||
 | 
								// Now we have an instance (the override) that we can register. At this
 | 
				
			||||||
 | 
								// stage we don't expect a singleton instance to be present, and this call
 | 
				
			||||||
 | 
								// will throw an exception if there is such an instance already.
 | 
				
			||||||
 | 
								beanFactory.registerSingleton(beanName, override);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private String getBeanNameForType(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
 | 
						private String getBeanNameForType(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry,
 | 
				
			||||||
| 
						 | 
					@ -231,13 +225,6 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
 | 
				
			||||||
		this.overrideRegistrar.registerNameForMetadata(metadata, beanName);
 | 
							this.overrideRegistrar.registerNameForMetadata(metadata, beanName);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RootBeanDefinition createBeanDefinition(OverrideMetadata metadata) {
 | 
					 | 
				
			||||||
		RootBeanDefinition definition = new RootBeanDefinition(metadata.getBeanType().resolve());
 | 
					 | 
				
			||||||
		definition.setTargetType(metadata.getBeanType());
 | 
					 | 
				
			||||||
		definition.setQualifiedElement(metadata.getField());
 | 
					 | 
				
			||||||
		return definition;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory beanFactory, OverrideMetadata metadata,
 | 
						private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory beanFactory, OverrideMetadata metadata,
 | 
				
			||||||
			boolean checkAutowiredCandidate) {
 | 
								boolean checkAutowiredCandidate) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -272,6 +259,26 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static RootBeanDefinition createBeanDefinition(OverrideMetadata metadata) {
 | 
				
			||||||
 | 
							RootBeanDefinition definition = new RootBeanDefinition(metadata.getBeanType().resolve());
 | 
				
			||||||
 | 
							definition.setTargetType(metadata.getBeanType());
 | 
				
			||||||
 | 
							definition.setQualifiedElement(metadata.getField());
 | 
				
			||||||
 | 
							return definition;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Copy the following properties of the source {@link BeanDefinition} to the
 | 
				
			||||||
 | 
						 * target: the {@linkplain BeanDefinition#isPrimary() primary flag}, the
 | 
				
			||||||
 | 
						 * {@linkplain BeanDefinition#isFallback() fallback flag}, and the
 | 
				
			||||||
 | 
						 * {@linkplain BeanDefinition#getScope() scope}.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static void copyBeanDefinitionProperties(BeanDefinition source, RootBeanDefinition target) {
 | 
				
			||||||
 | 
							target.setPrimary(source.isPrimary());
 | 
				
			||||||
 | 
							target.setFallback(source.isFallback());
 | 
				
			||||||
 | 
							target.setScope(source.getScope());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static class WrapEarlyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
 | 
						static class WrapEarlyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
 | 
				
			||||||
			PriorityOrdered {
 | 
								PriorityOrdered {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock;
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Simon Baslé
 | 
					 * @author Simon Baslé
 | 
				
			||||||
 * @author Stephane Nicoll
 | 
					 * @author Stephane Nicoll
 | 
				
			||||||
 | 
					 * @author Sam Brannen
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class BeanOverrideBeanFactoryPostProcessorTests {
 | 
					class BeanOverrideBeanFactoryPostProcessorTests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,7 +201,7 @@ class BeanOverrideBeanFactoryPostProcessorTests {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	void allowReplaceDefinitionWhenSingletonDefinitionPresent() {
 | 
						void replaceBeanByNameWithMatchingBeanDefinitionWithExplicitSingletonScope() {
 | 
				
			||||||
		AnnotationConfigApplicationContext context = createContext(CaseByName.class);
 | 
							AnnotationConfigApplicationContext context = createContext(CaseByName.class);
 | 
				
			||||||
		RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
 | 
							RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
 | 
				
			||||||
		definition.setScope(BeanDefinition.SCOPE_SINGLETON);
 | 
							definition.setScope(BeanDefinition.SCOPE_SINGLETON);
 | 
				
			||||||
| 
						 | 
					@ -212,7 +213,7 @@ class BeanOverrideBeanFactoryPostProcessorTests {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	void copyDefinitionPrimaryFallbackAndScope() {
 | 
						void replaceBeanByNameWithMatchingBeanDefinitionRetainsPrimaryFallbackAndScopeProperties() {
 | 
				
			||||||
		AnnotationConfigApplicationContext context = createContext(CaseByName.class);
 | 
							AnnotationConfigApplicationContext context = createContext(CaseByName.class);
 | 
				
			||||||
		context.getBeanFactory().registerScope("customScope", new SimpleThreadScope());
 | 
							context.getBeanFactory().registerScope("customScope", new SimpleThreadScope());
 | 
				
			||||||
		RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
 | 
							RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
 | 
				
			||||||
| 
						 | 
					@ -232,21 +233,21 @@ class BeanOverrideBeanFactoryPostProcessorTests {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	void createDefinitionShouldSetQualifierElement() {
 | 
						void qualifiedElementIsSetToBeanOverrideField() {
 | 
				
			||||||
		AnnotationConfigApplicationContext context = createContext(CaseByNameWithQualifier.class);
 | 
							AnnotationConfigApplicationContext context = createContext(CaseByNameWithQualifier.class);
 | 
				
			||||||
		context.registerBeanDefinition("descriptionBean", new RootBeanDefinition(String.class, () -> "ORIGINAL"));
 | 
							context.registerBeanDefinition("descriptionBean", new RootBeanDefinition(String.class, () -> "ORIGINAL"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assertThatNoException().isThrownBy(context::refresh);
 | 
							assertThatNoException().isThrownBy(context::refresh);
 | 
				
			||||||
		assertThat(context.getBeanDefinition("descriptionBean"))
 | 
							assertThat(context.getBeanDefinition("descriptionBean"))
 | 
				
			||||||
				.isInstanceOfSatisfying(RootBeanDefinition.class, this::isTheValueField);
 | 
									.isInstanceOfSatisfying(RootBeanDefinition.class, this::qualifiedElementIsField);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void isTheValueField(RootBeanDefinition def) {
 | 
						private void qualifiedElementIsField(RootBeanDefinition def) {
 | 
				
			||||||
		assertThat(def.getQualifiedElement()).isInstanceOfSatisfying(Field.class, field -> {
 | 
							assertThat(def.getQualifiedElement()).isInstanceOfSatisfying(Field.class,
 | 
				
			||||||
 | 
								field -> {
 | 
				
			||||||
				assertThat(field.getDeclaringClass()).isEqualTo(CaseByNameWithQualifier.class);
 | 
									assertThat(field.getDeclaringClass()).isEqualTo(CaseByNameWithQualifier.class);
 | 
				
			||||||
					assertThat(field.getName()).as("annotated field name")
 | 
									assertThat(field.getName()).as("annotated field name").isEqualTo("description");
 | 
				
			||||||
							.isEqualTo("description");
 | 
					 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue