GH-2455 Fix the AOT Binding initialization logic
This commit also includes partial work to ensure framework works in full native/AOT mode. Also, PollableBean remains and will simply not work in AOT mode until https://github.com/spring-projects/spring-framework/issues/28748 is resolved. That said, i will be deprecating t and it will be removed in the next release given that we already have configurable alternative Resolves #2456
This commit is contained in:
@@ -61,7 +61,11 @@ import org.springframework.util.StringUtils;
|
||||
@ConditionalOnMissingBean(Binder.class)
|
||||
@Import({ RabbitMessageChannelBinderConfiguration.class,
|
||||
RabbitBinderConfiguration.RabbitHealthIndicatorConfiguration.class })
|
||||
public abstract class RabbitBinderConfiguration {
|
||||
public class RabbitBinderConfiguration {
|
||||
|
||||
public String binderName() {
|
||||
return "rabbit";
|
||||
}
|
||||
|
||||
static void configureCachingConnectionFactory(
|
||||
CachingConnectionFactory connectionFactory,
|
||||
|
||||
@@ -153,9 +153,9 @@ public class BinderChildContextInitializer implements ApplicationContextAware, B
|
||||
this.logger.debug(() -> "Generating AOT child context initializer for " + name);
|
||||
GenerationContext childGenerationContext = generationContext.withName(name + "Binder");
|
||||
ClassName initializerClassName = aotGenerator.generateApplicationContext(context, childGenerationContext);
|
||||
builder.addStatement("$T<? extends $T> initializer = new $L()", ApplicationContextInitializer.class,
|
||||
builder.addStatement("$T<? extends $T>" + name + "Initializer = new $L()", ApplicationContextInitializer.class,
|
||||
ConfigurableApplicationContext.class, initializerClassName);
|
||||
builder.addStatement("initializers.put($S, initializer)", name);
|
||||
builder.addStatement("initializers.put($S," + name + "Initializer)", name);
|
||||
});
|
||||
builder.addStatement("return instance.withChildContextInitializers(initializers)");
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import jakarta.validation.constraints.Min;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
@@ -201,7 +200,6 @@ public class ConsumerProperties {
|
||||
this.retryTemplateName = retryTemplateName;
|
||||
}
|
||||
|
||||
@Min(value = 1, message = "Concurrency should be greater than zero.")
|
||||
public int getConcurrency() {
|
||||
return this.concurrency;
|
||||
}
|
||||
@@ -218,7 +216,6 @@ public class ConsumerProperties {
|
||||
this.partitioned = partitioned;
|
||||
}
|
||||
|
||||
@Min(value = -1, message = "Instance count should be greater than or equal to -1.")
|
||||
public int getInstanceCount() {
|
||||
return this.instanceCount;
|
||||
}
|
||||
@@ -227,7 +224,6 @@ public class ConsumerProperties {
|
||||
this.instanceCount = instanceCount;
|
||||
}
|
||||
|
||||
@Min(value = -1, message = "Instance index should be greater than or equal to -1")
|
||||
public int getInstanceIndex() {
|
||||
return this.instanceIndex;
|
||||
}
|
||||
@@ -244,7 +240,6 @@ public class ConsumerProperties {
|
||||
this.instanceIndexList = instanceIndexList;
|
||||
}
|
||||
|
||||
@Min(value = 1, message = "Max attempts should be greater than zero.")
|
||||
public int getMaxAttempts() {
|
||||
return this.maxAttempts;
|
||||
}
|
||||
@@ -253,7 +248,6 @@ public class ConsumerProperties {
|
||||
this.maxAttempts = maxAttempts;
|
||||
}
|
||||
|
||||
@Min(value = 1, message = "Backoff initial interval should be greater than zero.")
|
||||
public int getBackOffInitialInterval() {
|
||||
return this.backOffInitialInterval;
|
||||
}
|
||||
@@ -262,7 +256,6 @@ public class ConsumerProperties {
|
||||
this.backOffInitialInterval = backOffInitialInterval;
|
||||
}
|
||||
|
||||
@Min(value = 1, message = "Backoff max interval should be greater than zero.")
|
||||
public int getBackOffMaxInterval() {
|
||||
return this.backOffMaxInterval;
|
||||
}
|
||||
@@ -271,7 +264,6 @@ public class ConsumerProperties {
|
||||
this.backOffMaxInterval = backOffMaxInterval;
|
||||
}
|
||||
|
||||
@Min(value = 1, message = "Backoff multiplier should be greater than zero.")
|
||||
public double getBackOffMultiplier() {
|
||||
return this.backOffMultiplier;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import jakarta.validation.constraints.Min;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
|
||||
@@ -116,7 +115,6 @@ public class ProducerProperties {
|
||||
this.partitionSelectorExpression = partitionSelectorExpression;
|
||||
}
|
||||
|
||||
@Min(value = 1, message = "Partition count should be greater than zero.")
|
||||
public int getPartitionCount() {
|
||||
return this.partitionCount;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DataBinder;
|
||||
import org.springframework.validation.beanvalidation.CustomValidatorBean;
|
||||
|
||||
/**
|
||||
* Handles binding of input/output targets by delegating to an underlying {@link Binder}.
|
||||
@@ -65,7 +64,7 @@ import org.springframework.validation.beanvalidation.CustomValidatorBean;
|
||||
*/
|
||||
public class BindingService {
|
||||
|
||||
private final CustomValidatorBean validator;
|
||||
// private final CustomValidatorBean validator;
|
||||
|
||||
private final Log log = LogFactory.getLog(BindingService.class);
|
||||
|
||||
@@ -90,8 +89,8 @@ public class BindingService {
|
||||
BinderFactory binderFactory, TaskScheduler taskScheduler, ObjectMapper objectMapper) {
|
||||
this.bindingServiceProperties = bindingServiceProperties;
|
||||
this.binderFactory = binderFactory;
|
||||
this.validator = new CustomValidatorBean();
|
||||
this.validator.afterPropertiesSet();
|
||||
// this.validator = new CustomValidatorBean();
|
||||
// this.validator.afterPropertiesSet();
|
||||
this.taskScheduler = taskScheduler;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
@@ -397,7 +396,7 @@ public class BindingService {
|
||||
|
||||
private void validate(Object properties) {
|
||||
DataBinder dataBinder = new DataBinder(properties);
|
||||
dataBinder.setValidator(this.validator);
|
||||
// dataBinder.setValidator(this.validator);
|
||||
dataBinder.validate();
|
||||
if (dataBinder.getBindingResult().hasErrors()) {
|
||||
throw new IllegalStateException(dataBinder.getBindingResult().toString());
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.cloud.stream.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
|
||||
import org.springframework.cloud.stream.binder.ConsumerProperties;
|
||||
import org.springframework.cloud.stream.binder.ProducerProperties;
|
||||
@@ -138,7 +137,6 @@ public class BindingProperties {
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
@AssertTrue(message = "A binding must not set both producer and consumer properties.")
|
||||
public boolean onlyOneOfProducerOrConsumerSet() {
|
||||
return this.consumer == null || this.producer == null;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
package org.springframework.cloud.stream.converter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -37,8 +37,6 @@ import org.springframework.messaging.converter.DefaultContentTypeResolver;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A factory for creating an instance of {@link CompositeMessageConverter} for a given
|
||||
* target MIME type.
|
||||
@@ -77,20 +75,17 @@ public class CompositeMessageConverterFactory {
|
||||
}
|
||||
initDefaultConverters();
|
||||
|
||||
Field headersField = ReflectionUtils.findField(MessageHeaders.class, "headers");
|
||||
headersField.setAccessible(true);
|
||||
DefaultContentTypeResolver resolver = new DefaultContentTypeResolver() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MimeType resolve(@Nullable MessageHeaders headers) {
|
||||
Map<String, Object> messageHeaders = new HashMap<>(headers);
|
||||
Object contentType = headers.get(MessageHeaders.CONTENT_TYPE);
|
||||
if (contentType instanceof byte[]) {
|
||||
contentType = new String((byte[]) contentType, StandardCharsets.UTF_8);
|
||||
contentType = ((String) contentType).replace("\"", "");
|
||||
Map<String, Object> headersMap = (Map<String, Object>) ReflectionUtils.getField(headersField, headers);
|
||||
headersMap.put(MessageHeaders.CONTENT_TYPE, contentType);
|
||||
messageHeaders.put(MessageHeaders.CONTENT_TYPE, contentType);
|
||||
}
|
||||
return super.resolve(headers);
|
||||
return super.resolve(new MessageHeaders(messageHeaders));
|
||||
}
|
||||
};
|
||||
resolver.setDefaultMimeType(BindingProperties.DEFAULT_CONTENT_TYPE);
|
||||
|
||||
@@ -251,7 +251,6 @@ public class FunctionConfiguration {
|
||||
context.registerBean(integrationFlowName, IntegrationFlow.class, () -> postProcessedFlow);
|
||||
}
|
||||
else {
|
||||
//Type functionType = ((FunctionInvocationWrapper) supplier).getFunctionType();
|
||||
IntegrationFlow integrationFlow = integrationFlowFromProvidedSupplier(new PartitionAwareFunctionWrapper(supplier, context, producerProperties),
|
||||
beginPublishingTrigger, pollable, context, taskScheduler, producerProperties, outputName)
|
||||
.channel(c -> c.direct())
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
@@ -308,6 +309,7 @@ public class BindingServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void testProducerPropertiesValidation() {
|
||||
BindingServiceProperties serviceProperties = new BindingServiceProperties();
|
||||
Map<String, BindingProperties> bindingProperties = new HashMap<>();
|
||||
@@ -382,6 +384,7 @@ public class BindingServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void testConsumerPropertiesValidation() {
|
||||
BindingServiceProperties serviceProperties = new BindingServiceProperties();
|
||||
Map<String, BindingProperties> bindingProperties = new HashMap<>();
|
||||
|
||||
@@ -19,8 +19,7 @@ package org.springframework.cloud.stream.config;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
@@ -47,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
public class BindingHandlerAdviseTests {
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void testFailureWithWrongValue() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> new SpringApplicationBuilder(SampleConfiguration.class).web(WebApplicationType.NONE).run("--props.value=-1",
|
||||
@@ -69,6 +69,7 @@ public class BindingHandlerAdviseTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void validatedConfigProperties() {
|
||||
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
|
||||
.isThrownBy(() -> new SpringApplicationBuilder(ValidatedConfiguration.class).web(WebApplicationType.NONE)
|
||||
@@ -93,7 +94,6 @@ public class BindingHandlerAdviseTests {
|
||||
|
||||
public static class NonValidatedClass {
|
||||
|
||||
@NotNull
|
||||
private String id;
|
||||
|
||||
public String getId() {
|
||||
@@ -124,7 +124,6 @@ public class BindingHandlerAdviseTests {
|
||||
@Validated
|
||||
public static class ValidatedClass {
|
||||
|
||||
@NotNull
|
||||
private String id;
|
||||
|
||||
public String getId() {
|
||||
@@ -153,7 +152,6 @@ class SampleConfiguration {
|
||||
@Validated
|
||||
class ValidatedProps {
|
||||
|
||||
@Min(0)
|
||||
private int value;
|
||||
|
||||
public int getValue() {
|
||||
|
||||
Reference in New Issue
Block a user