Change FunctionCatalog to key off Class<?>
Makes it possible to support other "function" types in the future. The user is always taking a risk with the lookup that the object returned has the generic type desired (but that hasn't changed with this commit). FunctionCatalog is a lot simpler as a result and also a lot more flexible.
This commit is contained in:
@@ -30,7 +30,6 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -52,8 +51,11 @@ public class FunctionController {
|
||||
|
||||
private boolean debug = false;
|
||||
|
||||
public FunctionController(FunctionInspector inspector) {
|
||||
private StringConverter converter;
|
||||
|
||||
public FunctionController(FunctionInspector inspector, StringConverter converter) {
|
||||
this.inspector = inspector;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
@@ -115,9 +117,8 @@ public class FunctionController {
|
||||
return debug ? result.log() : result;
|
||||
}
|
||||
|
||||
private Mono<?> value(Function<Flux<?>, Flux<?>> function,
|
||||
@PathVariable String value) {
|
||||
Object input = inspector.convert(function, value);
|
||||
private Mono<?> value(Function<Flux<?>, Flux<?>> function, String value) {
|
||||
Object input = converter.convert(function, value);
|
||||
Mono<?> result = Mono.from(function.apply(Flux.just(input)));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Handled GET with function");
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.cloud.function.web.flux.constants.WebRequestConstants;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -55,11 +54,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
||||
private String debug = "false";
|
||||
|
||||
@Autowired
|
||||
public FunctionHandlerMapping(FunctionCatalog catalog, FunctionInspector inspector) {
|
||||
public FunctionHandlerMapping(FunctionCatalog catalog,
|
||||
FunctionController controller) {
|
||||
this.functions = catalog;
|
||||
logger.info("FunctionCatalog: " + catalog + ", FunctionInspector: " + inspector);
|
||||
logger.info("FunctionCatalog: " + catalog);
|
||||
setOrder(super.getOrder() - 5);
|
||||
this.controller = new FunctionController(inspector);
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,12 +118,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
||||
return null;
|
||||
}
|
||||
path = path.startsWith("/") ? path.substring(1) : path;
|
||||
Consumer<Object> consumer = functions.lookupConsumer(path);
|
||||
Consumer<Object> consumer = functions.lookup(Consumer.class, path);
|
||||
if (consumer != null) {
|
||||
request.setAttribute(WebRequestConstants.CONSUMER, consumer);
|
||||
return consumer;
|
||||
}
|
||||
Function<Object, Object> function = functions.lookupFunction(path);
|
||||
Function<Object, Object> function = functions.lookup(Function.class, path);
|
||||
if (function != null) {
|
||||
request.setAttribute(WebRequestConstants.FUNCTION, function);
|
||||
return function;
|
||||
@@ -136,7 +136,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
||||
return null;
|
||||
}
|
||||
path = path.startsWith("/") ? path.substring(1) : path;
|
||||
Supplier<Object> supplier = functions.lookupSupplier(path);
|
||||
Supplier<Object> supplier = functions.lookup(Supplier.class, path);
|
||||
if (supplier != null) {
|
||||
request.setAttribute(WebRequestConstants.SUPPLIER, supplier);
|
||||
return supplier;
|
||||
@@ -152,7 +152,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
||||
name = builder.toString();
|
||||
value = path.length() > name.length() ? path.substring(name.length() + 1)
|
||||
: null;
|
||||
Function<Object, Object> function = functions.lookupFunction(name);
|
||||
Function<Object, Object> function = functions.lookup(Function.class, name);
|
||||
if (function != null) {
|
||||
request.setAttribute(WebRequestConstants.FUNCTION, function);
|
||||
request.setAttribute(WebRequestConstants.ARGUMENT, value);
|
||||
|
||||
@@ -23,8 +23,10 @@ import com.google.gson.Gson;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
@@ -36,6 +38,9 @@ import org.springframework.cloud.function.web.flux.response.FluxReturnValueHandl
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -54,6 +59,7 @@ import reactor.core.publisher.Flux;
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnClass({ Flux.class, AsyncHandlerMethodReturnValueHandler.class })
|
||||
@AutoConfigureBefore(HttpMessageConvertersAutoConfiguration.class)
|
||||
@Import(FunctionController.class)
|
||||
public class ReactorAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -61,8 +67,15 @@ public class ReactorAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public FunctionHandlerMapping functionHandlerMapping(FunctionCatalog catalog,
|
||||
FunctionInspector inspector) {
|
||||
return new FunctionHandlerMapping(catalog, inspector);
|
||||
FunctionController controller) {
|
||||
return new FunctionHandlerMapping(catalog, controller);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public StringConverter functionStringConverter(FunctionInspector inspector,
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
return new BasicStringConverter(inspector, beanFactory);
|
||||
}
|
||||
|
||||
// TODO: remove this when https://jira.spring.io/browse/SPR-16529 is resolved
|
||||
@@ -125,4 +138,32 @@ public class ReactorAutoConfiguration {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static class BasicStringConverter implements StringConverter {
|
||||
|
||||
private ConversionService conversionService;
|
||||
private ConfigurableListableBeanFactory registry;
|
||||
private FunctionInspector inspector;
|
||||
|
||||
public BasicStringConverter(FunctionInspector inspector,
|
||||
ConfigurableListableBeanFactory registry) {
|
||||
this.inspector = inspector;
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convert(Object function, String value) {
|
||||
if (conversionService == null && registry != null) {
|
||||
ConversionService conversionService = this.registry
|
||||
.getConversionService();
|
||||
this.conversionService = conversionService != null ? conversionService
|
||||
: new DefaultConversionService();
|
||||
}
|
||||
Class<?> type = inspector.getInputType(function);
|
||||
return conversionService.canConvert(String.class, type)
|
||||
? conversionService.convert(value, type)
|
||||
: value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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.web.flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface StringConverter {
|
||||
|
||||
Object convert(Object function, String value);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user