GH-258 Polishing around duplicqte registration

Removwd formatter plugin
Added additional test

Resolves #258
Resolves #259
This commit is contained in:
Oleg Zhurakousky
2019-02-15 10:15:13 +01:00
parent 95a462467e
commit 94106dba48
3 changed files with 130 additions and 54 deletions

View File

@@ -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<ConfigurableApplicationContext> initializer =
(ApplicationContextInitializer<ConfigurableApplicationContext>) 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,

View File

@@ -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<String, String> {
@Override
public String apply(String t) {
System.out.println("Receoved " + t);
return t;
}
@Bean
public Function<String, String> foo() {
return x -> x;
}
}
}