From 94106dba485f741b3a278c871bbd6b42cbfc2870 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Fri, 15 Feb 2019 10:15:13 +0100 Subject: [PATCH] GH-258 Polishing around duplicqte registration Removwd formatter plugin Added additional test Resolves #258 Resolves #259 --- pom.xml | 4 - .../context/FunctionalSpringApplication.java | 113 ++++++++++-------- .../HybridFunctionalRegistrationTests.java | 67 +++++++++++ 3 files changed, 130 insertions(+), 54 deletions(-) create mode 100644 spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/HybridFunctionalRegistrationTests.java diff --git a/pom.xml b/pom.xml index c614752b9..8409a5dd9 100644 --- a/pom.xml +++ b/pom.xml @@ -100,10 +100,6 @@ org.apache.maven.plugins maven-checkstyle-plugin - - io.spring.javaformat - spring-javaformat-maven-plugin - diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java index 0dd395aec..e15f6d861 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2017-2019 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.cloud.function.context; -import static java.util.Arrays.stream; - import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -34,11 +32,16 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; + +import static java.util.Arrays.stream; /** * @author Dave Syer - * + * @author Semyon Fishman + * @author Oleg Zhurakousky */ public class FunctionalSpringApplication extends org.springframework.boot.SpringApplication { @@ -84,62 +87,72 @@ public class FunctionalSpringApplication return new FunctionalSpringApplication(primarySources).run(args); } + @SuppressWarnings("unchecked") @Override protected void postProcessApplicationContext(ConfigurableApplicationContext context) { super.postProcessApplicationContext(context); boolean functional = false; - if (context instanceof GenericApplicationContext) { - GenericApplicationContext generic = (GenericApplicationContext) context; - for (Object source : getAllSources()) { - Class type = null; - Object handler = null; - if (source instanceof String) { - String name = (String) source; - if (ClassUtils.isPresent(name, null)) { - type = ClassUtils.resolveClassName(name, null); - } + Assert.isInstanceOf(GenericApplicationContext.class, context, + "ApplicationContext must be an instanceof GenericApplicationContext"); + for (Object source : getAllSources()) { + Class type = null; + Object handler = null; + if (source instanceof String) { + String name = (String) source; + if (ClassUtils.isPresent(name, null)) { + type = ClassUtils.resolveClassName(name, null); } - else if (source instanceof Class) { - type = (Class) source; + } + else if (source instanceof Class) { + type = (Class) source; + } + else { + type = source.getClass(); + handler = source; + } + if (ApplicationContextInitializer.class.isAssignableFrom(type)) { + if (handler == null) { + handler = BeanUtils.instantiateClass(type); + } + + ApplicationContextInitializer initializer = + (ApplicationContextInitializer) handler; + initializer.initialize(context); + functional = true; + } + else if (Function.class.isAssignableFrom(type) + || Consumer.class.isAssignableFrom(type) + || Supplier.class.isAssignableFrom(type)) { + Class functionType = type; + Object function = handler; + if (source.equals(functionType)) { + context.addBeanFactoryPostProcessor(beanFactory -> { + BeanDefinitionRegistry bdRegistry = (BeanDefinitionRegistry) beanFactory; + if (!ObjectUtils.isEmpty(context.getBeanNamesForType(functionType))) { + stream(context.getBeanNamesForType(functionType)) + .forEach(beanName -> bdRegistry.registerAlias(beanName, "function")); + } + else { + this.register((GenericApplicationContext) context, function, functionType); + } + }); } else { - type = source.getClass(); - handler = source; + this.register((GenericApplicationContext) context, function, functionType); } - if (type != null) { - if (ApplicationContextInitializer.class.isAssignableFrom(type)) { - if (handler == null) { - handler = BeanUtils.instantiateClass(type); - } - @SuppressWarnings("unchecked") - ApplicationContextInitializer initializer = (ApplicationContextInitializer) handler; - initializer.initialize(generic); - functional = true; - } - else if (Function.class.isAssignableFrom(type) - || Consumer.class.isAssignableFrom(type) - || Supplier.class.isAssignableFrom(type)) { - Class functionType = type; - Object function = handler; - generic.registerBean("function", FunctionRegistration.class, - () -> new FunctionRegistration<>( - handler(generic, function, functionType)) - .type(FunctionType.of(functionType))); - if (source.equals(functionType)) { - context.addBeanFactoryPostProcessor(beanFactory -> { - BeanDefinitionRegistry bdRegistry = (BeanDefinitionRegistry) beanFactory; - stream(beanFactory.getBeanNamesForType(functionType)) - .forEach(bdRegistry::removeBeanDefinition); - }); - } - functional = true; - } - } - } - if (functional) { - defaultProperties(generic); + functional = true; } } + if (functional) { + defaultProperties(context); + } + } + + private void register(GenericApplicationContext context, Object function, Class functionType) { + context.registerBean("function", FunctionRegistration.class, + () -> new FunctionRegistration<>( + handler(context, function, functionType)) + .type(FunctionType.of(functionType))); } private Object handler(GenericApplicationContext generic, Object handler, diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/HybridFunctionalRegistrationTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/HybridFunctionalRegistrationTests.java new file mode 100644 index 000000000..fd420a085 --- /dev/null +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/HybridFunctionalRegistrationTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2019 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 + * + * http://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.cloud.function.context; + +import java.util.function.Function; + +import org.junit.Test; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * + * @author Oleg Zhurakousky + * + */ +public class HybridFunctionalRegistrationTests { + + // see https://github.com/spring-cloud/spring-cloud-function/issues/258 + @Test + public void testNoDoubleRegistrationInHybridMode() { + ConfigurableApplicationContext context = FunctionalSpringApplication + .run(UppercaseFunction.class, "--spring.functional.enabled=false"); + assertThat(context.containsBean("function")).isTrue(); + assertThat(context.getBeansOfType(UppercaseFunction.class).size()).isEqualTo(1); + } + + @SpringBootConfiguration + @ImportAutoConfiguration({ + ContextFunctionCatalogAutoConfiguration.class, + JacksonAutoConfiguration.class } + ) + public static class UppercaseFunction implements Function { + + @Override + public String apply(String t) { + System.out.println("Receoved " + t); + return t; + } + + @Bean + public Function foo() { + return x -> x; + } + } + +}