GH-3828: Initial Spring AOT support (#3832)
* GH-3828: Initial Spring AOT support Fixes https://github.com/spring-projects/spring-integration/issues/3828 * Provide an infrastructure based on a new Spring AOT engine in the latest Spring Framework * Introduce `RuntimeHintsRegistrar` impls into modules which require some reflection, resources or proxies and serialization available in the native image * Mark some framework method with the `@Reflective` to make their reflection info available in the native image, for example for SpEL or JMX invocations * Add a `GatewayProxyBeanRegistrationAotProcessor` to register proxy interfaces info for messaging gateways (either instance of the `GatewayProxyFactoryBean`) * Rework `ConverterRegistrar` to not use a `beanFactory.getBeansWithAnnotation()` since it is not available after AOT phase. Instead, register an intermediate `IntegrationConverterRegistration` bean definition from the `IntegrationConverterInitializer` * Refactor `GlobalChannelInterceptorInitializer` a bit according to a new logic in the `IntegrationConverterInitializer` * Remove `JsonNodeWrapperToJsonNodeConverter` bean registration from the `DefaultConfiguringBeanFactoryPostProcessor` - it is added by the `ConverterRegistrar` into the target `ConversionService` * Fix `ParentContextTests` respectively a `JsonNodeWrapperToJsonNodeConverter` bean removal * Refactor `XsltPayloadTransformer` to not load a `ServletContextResource`, but just use its name for the `xslResource` condition * * Rework AOT support according latest changes and requirements * Remove `@Bean` reflection since it is not needed any more * Add `AotDetector.useGeneratedArtifacts()` condition to not register beans one more time at runtime after AOT build phase * Fix deprecation in the WebFlux test from the latest SF
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.aot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ProxyHints;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.SerializationHints;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.DecoratingProxy;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.core.GenericSelector;
|
||||
import org.springframework.integration.core.Pausable;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
import org.springframework.integration.gateway.MethodArgsHolder;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.handler.DelayHandler;
|
||||
import org.springframework.integration.handler.GenericHandler;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.json.JsonPathUtils;
|
||||
import org.springframework.integration.message.AdviceMessage;
|
||||
import org.springframework.integration.routingslip.ExpressionEvaluatingRoutingSlipRouteStrategy;
|
||||
import org.springframework.integration.store.MessageGroupMetadata;
|
||||
import org.springframework.integration.store.MessageHolder;
|
||||
import org.springframework.integration.store.MessageMetadata;
|
||||
import org.springframework.integration.support.MutableMessage;
|
||||
import org.springframework.integration.support.MutableMessageHeaders;
|
||||
import org.springframework.integration.support.management.ManageableSmartLifecycle;
|
||||
import org.springframework.integration.transformer.GenericTransformer;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for Spring Integration core module.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
class CoreRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
ReflectionHints reflectionHints = hints.reflection();
|
||||
Stream.of(
|
||||
GenericSelector.class,
|
||||
GenericTransformer.class,
|
||||
GenericHandler.class,
|
||||
Function.class,
|
||||
Supplier.class,
|
||||
BeanExpressionContext.class,
|
||||
IntegrationContextUtils.class,
|
||||
MethodArgsHolder.class,
|
||||
AbstractReplyProducingMessageHandler.RequestHandler.class,
|
||||
ExpressionEvaluatingRoutingSlipRouteStrategy.RequestAndReply.class,
|
||||
Pausable.class,
|
||||
ManageableSmartLifecycle.class)
|
||||
.forEach(type ->
|
||||
reflectionHints.registerType(type,
|
||||
builder -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)));
|
||||
|
||||
reflectionHints.registerType(JsonPathUtils.class,
|
||||
builder ->
|
||||
builder.onReachableType(TypeReference.of("com.jayway.jsonpath.JsonPath"))
|
||||
.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
|
||||
// For #xpath() SpEL function
|
||||
reflectionHints.registerTypeIfPresent(classLoader, "org.springframework.integration.xml.xpath.XPathUtils",
|
||||
builder -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
|
||||
Stream.of(
|
||||
"kotlin.jvm.functions.Function0",
|
||||
"kotlin.jvm.functions.Function1",
|
||||
"kotlin.Unit")
|
||||
.forEach(type ->
|
||||
reflectionHints.registerTypeIfPresent(classLoader, type,
|
||||
builder -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)));
|
||||
|
||||
hints.resources().registerPattern("META-INF/spring.integration.properties");
|
||||
|
||||
SerializationHints serializationHints = hints.serialization();
|
||||
Stream.of(
|
||||
String.class,
|
||||
Number.class,
|
||||
Long.class,
|
||||
Date.class,
|
||||
ArrayList.class,
|
||||
HashMap.class,
|
||||
Properties.class,
|
||||
Hashtable.class,
|
||||
Exception.class,
|
||||
UUID.class,
|
||||
GenericMessage.class,
|
||||
ErrorMessage.class,
|
||||
MessageHeaders.class,
|
||||
AdviceMessage.class,
|
||||
MutableMessage.class,
|
||||
MutableMessageHeaders.class,
|
||||
MessageGroupMetadata.class,
|
||||
MessageHolder.class,
|
||||
MessageMetadata.class,
|
||||
MessageHistory.class,
|
||||
MessageHistory.Entry.class,
|
||||
DelayHandler.DelayedMessageWrapper.class)
|
||||
.forEach(serializationHints::registerType);
|
||||
|
||||
ProxyHints proxyHints = hints.proxies();
|
||||
|
||||
registerSpringJdkProxy(proxyHints, AbstractReplyProducingMessageHandler.RequestHandler.class);
|
||||
registerSpringJdkProxy(proxyHints, IntegrationFlow.class, SmartLifecycle.class);
|
||||
}
|
||||
|
||||
private static void registerSpringJdkProxy(ProxyHints proxyHints, Class<?>... proxiedInterfaces) {
|
||||
proxyHints
|
||||
.registerJdkProxy(builder ->
|
||||
builder.proxiedInterfaces(proxiedInterfaces)
|
||||
.proxiedInterfaces(SpringProxy.class, Advised.class, DecoratingProxy.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.aot;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCode;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.DecoratingProxy;
|
||||
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
|
||||
/**
|
||||
* {@link BeanRegistrationAotProcessor} for registering proxy interfaces of the {@link GatewayProxyFactoryBean} beans.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
class GatewayProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
|
||||
|
||||
@Override
|
||||
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||
if (GatewayProxyFactoryBean.class.isAssignableFrom(registeredBean.getBeanClass())) {
|
||||
return BeanRegistrationAotContribution
|
||||
.ofBeanRegistrationCodeFragmentsCustomizer(GatewayProxyBeanRegistrationCodeFragments::new);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class GatewayProxyBeanRegistrationCodeFragments extends BeanRegistrationCodeFragments {
|
||||
|
||||
GatewayProxyBeanRegistrationCodeFragments(BeanRegistrationCodeFragments codeFragments) {
|
||||
super(codeFragments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeBlock generateSetBeanDefinitionPropertiesCode(GenerationContext generationContext,
|
||||
BeanRegistrationCode beanRegistrationCode, RootBeanDefinition beanDefinition,
|
||||
Predicate<String> attributeFilter) {
|
||||
|
||||
Class<?> serviceInterface = (Class<?>) beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
|
||||
generationContext.getRuntimeHints().proxies()
|
||||
.registerJdkProxy(serviceInterface, SpringProxy.class, Advised.class, DecoratingProxy.class);
|
||||
|
||||
return super.generateSetBeanDefinitionPropertiesCode(generationContext, beanRegistrationCode,
|
||||
beanDefinition, FactoryBean.OBJECT_TYPE_ATTRIBUTE::equals);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Provides classes to support Spring AOT.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.integration.aot;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
|
||||
import org.springframework.aot.hint.annotation.Reflective;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -123,6 +124,7 @@ public class ConsumerEndpointFactoryBean
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
@Reflective // The native image doesn't see this method because its type is not specific
|
||||
public void setHandler(Object handler) {
|
||||
Assert.isTrue(handler instanceof MessageHandler || handler instanceof ReactiveMessageHandler,
|
||||
"'handler' must be an instance of 'MessageHandler' or 'ReactiveMessageHandler'");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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,8 @@
|
||||
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -44,17 +44,9 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
class ConverterRegistrar implements InitializingBean, ApplicationContextAware {
|
||||
|
||||
private final Set<Object> converters;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
|
||||
ConverterRegistrar() {
|
||||
this(new HashSet<>());
|
||||
}
|
||||
|
||||
ConverterRegistrar(Set<Object> converters) {
|
||||
this.converters = converters;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,11 +67,27 @@ class ConverterRegistrar implements InitializingBean, ApplicationContextAware {
|
||||
}
|
||||
|
||||
private void registerConverters(GenericConversionService conversionService) {
|
||||
this.converters.addAll(this.applicationContext.getBeansWithAnnotation(IntegrationConverter.class).values());
|
||||
Set<Object> converters =
|
||||
this.applicationContext.getBeansOfType(IntegrationConverterRegistration.class)
|
||||
.values()
|
||||
.stream().map(IntegrationConverterRegistration::converter)
|
||||
.collect(Collectors.toSet());
|
||||
if (JacksonPresent.isJackson2Present()) {
|
||||
this.converters.add(new JsonNodeWrapperToJsonNodeConverter());
|
||||
converters.add(new JsonNodeWrapperToJsonNodeConverter());
|
||||
}
|
||||
ConversionServiceFactory.registerConverters(this.converters, conversionService);
|
||||
ConversionServiceFactory.registerConverters(converters, conversionService);
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration supporting bean for converter with a {@link IntegrationConverter}
|
||||
* annotation.
|
||||
*
|
||||
* @param converter the target converter bean with a {@link IntegrationConverter}.
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
record IntegrationConverterRegistration(Object converter) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -23,6 +23,7 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
|
||||
|
||||
import org.springframework.aot.AotDetector;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
@@ -45,7 +46,6 @@ import org.springframework.integration.channel.PublishSubscribeChannel;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.context.IntegrationProperties;
|
||||
import org.springframework.integration.handler.LoggingHandler;
|
||||
import org.springframework.integration.json.JsonNodeWrapperToJsonNodeConverter;
|
||||
import org.springframework.integration.json.JsonPathUtils;
|
||||
import org.springframework.integration.support.DefaultMessageBuilderFactory;
|
||||
import org.springframework.integration.support.SmartLifecycleRoleController;
|
||||
@@ -53,7 +53,6 @@ import org.springframework.integration.support.channel.BeanFactoryChannelResolve
|
||||
import org.springframework.integration.support.channel.ChannelResolverUtils;
|
||||
import org.springframework.integration.support.converter.ConfigurableCompositeMessageConverter;
|
||||
import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter;
|
||||
import org.springframework.integration.support.json.JacksonPresent;
|
||||
import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -108,26 +107,28 @@ public class DefaultConfiguringBeanFactoryPostProcessor
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
this.registry = registry;
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) registry;
|
||||
if (!AotDetector.useGeneratedArtifacts()) {
|
||||
this.registry = registry;
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) registry;
|
||||
|
||||
registerBeanFactoryChannelResolver();
|
||||
registerMessagePublishingErrorHandler();
|
||||
registerNullChannel();
|
||||
registerErrorChannel();
|
||||
registerIntegrationEvaluationContext();
|
||||
registerTaskScheduler();
|
||||
registerIdGeneratorConfigurer();
|
||||
registerIntegrationProperties();
|
||||
registerBuiltInBeans();
|
||||
registerRoleController();
|
||||
registerMessageBuilderFactory();
|
||||
registerHeaderChannelRegistry();
|
||||
registerGlobalChannelInterceptorProcessor();
|
||||
registerDefaultDatatypeChannelMessageConverter();
|
||||
registerArgumentResolverMessageConverter();
|
||||
registerMessageHandlerMethodFactory();
|
||||
registerListMessageHandlerMethodFactory();
|
||||
registerBeanFactoryChannelResolver();
|
||||
registerMessagePublishingErrorHandler();
|
||||
registerNullChannel();
|
||||
registerErrorChannel();
|
||||
registerIntegrationEvaluationContext();
|
||||
registerTaskScheduler();
|
||||
registerIdGeneratorConfigurer();
|
||||
registerIntegrationProperties();
|
||||
registerBuiltInBeans();
|
||||
registerRoleController();
|
||||
registerMessageBuilderFactory();
|
||||
registerHeaderChannelRegistry();
|
||||
registerGlobalChannelInterceptorProcessor();
|
||||
registerDefaultDatatypeChannelMessageConverter();
|
||||
registerArgumentResolverMessageConverter();
|
||||
registerMessageHandlerMethodFactory();
|
||||
registerListMessageHandlerMethodFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,7 +338,6 @@ public class DefaultConfiguringBeanFactoryPostProcessor
|
||||
int registryId = System.identityHashCode(this.registry);
|
||||
jsonPath(registryId);
|
||||
xpath(registryId);
|
||||
jsonNodeToString(registryId);
|
||||
REGISTRIES_PROCESSED.add(registryId);
|
||||
}
|
||||
|
||||
@@ -365,19 +365,6 @@ public class DefaultConfiguringBeanFactoryPostProcessor
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove in 6.0
|
||||
private void jsonNodeToString(int registryId) {
|
||||
if (!this.beanFactory.containsBean(
|
||||
IntegrationContextUtils.JSON_NODE_WRAPPER_TO_JSON_NODE_CONVERTER) &&
|
||||
!REGISTRIES_PROCESSED.contains(registryId) && JacksonPresent.isJackson2Present()) {
|
||||
|
||||
this.registry.registerBeanDefinition(
|
||||
IntegrationContextUtils.JSON_NODE_WRAPPER_TO_JSON_NODE_CONVERTER,
|
||||
new RootBeanDefinition(JsonNodeWrapperToJsonNodeConverter.class,
|
||||
JsonNodeWrapperToJsonNodeConverter::new));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link SmartLifecycleRoleController} if necessary.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -28,7 +28,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.integration.channel.interceptor.GlobalChannelInterceptorWrapper;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -45,42 +45,38 @@ import org.springframework.util.CollectionUtils;
|
||||
*/
|
||||
public class GlobalChannelInterceptorInitializer implements IntegrationConfigurationInitializer {
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
|
||||
for (String beanName : registry.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
if (beanDefinition instanceof AnnotatedBeanDefinition) {
|
||||
AnnotationMetadata metadata = ((AnnotatedBeanDefinition) beanDefinition).getMetadata();
|
||||
Map<String, Object> annotationAttributes =
|
||||
metadata.getAnnotationAttributes(GlobalChannelInterceptor.class.getName());
|
||||
if (CollectionUtils.isEmpty(annotationAttributes)
|
||||
&& beanDefinition.getSource() instanceof MethodMetadata) {
|
||||
MethodMetadata beanMethod = (MethodMetadata) beanDefinition.getSource();
|
||||
annotationAttributes =
|
||||
beanMethod.getAnnotationAttributes(GlobalChannelInterceptor.class.getName()); // NOSONAR not null
|
||||
}
|
||||
Map<String, Object> interceptorAttributes = obtainGlobalChannelInterceptorAttributes(beanDefinition);
|
||||
if (!CollectionUtils.isEmpty(interceptorAttributes)) {
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(GlobalChannelInterceptorWrapper.class)
|
||||
.addConstructorArgReference(beanName)
|
||||
.addPropertyValue("patterns", interceptorAttributes.get("patterns"))
|
||||
.addPropertyValue("order", interceptorAttributes.get("order"));
|
||||
|
||||
if (!CollectionUtils.isEmpty(annotationAttributes)) {
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(GlobalChannelInterceptorWrapper.class,
|
||||
() -> createGlobalChannelInterceptorWrapper(beanName))
|
||||
.addConstructorArgReference(beanName)
|
||||
.addPropertyValue("patterns", annotationAttributes.get("patterns"))
|
||||
.addPropertyValue("order", annotationAttributes.get("order"));
|
||||
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
|
||||
}
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalChannelInterceptorWrapper createGlobalChannelInterceptorWrapper(String interceptorBeanName) {
|
||||
ChannelInterceptor interceptor = this.beanFactory.getBean(interceptorBeanName, ChannelInterceptor.class);
|
||||
return new GlobalChannelInterceptorWrapper(interceptor);
|
||||
@Nullable
|
||||
private static Map<String, Object> obtainGlobalChannelInterceptorAttributes(BeanDefinition beanDefinition) {
|
||||
Map<String, Object> annotationAttributes = null;
|
||||
if (beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
|
||||
AnnotationMetadata metadata = annotatedBeanDefinition.getMetadata();
|
||||
annotationAttributes = metadata.getAnnotationAttributes(GlobalChannelInterceptor.class.getName());
|
||||
if (CollectionUtils.isEmpty(annotationAttributes)
|
||||
&& beanDefinition.getSource() instanceof MethodMetadata beanMethod) {
|
||||
|
||||
annotationAttributes = beanMethod.getAnnotationAttributes(GlobalChannelInterceptor.class.getName());
|
||||
}
|
||||
}
|
||||
return annotationAttributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aot.AotDetector;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -31,20 +32,23 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class IntegrationConfigurationBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) registry;
|
||||
if (!AotDetector.useGeneratedArtifacts()) {
|
||||
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) registry;
|
||||
|
||||
List<IntegrationConfigurationInitializer> initializers =
|
||||
SpringFactoriesLoader.loadFactories(IntegrationConfigurationInitializer.class,
|
||||
beanFactory.getBeanClassLoader());
|
||||
List<IntegrationConfigurationInitializer> initializers =
|
||||
SpringFactoriesLoader.loadFactories(IntegrationConfigurationInitializer.class,
|
||||
beanFactory.getBeanClassLoader());
|
||||
|
||||
for (IntegrationConfigurationInitializer initializer : initializers) {
|
||||
initializer.initialize(beanFactory);
|
||||
for (IntegrationConfigurationInitializer initializer : initializers) {
|
||||
initializer.initialize(beanFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2021 the original author or authors.
|
||||
* Copyright 2014-2022 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.
|
||||
@@ -17,15 +17,28 @@
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
|
||||
/**
|
||||
* The {@link IntegrationConfigurationInitializer} to populate
|
||||
* {@link ConverterRegistrar.IntegrationConverterRegistration}
|
||||
* for converter beans marked with an {@link IntegrationConverter} annotation.
|
||||
* <p>
|
||||
* {@link org.springframework.context.annotation.Bean} methods are also processed.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class IntegrationConverterInitializer implements IntegrationConfigurationInitializer {
|
||||
@@ -34,6 +47,17 @@ public class IntegrationConverterInitializer implements IntegrationConfiguration
|
||||
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
|
||||
for (String beanName : registry.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
if (isIntegrationConverter(beanDefinition)) {
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(
|
||||
ConverterRegistrar.IntegrationConverterRegistration.class)
|
||||
.addConstructorArgReference(beanName);
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
|
||||
}
|
||||
}
|
||||
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME)) {
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME,
|
||||
new RootBeanDefinition(ConverterRegistrar.class, ConverterRegistrar::new));
|
||||
@@ -44,6 +68,19 @@ public class IntegrationConverterInitializer implements IntegrationConfiguration
|
||||
new RootBeanDefinition(CustomConversionServiceFactoryBean.class,
|
||||
CustomConversionServiceFactoryBean::new));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean isIntegrationConverter(BeanDefinition beanDefinition) {
|
||||
boolean hasIntegrationConverter = false;
|
||||
if (beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
|
||||
AnnotationMetadata metadata = annotatedBeanDefinition.getMetadata();
|
||||
hasIntegrationConverter = metadata.hasAnnotation(IntegrationConverter.class.getName());
|
||||
if (!hasIntegrationConverter && beanDefinition.getSource() instanceof MethodMetadata beanMethodMetadata) {
|
||||
hasIntegrationConverter = beanMethodMetadata.isAnnotated(IntegrationConverter.class.getName());
|
||||
}
|
||||
}
|
||||
return hasIntegrationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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,18 +16,15 @@
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
@@ -61,32 +58,13 @@ public class ConverterParser extends AbstractBeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void registerConverter(BeanDefinitionRegistry registry,
|
||||
BeanMetadataElement converterBeanDefinition) {
|
||||
|
||||
Set<BeanMetadataElement> converters = new ManagedSet<>();
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder converterRegistrarBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationContextUtils.BASE_PACKAGE + ".config.ConverterRegistrar")
|
||||
.addConstructorArgValue(converters);
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME,
|
||||
converterRegistrarBuilder.getBeanDefinition());
|
||||
}
|
||||
else {
|
||||
BeanDefinition converterRegistrarBeanDefinition = registry
|
||||
.getBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME);
|
||||
converters = (Set<BeanMetadataElement>) converterRegistrarBeanDefinition
|
||||
.getConstructorArgumentValues()
|
||||
.getIndexedArgumentValues()
|
||||
.values()
|
||||
.iterator()
|
||||
.next()
|
||||
.getValue();
|
||||
}
|
||||
|
||||
converters.add(converterBeanDefinition); // NOSONAR never null
|
||||
private static void registerConverter(BeanDefinitionRegistry registry, BeanMetadataElement targetBeanDefinition) {
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationContextUtils.BASE_PACKAGE +
|
||||
".config.ConverterRegistrar.IntegrationConverterRegistration")
|
||||
.addConstructorArgValue(targetBeanDefinition);
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2020 the original author or authors.
|
||||
* Copyright 2018-2022 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
* Copyright 2020-2022 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.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=org.springframework.integration.aot.CoreRuntimeHints
|
||||
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=org.springframework.integration.aot.GatewayProxyBeanRegistrationAotProcessor
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
* Copyright 2013-2022 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.
|
||||
@@ -17,14 +17,13 @@
|
||||
package org.springframework.integration.expression;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -34,6 +33,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
@@ -41,12 +41,17 @@ import org.springframework.integration.config.IntegrationEvaluationContextFactor
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.json.JsonPathUtils;
|
||||
import org.springframework.integration.json.TestPerson;
|
||||
import org.springframework.integration.support.MutableMessage;
|
||||
import org.springframework.integration.support.MutableMessageBuilder;
|
||||
import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
@@ -74,7 +79,7 @@ public class ParentContextTests {
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSpelBeanReferencesInChildAndParent() {
|
||||
public void testSpelBeanReferencesInChildAndParent() throws ClassNotFoundException {
|
||||
AbstractApplicationContext parent = new ClassPathXmlApplicationContext("ParentContext-context.xml",
|
||||
this.getClass());
|
||||
|
||||
@@ -153,40 +158,21 @@ public class ParentContextTests {
|
||||
IntegrationEvaluationContextFactoryBean evaluationContextFactoryBean =
|
||||
child.getBean("&" + IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
|
||||
IntegrationEvaluationContextFactoryBean.class);
|
||||
try {
|
||||
evaluationContextFactoryBean.setPropertyAccessors(Collections.emptyMap());
|
||||
fail("IllegalArgumentException expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> evaluationContextFactoryBean.setPropertyAccessors(Collections.emptyMap()));
|
||||
|
||||
parent.getBean("fromParentToChild", MessageChannel.class).send(new GenericMessage<>("foo"));
|
||||
out = child.getBean("output", QueueChannel.class).receive(0);
|
||||
assertThat(out).isNotNull();
|
||||
assertThat(out.getClass().getName()).isEqualTo("org.springframework.integration.support.MutableMessage");
|
||||
assertThat(out).isInstanceOf(MutableMessage.class);
|
||||
assertThat(out.getPayload()).isEqualTo("FOO");
|
||||
|
||||
assertThat(parent
|
||||
.containsBean(IntegrationContextUtils.JSON_NODE_WRAPPER_TO_JSON_NODE_CONVERTER))
|
||||
.isTrue();
|
||||
|
||||
assertThat(child
|
||||
.containsBean(IntegrationContextUtils.JSON_NODE_WRAPPER_TO_JSON_NODE_CONVERTER))
|
||||
.isTrue();
|
||||
|
||||
Object converterRegistrar = parent.getBean(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME);
|
||||
assertThat(converterRegistrar).isNotNull();
|
||||
Set<?> converters = TestUtils.getPropertyValue(converterRegistrar, "converters", Set.class);
|
||||
boolean jsonNodeWrapperToJsonNodeConverterPresent = false;
|
||||
for (Object converter : converters) {
|
||||
if ("JsonNodeWrapperToJsonNodeConverter".equals(converter.getClass().getSimpleName())) {
|
||||
jsonNodeWrapperToJsonNodeConverterPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(jsonNodeWrapperToJsonNodeConverterPresent).isTrue();
|
||||
ConversionService conversionService = IntegrationUtils.getConversionService(parent);
|
||||
Class<?> jsonNodeWrapperClass =
|
||||
ClassUtils.forName("org.springframework.integration.json.JsonPropertyAccessor.JsonNodeWrapper",
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
assertThat(conversionService.canConvert(jsonNodeWrapperClass, JsonNode.class)).isTrue();
|
||||
|
||||
MessageChannel input = parent.getBean("testJsonNodeToStringConverterInputChannel", MessageChannel.class);
|
||||
PollableChannel output = parent.getBean("testJsonNodeToStringConverterOutputChannel", PollableChannel.class);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file.aot;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.SerializationHints;
|
||||
import org.springframework.integration.file.splitter.FileSplitter;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for Spring Integration file module.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
class FileRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
SerializationHints serializationHints = hints.serialization();
|
||||
Stream.of(FileSplitter.FileMarker.class, FileSplitter.FileMarker.Mark.class)
|
||||
.forEach(serializationHints::registerType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Provides classes to support Spring AOT.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.integration.file.aot;
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=org.springframework.integration.file.aot.FileRuntimeHints
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.http.aot;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.server.WebHandler;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for Spring Integration core module.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
class HttpRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
ReflectionHints reflectionHints = hints.reflection();
|
||||
reflectionHints.registerType(WebHandler.class, builder ->
|
||||
builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
|
||||
reflectionHints.registerType(HttpRequestHandler.class, builder ->
|
||||
builder.onReachableType(TypeReference.of("jakarta.servlet.http.HttpServletRequest"))
|
||||
.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Provides classes to support Spring AOT.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.integration.http.aot;
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=org.springframework.integration.http.aot.HttpRuntimeHints
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.jdbc.aot;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for Spring Integration JDBC module.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
class JdbcRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
hints.resources().registerPattern("org/springframework/integration/jdbc/schema-*.sql");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Provides classes to support Spring AOT.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.integration.jdbc.aot;
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=org.springframework.integration.jdbc.aot.JdbcRuntimeHints
|
||||
@@ -275,12 +275,11 @@ class WebFluxRequestExecutingMessageHandlerTests {
|
||||
|
||||
StepVerifier.create(
|
||||
response.getBody()
|
||||
.map(dataBuffer -> new String(dataBuffer.asByteBuffer().array())))
|
||||
.map(dataBuffer -> new String(dataBuffer.toByteBuffer().array())))
|
||||
.expectNext("foo", "bar", "baz")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testClientHttpResponseErrorAsReply() {
|
||||
ClientHttpConnector httpConnector = new HttpHandlerConnector((request, response) -> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -110,24 +110,6 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be
|
||||
|
||||
private String[] xsltParamHeaders;
|
||||
|
||||
private static final Class<?> SERVLET_CONTEXT_RESOURCE_CLASS;
|
||||
|
||||
static {
|
||||
Class<?> aClass = null;
|
||||
try {
|
||||
aClass =
|
||||
ClassUtils.forName("org.springframework.web.context.support.ServletContextResource",
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
catch (ClassNotFoundException e) {
|
||||
// No 'ServletContextResource' class present - ignoring
|
||||
}
|
||||
finally {
|
||||
SERVLET_CONTEXT_RESOURCE_CLASS = aClass;
|
||||
}
|
||||
}
|
||||
|
||||
public XsltPayloadTransformer(Templates templates) {
|
||||
this(templates, null);
|
||||
}
|
||||
@@ -160,8 +142,8 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be
|
||||
Assert.isTrue(xslResource instanceof ClassPathResource ||
|
||||
xslResource instanceof FileSystemResource ||
|
||||
xslResource instanceof VfsResource || // NOSONAR boolean complexity
|
||||
(SERVLET_CONTEXT_RESOURCE_CLASS != null
|
||||
&& SERVLET_CONTEXT_RESOURCE_CLASS.isInstance(xslResource)),
|
||||
xslResource.getClass().getName()
|
||||
.equals("org.springframework.web.context.support.ServletContextResource"),
|
||||
"Only 'ClassPathResource', 'FileSystemResource', 'ServletContextResource' or 'VfsResource'" +
|
||||
" are supported directly in this transformer. For any other 'Resource' implementations" +
|
||||
" consider to use a 'Templates'-based constructor instantiation.");
|
||||
@@ -288,7 +270,7 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be
|
||||
else {
|
||||
payload = message.getPayload();
|
||||
}
|
||||
Object transformedPayload = null;
|
||||
Object transformedPayload;
|
||||
if (this.alwaysUseResultFactory) {
|
||||
transformedPayload = transformUsingResultFactory(payload, transformer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user