From b8673113333c38b403629fab99bc791ac693840d Mon Sep 17 00:00:00 2001 From: Soby Chacko Date: Wed, 18 Oct 2023 20:21:39 -0400 Subject: [PATCH] GH-2828: Custom binders not recognized by AOT - When using multi-binders with custom binders and running in AOT mode, there is a regression that is causing some issues for propertly identifying the binders during the AOT phase. It forces the users to provide property in the form of `spring.cloud.stream.binders.binders...` Fixing this issue by properly binding the custom binders in BinderChildContextInitializer. Resolves https://github.com/spring-cloud/spring-cloud-stream/issues/2828 Resolves #2834 --- .../binder/BinderChildContextInitializer.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java index 9b454605d..e1ceae3cc 100644 --- a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java +++ b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java @@ -32,6 +32,8 @@ import org.springframework.beans.factory.aot.BeanRegistrationCode; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.cloud.stream.config.BinderProperties; import org.springframework.cloud.stream.config.BindingServiceConfiguration; import org.springframework.cloud.stream.config.BindingServiceProperties; import org.springframework.context.ApplicationContext; @@ -107,8 +109,21 @@ public class BinderChildContextInitializer implements ApplicationContextAware, B private BindingServiceProperties declaredBindersAsBindingServiceProperties() { BindingServiceProperties bindingServiceProperties = new BindingServiceProperties(); + + // We only need to bind to a single property -- "binders" -- defined in BindingServiceProperties + // to retrieve the custom binders declared by the application. + // Therefore, we are binding to a custom type (DeclaredBinders) which only has this custom binders map property. + // If we bind to BindingServiceProperties directly, it tries to bind all the properties defined there which + // is unnecessary and may throw errors. + // For more details on why that is the case, see https://github.com/spring-cloud/spring-cloud-stream/issues/2799 + + // Moreover, we cannot bind directly to spring.cloud.stream.binders and use BindingServiceProperties + // because in that case, users have to specify custom binders like spring.cloud.stream.binders.binders.. + // See https://github.com/spring-cloud/spring-cloud-stream/issues/2828 for more details on that. + DeclaredBinders declaredBinders = new DeclaredBinders(); Binder.get(this.context.getEnvironment()) - .bind("spring.cloud.stream.binders", Bindable.ofInstance(bindingServiceProperties)); + .bind(ConfigurationPropertyName.of("spring.cloud.stream"), Bindable.ofInstance(declaredBinders)); + bindingServiceProperties.setBinders(declaredBinders.getBinders()); return bindingServiceProperties; } @@ -180,4 +195,17 @@ public class BinderChildContextInitializer implements ApplicationContextAware, B } } + private static class DeclaredBinders { + + Map binders = new HashMap<>(); + + public Map getBinders() { + return binders; + } + + public void setBinders(Map binders) { + this.binders = binders; + } + } + }