From ae79c606194123f60785155df97542ec1c4d065e Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Wed, 18 Jan 2023 09:40:16 +0100 Subject: [PATCH] Remove instance suppliers in bean definitions Remove instance suppliers in bean definitions and depend instead on reflection. This allows the AOT engine to correctly process the definitions. Fixes gh-33763 --- ...tiveWebServerFactoryAutoConfiguration.java | 11 ++-- ...vletWebServerFactoryAutoConfiguration.java | 13 ++-- .../BoundConfigurationProperties.java | 5 +- .../ConfigurationPropertiesBinder.java | 61 +++++++++---------- 4 files changed, 39 insertions(+), 51 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfiguration.java index f16b57e872..7e621f0947 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.web.reactive; -import java.util.function.Supplier; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -102,14 +100,13 @@ public class ReactiveWebServerFactoryAutoConfiguration { return; } registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", - WebServerFactoryCustomizerBeanPostProcessor.class, - WebServerFactoryCustomizerBeanPostProcessor::new); + WebServerFactoryCustomizerBeanPostProcessor.class); } private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, - Class beanClass, Supplier instanceSupplier) { + Class beanClass) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { - RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier); + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfiguration.java index 624383b59a..88c5e0d5e6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.web.servlet; -import java.util.function.Supplier; - import jakarta.servlet.DispatcherType; import jakarta.servlet.ServletRequest; @@ -139,16 +137,15 @@ public class ServletWebServerFactoryAutoConfiguration { return; } registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", - WebServerFactoryCustomizerBeanPostProcessor.class, - WebServerFactoryCustomizerBeanPostProcessor::new); + WebServerFactoryCustomizerBeanPostProcessor.class); registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", - ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new); + ErrorPageRegistrarBeanPostProcessor.class); } private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, - Class beanClass, Supplier instanceSupplier) { + Class beanClass) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { - RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier); + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/BoundConfigurationProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/BoundConfigurationProperties.java index 075463c1bb..c8616d08d1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/BoundConfigurationProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/BoundConfigurationProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -81,8 +81,7 @@ public class BoundConfigurationProperties { static void register(BeanDefinitionRegistry registry) { Assert.notNull(registry, "Registry must not be null"); if (!registry.containsBeanDefinition(BEAN_NAME)) { - BeanDefinition definition = BeanDefinitionBuilder - .genericBeanDefinition(BoundConfigurationProperties.class, BoundConfigurationProperties::new) + BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(BoundConfigurationProperties.class) .getBeanDefinition(); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(BEAN_NAME, definition); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinder.java index 5fe6661c04..4f730235e3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -50,6 +50,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.convert.ConversionService; import org.springframework.core.env.PropertySources; +import org.springframework.util.Assert; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; @@ -64,8 +65,6 @@ class ConfigurationPropertiesBinder { private static final String BEAN_NAME = "org.springframework.boot.context.internalConfigurationPropertiesBinder"; - private static final String FACTORY_BEAN_NAME = "org.springframework.boot.context.internalConfigurationPropertiesBinderFactory"; - private static final String VALIDATOR_BEAN_NAME = EnableConfigurationProperties.VALIDATOR_BEAN_NAME; private final ApplicationContext applicationContext; @@ -189,18 +188,9 @@ class ConfigurationPropertiesBinder { } static void register(BeanDefinitionRegistry registry) { - if (!registry.containsBeanDefinition(FACTORY_BEAN_NAME)) { - BeanDefinition definition = BeanDefinitionBuilder - .rootBeanDefinition(ConfigurationPropertiesBinder.Factory.class).getBeanDefinition(); - definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(ConfigurationPropertiesBinder.FACTORY_BEAN_NAME, definition); - } if (!registry.containsBeanDefinition(BEAN_NAME)) { BeanDefinition definition = BeanDefinitionBuilder - .rootBeanDefinition(ConfigurationPropertiesBinder.class, - () -> ((BeanFactory) registry) - .getBean(FACTORY_BEAN_NAME, ConfigurationPropertiesBinder.Factory.class).create()) - .getBeanDefinition(); + .rootBeanDefinition(ConfigurationPropertiesBinderFactory.class).getBeanDefinition(); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(ConfigurationPropertiesBinder.BEAN_NAME, definition); } @@ -211,44 +201,49 @@ class ConfigurationPropertiesBinder { } /** - * Factory bean used to create the {@link ConfigurationPropertiesBinder}. The bean - * needs to be {@link ApplicationContextAware} since we can't directly inject an - * {@link ApplicationContext} into the constructor without causing eager - * {@link FactoryBean} initialization. + * {@link BindHandler} to deal with + * {@link ConfigurationProperties @ConfigurationProperties} concerns. */ - static class Factory implements ApplicationContextAware { + private static class ConfigurationPropertiesBindHandler extends AbstractBindHandler { - private ApplicationContext applicationContext; + ConfigurationPropertiesBindHandler(BindHandler handler) { + super(handler); + } @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; + public Bindable onStart(ConfigurationPropertyName name, Bindable target, BindContext context) { + return isConfigurationProperties(target.getType().resolve()) + ? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target; } - ConfigurationPropertiesBinder create() { - return new ConfigurationPropertiesBinder(this.applicationContext); + private boolean isConfigurationProperties(Class target) { + return target != null && MergedAnnotations.from(target).isPresent(ConfigurationProperties.class); } } /** - * {@link BindHandler} to deal with - * {@link ConfigurationProperties @ConfigurationProperties} concerns. + * {@link FactoryBean} to create the {@link ConfigurationPropertiesBinder}. */ - private static class ConfigurationPropertiesBindHandler extends AbstractBindHandler { + static class ConfigurationPropertiesBinderFactory + implements FactoryBean, ApplicationContextAware { - ConfigurationPropertiesBindHandler(BindHandler handler) { - super(handler); + private ConfigurationPropertiesBinder binder; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.binder = (this.binder != null) ? this.binder : new ConfigurationPropertiesBinder(applicationContext); } @Override - public Bindable onStart(ConfigurationPropertyName name, Bindable target, BindContext context) { - return isConfigurationProperties(target.getType().resolve()) - ? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target; + public Class getObjectType() { + return ConfigurationPropertiesBinder.class; } - private boolean isConfigurationProperties(Class target) { - return target != null && MergedAnnotations.from(target).isPresent(ConfigurationProperties.class); + @Override + public ConfigurationPropertiesBinder getObject() throws Exception { + Assert.state(this.binder != null, "Binder was not created due to missing setApplicationContext call"); + return this.binder; } }