Turned on checkstyle

This commit is contained in:
Marcin Grzejszczak
2019-02-01 15:48:32 +01:00
parent 94e9b8f2f8
commit e4b08a083c
268 changed files with 5114 additions and 3993 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 the original author or authors.
* Copyright 2012-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.
@@ -22,9 +22,7 @@ import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.StringUtils;
/**
*
* @author Oleg Zhurakousky
*
* @since 2.0.1
*
*/
@@ -33,12 +31,14 @@ public abstract class AbstractFunctionRegistry implements FunctionRegistry {
@Autowired
private Environment environment = new StandardEnvironment();
public <T> T lookup(Class<?> type, String name) {
String functionDefinitionName = !StringUtils.hasText(name) && environment.containsProperty("spring.cloud.function.definition")
? environment.getProperty("spring.cloud.function.definition") : name;
String functionDefinitionName = !StringUtils.hasText(name)
&& this.environment.containsProperty("spring.cloud.function.definition")
? this.environment.getProperty("spring.cloud.function.definition")
: name;
return this.doLookup(type, functionDefinitionName);
}
protected abstract <T> T doLookup(Class<?> type, String name);
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-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
* 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,
@@ -25,20 +25,20 @@ import java.util.Set;
public interface FunctionCatalog {
/**
* Will look up the instance of the functional interface by name only
*
* Will look up the instance of the functional interface by name only.
* @param <T> instance type
* @param name the name of the functional interface. Must not be null;
* @return instance of the functional interface registered with this catalog
*/
default public <T> T lookup(String name) {
default <T> T lookup(String name) {
return this.lookup(null, name);
}
/**
* Will look up the instance of the functional interface by name and type
* which can only be Supplier, Consumer or Function. If type is not provided, the lookup
* will be made based on name only
*
* Will look up the instance of the functional interface by name and type which can
* only be Supplier, Consumer or Function. If type is not provided, the lookup will be
* made based on name only.
* @param <T> instance type
* @param type the type of functional interface. Can be null
* @param name the name of the functional interface. Must not be null;
* @return instance of the functional interface registered with this catalog
@@ -48,11 +48,12 @@ public interface FunctionCatalog {
Set<String> getNames(Class<?> type);
/**
* Return the count of functions registered in this catalog
* Return the count of functions registered in this catalog.
* @return the count of functions registered in this catalog
*/
default int size() {
throw new UnsupportedOperationException("This instance of FunctionCatalog does not support this operation");
throw new UnsupportedOperationException(
"This instance of FunctionCatalog does not support this operation");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-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.
@@ -27,6 +27,9 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.cloud.function.core.FluxConsumer;
import org.springframework.cloud.function.core.FluxFunction;
@@ -34,26 +37,23 @@ import org.springframework.cloud.function.core.FluxSupplier;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @param <T> target type
* @author Dave Syer
* @author Oleg Zhurakousky
*/
public class FunctionRegistration<T> implements BeanNameAware {
private T target;
private final Set<String> names = new LinkedHashSet<>();
private final Map<String, String> properties = new LinkedHashMap<>();
private T target;
private FunctionType type;
/**
* Creates instance of FunctionRegistration.
*
* @param target instance of {@link Supplier}, {@link Function} or {@link Consumer}
* @param names additional set of names for this registration. Additional names can be
* provided {@link #name(String)} or {@link #names(String...)} operations.
@@ -65,15 +65,11 @@ public class FunctionRegistration<T> implements BeanNameAware {
}
public Map<String, String> getProperties() {
return properties;
return this.properties;
}
public Set<String> getNames() {
return names;
}
public FunctionType getType() {
return type;
return this.names;
}
/**
@@ -81,15 +77,19 @@ public class FunctionRegistration<T> implements BeanNameAware {
* want to add a name or set or names to the existing set of names use
* {@link #names(Collection)} or {@link #name(String)} or {@link #names(String...)}
* operations.
* @param names
* @param names - bean names
*/
public void setNames(Set<String> names) {
this.names.clear();
this.names.addAll(names);
}
public FunctionType getType() {
return this.type;
}
public T getTarget() {
return target;
return this.target;
}
public FunctionRegistration<T> properties(Map<String, String> properties) {
@@ -133,7 +133,7 @@ public class FunctionRegistration<T> implements BeanNameAware {
}
public <S> FunctionRegistration<S> wrap() {
if (type == null || type.isWrapper()) {
if (this.type == null || this.type.isWrapper()) {
@SuppressWarnings("unchecked")
FunctionRegistration<S> value = (FunctionRegistration<S>) this;
return value;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.context;
import java.lang.reflect.ParameterizedType;
@@ -23,18 +24,21 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.messaging.Message;
import reactor.core.publisher.Flux;
/**
* @author Dave Syer
*
*/
public class FunctionType {
/**
* Unclassified function types.
*/
public static FunctionType UNCLASSIFIED = new FunctionType(ResolvableType
.forClassWithGenerics(Function.class, Object.class, Object.class).getType());
@@ -61,34 +65,6 @@ public class FunctionType {
this.message = messageType();
}
public Type getType() {
return type;
}
public Class<?> getInputWrapper() {
return inputWrapper;
}
public Class<?> getOutputWrapper() {
return outputWrapper;
}
public Class<?> getInputType() {
return inputType;
}
public Class<?> getOutputType() {
return outputType;
}
public boolean isMessage() {
return message;
}
public boolean isWrapper() {
return isWrapper(getInputWrapper()) || isWrapper(getOutputWrapper());
}
public static boolean isWrapper(Type type) {
if (type instanceof ParameterizedType) {
type = ((ParameterizedType) type).getRawType();
@@ -125,6 +101,91 @@ public class FunctionType {
ResolvableType.forClassWithGenerics(Consumer.class, input).getType());
}
public static FunctionType compose(FunctionType input, FunctionType output) {
ResolvableType inputGeneric = input(input);
ResolvableType outputGeneric = output(output);
if (!isWrapper(outputGeneric.getType())) {
ResolvableType inputOutput = output(input);
if (isWrapper(inputOutput.getType())) {
outputGeneric = wrap(input,
extractClass(inputOutput.getType(), ParamType.OUTPUT_WRAPPER),
extractClass(outputGeneric.getType(), ParamType.OUTPUT));
}
}
return new FunctionType(ResolvableType
.forClassWithGenerics(Function.class, inputGeneric, outputGeneric)
.getType());
}
private static ResolvableType wrap(FunctionType input, Class<?> wrapper,
Class<?> type) {
return input.isMessage() ? wrap(wrapper, message(type))
: ResolvableType.forClassWithGenerics(wrapper, type);
}
private static ResolvableType wrap(Class<?> wrapper, ResolvableType type) {
return ResolvableType.forClassWithGenerics(wrapper, type);
}
private static ResolvableType message(Class<?> type) {
return ResolvableType.forClassWithGenerics(Message.class, type);
}
private static ResolvableType input(FunctionType type) {
return type.input(type.getInputType());
}
private static ResolvableType output(FunctionType type) {
return type.output(type.getOutputType());
}
private static Class<?> extractClass(Type param, ParamType paramType) {
if (param instanceof ParameterizedType) {
ParameterizedType concrete = (ParameterizedType) param;
param = concrete.getRawType();
}
if (param == null) {
// Last ditch attempt to guess: Flux<String>
if (paramType.isWrapper()) {
param = Flux.class;
}
else {
param = String.class;
}
}
Class<?> result = param instanceof Class ? (Class<?>) param : null;
// TODO: cache result
return result;
}
public Type getType() {
return this.type;
}
public Class<?> getInputWrapper() {
return this.inputWrapper;
}
public Class<?> getOutputWrapper() {
return this.outputWrapper;
}
public Class<?> getInputType() {
return this.inputType;
}
public Class<?> getOutputType() {
return this.outputType;
}
public boolean isMessage() {
return this.message;
}
public boolean isWrapper() {
return isWrapper(getInputWrapper()) || isWrapper(getOutputWrapper());
}
public FunctionType to(Class<?> output) {
ResolvableType inputGeneric = input(this);
ResolvableType outputGeneric = output(output);
@@ -173,73 +234,69 @@ public class FunctionType {
return wrap(wrapper, wrapper);
}
public static FunctionType compose(FunctionType input, FunctionType output) {
ResolvableType inputGeneric = input(input);
ResolvableType outputGeneric = output(output);
if (!isWrapper(outputGeneric.getType())) {
ResolvableType inputOutput = output(input);
if (isWrapper(inputOutput.getType())) {
outputGeneric = wrap(input,
extractClass(inputOutput.getType(), ParamType.OUTPUT_WRAPPER),
extractClass(outputGeneric.getType(), ParamType.OUTPUT));
}
}
return new FunctionType(ResolvableType
.forClassWithGenerics(Function.class, inputGeneric, outputGeneric)
.getType());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((inputType == null) ? 0 : inputType.toString().hashCode());
+ ((this.inputType == null) ? 0 : this.inputType.toString().hashCode());
result = prime * result + ((this.inputWrapper == null) ? 0
: this.inputWrapper.toString().hashCode());
result = prime * result + (this.message ? 1231 : 1237);
result = prime * result
+ ((inputWrapper == null) ? 0 : inputWrapper.toString().hashCode());
result = prime * result + (message ? 1231 : 1237);
result = prime * result
+ ((outputType == null) ? 0 : outputType.toString().hashCode());
result = prime * result
+ ((outputWrapper == null) ? 0 : outputWrapper.toString().hashCode());
+ ((this.outputType == null) ? 0 : this.outputType.toString().hashCode());
result = prime * result + ((this.outputWrapper == null) ? 0
: this.outputWrapper.toString().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
if (this == obj) {
return true;
if (obj == null)
}
if (obj == null) {
return false;
if (getClass() != obj.getClass())
}
if (getClass() != obj.getClass()) {
return false;
}
FunctionType other = (FunctionType) obj;
if (inputType == null) {
if (other.inputType != null)
if (this.inputType == null) {
if (other.inputType != null) {
return false;
}
}
else if (!inputType.toString().equals(other.inputType.toString()))
else if (!this.inputType.toString().equals(other.inputType.toString())) {
return false;
if (inputWrapper == null) {
if (other.inputWrapper != null)
}
if (this.inputWrapper == null) {
if (other.inputWrapper != null) {
return false;
}
}
else if (!inputWrapper.toString().equals(other.inputWrapper.toString()))
else if (!this.inputWrapper.toString().equals(other.inputWrapper.toString())) {
return false;
if (message != other.message)
}
if (this.message != other.message) {
return false;
if (outputType == null) {
if (other.outputType != null)
}
if (this.outputType == null) {
if (other.outputType != null) {
return false;
}
}
else if (!outputType.toString().equals(other.outputType.toString()))
else if (!this.outputType.toString().equals(other.outputType.toString())) {
return false;
if (outputWrapper == null) {
if (other.outputWrapper != null)
}
if (this.outputWrapper == null) {
if (other.outputWrapper != null) {
return false;
}
}
else if (!outputWrapper.toString().equals(other.outputWrapper.toString()))
else if (!this.outputWrapper.toString().equals(other.outputWrapper.toString())) {
return false;
}
return true;
}
@@ -247,28 +304,6 @@ public class FunctionType {
return wrap(this, wrapper, type);
}
private static ResolvableType wrap(FunctionType input, Class<?> wrapper,
Class<?> type) {
return input.isMessage() ? wrap(wrapper, message(type))
: ResolvableType.forClassWithGenerics(wrapper, type);
}
private static ResolvableType wrap(Class<?> wrapper, ResolvableType type) {
return ResolvableType.forClassWithGenerics(wrapper, type);
}
private static ResolvableType message(Class<?> type) {
return ResolvableType.forClassWithGenerics(Message.class, type);
}
private static ResolvableType input(FunctionType type) {
return type.input(type.getInputType());
}
private static ResolvableType output(FunctionType type) {
return type.output(type.getOutputType());
}
private ResolvableType output(Class<?> type) {
ResolvableType generic;
ResolvableType raw = ResolvableType.forClass(type);
@@ -331,25 +366,6 @@ public class FunctionType {
return Object.class;
}
private static Class<?> extractClass(Type param, ParamType paramType) {
if (param instanceof ParameterizedType) {
ParameterizedType concrete = (ParameterizedType) param;
param = concrete.getRawType();
}
if (param == null) {
// Last ditch attempt to guess: Flux<String>
if (paramType.isWrapper()) {
param = Flux.class;
}
else {
param = String.class;
}
}
Class<?> result = param instanceof Class ? (Class<?>) param : null;
// TODO: cache result
return result;
}
private Type extractType(Type type, ParamType paramType, int index) {
Type param;
if (type instanceof ParameterizedType) {
@@ -442,6 +458,7 @@ public class FunctionType {
}
enum ParamType {
INPUT, OUTPUT, INPUT_WRAPPER, OUTPUT_WRAPPER, INPUT_INNER_WRAPPER, OUTPUT_INNER_WRAPPER;
public boolean isOutput() {
@@ -460,6 +477,7 @@ public class FunctionType {
public boolean isInnerWrapper() {
return this == OUTPUT_INNER_WRAPPER || this == INPUT_INNER_WRAPPER;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.context;
import java.util.Collections;
@@ -39,11 +40,6 @@ import org.springframework.util.ClassUtils;
public class FunctionalSpringApplication
extends org.springframework.boot.SpringApplication {
/**
* Name of default property source.
*/
private static final String DEFAULT_PROPERTIES = "defaultProperties";
/**
* Flag to say that context is functional beans.
*/
@@ -54,6 +50,23 @@ public class FunctionalSpringApplication
*/
public static final String SPRING_WEB_APPLICATION_TYPE = "spring.main.web-application-type";
/**
* Name of default property source.
*/
private static final String DEFAULT_PROPERTIES = "defaultProperties";
public FunctionalSpringApplication(Class<?>... primarySources) {
super(primarySources);
setApplicationContextClass(GenericApplicationContext.class);
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler",
null)) {
setWebApplicationType(WebApplicationType.REACTIVE);
}
else {
setWebApplicationType(WebApplicationType.NONE);
}
}
public static void main(String[] args) throws Exception {
FunctionalSpringApplication.run(new Class<?>[0], args);
}
@@ -68,18 +81,6 @@ public class FunctionalSpringApplication
return new FunctionalSpringApplication(primarySources).run(args);
}
public FunctionalSpringApplication(Class<?>... primarySources) {
super(primarySources);
setApplicationContextClass(GenericApplicationContext.class);
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler",
null)) {
setWebApplicationType(WebApplicationType.REACTIVE);
}
else {
setWebApplicationType(WebApplicationType.NONE);
}
}
@Override
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
super.postProcessApplicationContext(context);
@@ -108,7 +109,7 @@ public class FunctionalSpringApplication
handler = BeanUtils.instantiateClass(type);
}
@SuppressWarnings("unchecked")
ApplicationContextInitializer<GenericApplicationContext> initializer = (ApplicationContextInitializer<GenericApplicationContext>) handler;
ApplicationContextInitializer initializer = (ApplicationContextInitializer) handler;
initializer.initialize(generic);
functional = true;
}
@@ -118,8 +119,9 @@ public class FunctionalSpringApplication
Class<?> functionType = type;
Object function = handler;
generic.registerBean("function", FunctionRegistration.class,
() -> new FunctionRegistration<>(handler(generic, function, functionType))
.type(FunctionType.of(functionType)));
() -> new FunctionRegistration<>(
handler(generic, function, functionType))
.type(FunctionType.of(functionType)));
functional = true;
}
}
@@ -130,7 +132,8 @@ public class FunctionalSpringApplication
}
}
private Object handler(GenericApplicationContext generic, Object handler, Class<?> type) {
private Object handler(GenericApplicationContext generic, Object handler,
Class<?> type) {
if (handler == null) {
handler = generic.getAutowireCapableBeanFactory().createBean(type);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.context.catalog;
import org.springframework.context.ApplicationEvent;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.context.catalog;
import java.util.HashSet;
@@ -26,6 +27,7 @@ import java.util.Set;
public class FunctionRegistrationEvent extends FunctionCatalogEvent {
private final Class<?> type;
private final Set<String> names;
public FunctionRegistrationEvent(Object source, Class<?> type, Set<String> names) {
@@ -35,11 +37,11 @@ public class FunctionRegistrationEvent extends FunctionCatalogEvent {
}
public Class<?> getType() {
return type;
return this.type;
}
public Set<String> getNames() {
return names;
return this.names;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.context.catalog;
import java.util.HashSet;
@@ -26,6 +27,7 @@ import java.util.Set;
public class FunctionUnregistrationEvent extends FunctionCatalogEvent {
private final Class<?> type;
private final Set<String> names;
public FunctionUnregistrationEvent(Object source, Class<?> type, Set<String> names) {
@@ -35,11 +37,11 @@ public class FunctionUnregistrationEvent extends FunctionCatalogEvent {
}
public Class<?> getType() {
return type;
return this.type;
}
public Set<String> getNames() {
return names;
return this.names;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2012-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
* 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,
@@ -81,16 +81,17 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry
FunctionRegistrationEvent event = new FunctionRegistrationEvent(this, type,
registration.getNames());
registrations.put(registration.getTarget(), registration);
this.registrations.put(registration.getTarget(), registration);
FunctionRegistration<T> wrapped = registration.wrap();
if (wrapped != registration) {
registration = wrapped;
registrations.put(wrapped.getTarget(), wrapped);
this.registrations.put(wrapped.getTarget(), wrapped);
if (type == Consumer.class) {
type = Function.class;
}
}
Map<String, Object> map = functions.computeIfAbsent(type, key -> new HashMap<>());
Map<String, Object> map = this.functions.computeIfAbsent(type,
key -> new HashMap<>());
for (String name : registration.getNames()) {
map.put(name, registration.getTarget());
}
@@ -104,19 +105,19 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry
@PostConstruct
public void init() {
if (publisher != null && !functions.isEmpty()) {
functions.keySet()
if (this.publisher != null && !this.functions.isEmpty()) {
this.functions.keySet()
.forEach(type -> this.publishEvent(new FunctionRegistrationEvent(this,
type, functions.get(type).keySet())));
type, this.functions.get(type).keySet())));
}
}
@PreDestroy
public void close() {
if (publisher != null && !functions.isEmpty()) {
functions.keySet().forEach(
if (this.publisher != null && !this.functions.isEmpty()) {
this.functions.keySet().forEach(
type -> this.publishEvent(new FunctionUnregistrationEvent(this, type,
functions.get(type).keySet())));
this.functions.get(type).keySet())));
}
}
@@ -125,7 +126,7 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry
public <T> T doLookup(Class<?> type, String name) {
T function = null;
if (type == null) {
function = (T) functions.values().stream()
function = (T) this.functions.values().stream()
.filter(map -> map.get(name) != null).map(map -> map.get(name))
.findFirst().orElse(null);
}
@@ -138,7 +139,7 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry
@Override
public Set<String> getNames(Class<?> type) {
if (type == null) {
return functions.values().stream().flatMap(map -> map.keySet().stream())
return this.functions.values().stream().flatMap(map -> map.keySet().stream())
.collect(Collectors.toSet());
}
Map<String, Object> map = this.extractTypeMap(type);
@@ -146,10 +147,10 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry
}
private Map<String, Object> extractTypeMap(Class<?> type) {
return functions.keySet().stream()
return this.functions.keySet().stream()
.filter(key -> key != Object.class && key.isAssignableFrom(type))
.map(key -> functions.get(key)).findFirst()
.orElse(functions.get(Object.class));
.map(key -> this.functions.get(key)).findFirst()
.orElse(this.functions.get(Object.class));
}
private void publishEvent(Object event) {
@@ -157,4 +158,5 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry
this.publisher.publishEvent(event);
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2012-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
* 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,
@@ -32,6 +32,11 @@ import java.util.stream.Stream;
import javax.annotation.PreDestroy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -62,22 +67,16 @@ import org.springframework.cloud.function.json.JacksonMapper;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
* @author Mark Fisher
@@ -86,8 +85,10 @@ import reactor.core.publisher.Mono;
*/
@Configuration
@ConditionalOnMissingBean(FunctionCatalog.class)
@ComponentScan(basePackages = "${spring.cloud.function.scan.packages:functions}",
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Supplier.class, Function.class, Consumer.class}))
// @checkstyle:off
@ComponentScan(basePackages = "${spring.cloud.function.scan.packages:functions}", includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
Supplier.class, Function.class, Consumer.class }))
// @checkstyle:on
public class ContextFunctionCatalogAutoConfiguration {
static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper";
@@ -104,11 +105,10 @@ public class ContextFunctionCatalogAutoConfiguration {
@Autowired(required = false)
private Map<String, FunctionRegistration<?>> registrations = Collections.emptyMap();
@Bean
public FunctionRegistry functionCatalog(ContextFunctionRegistry processor) {
processor.merge(registrations, consumers, suppliers, functions);
processor.merge(this.registrations, this.consumers, this.suppliers,
this.functions);
return new BeanFactoryFunctionCatalog(processor);
}
@@ -121,11 +121,15 @@ public class ContextFunctionCatalogAutoConfiguration {
private final ContextFunctionRegistry processor;
public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) {
this.processor = processor;
}
@Override
public <T> void register(FunctionRegistration<T> registration) {
Assert.notEmpty(registration.getNames(),
"'registration' must contain at least one name before it is registered in catalog.");
processor.register(registration);
this.processor.register(registration);
}
@Override
@@ -133,22 +137,22 @@ public class ContextFunctionCatalogAutoConfiguration {
protected <T> T doLookup(Class<?> type, String name) {
T function = null;
if (type == null) {
function = (T) processor.lookupFunction(name);
function = (T) this.processor.lookupFunction(name);
if (function == null) {
function = (T) processor.lookupConsumer(name);
function = (T) this.processor.lookupConsumer(name);
}
if (function == null) {
function = (T) processor.lookupSupplier(name);
function = (T) this.processor.lookupSupplier(name);
}
}
else if (Supplier.class.isAssignableFrom(type)) {
function = (T) processor.lookupSupplier(name);
function = (T) this.processor.lookupSupplier(name);
}
else if (Consumer.class.isAssignableFrom(type)) {
function = (T) processor.lookupConsumer(name);
function = (T) this.processor.lookupConsumer(name);
}
else if (Function.class.isAssignableFrom(type)) {
function = (T) processor.lookupFunction(name);
function = (T) this.processor.lookupFunction(name);
}
return function;
}
@@ -174,26 +178,6 @@ public class ContextFunctionCatalogAutoConfiguration {
+ this.processor.getConsumers().size();
}
public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) {
this.processor = processor;
}
}
protected class BeanFactoryFunctionInspector implements FunctionInspector {
private ContextFunctionRegistry processor;
public BeanFactoryFunctionInspector(ContextFunctionRegistry processor) {
this.processor = processor;
}
@Override
public FunctionRegistration<?> getRegistration(Object function) {
FunctionRegistration<?> registration = processor.getRegistration(function);
return registration;
}
}
@Configuration
@@ -201,21 +185,27 @@ public class ContextFunctionCatalogAutoConfiguration {
@ConditionalOnBean(Gson.class)
@Conditional(PreferGsonOrMissingJacksonCondition.class)
protected static class GsonConfiguration {
@Bean
public GsonMapper jsonMapper(Gson gson) {
return new GsonMapper(gson);
}
}
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
// @checkstyle:off
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
// @checkstyle:on
protected static class JacksonConfiguration {
@Bean
public JacksonMapper jsonMapper(ObjectMapper mapper) {
return new JacksonMapper(mapper);
}
}
@Component
@@ -242,10 +232,10 @@ public class ContextFunctionCatalogAutoConfiguration {
}
public FunctionRegistration<?> getRegistration(Object function) {
if (function == null || !names.containsKey(function)) {
if (function == null || !this.names.containsKey(function)) {
return null;
}
return new FunctionRegistration<>(function, names.get(function))
return new FunctionRegistration<>(function, this.names.get(function))
.type(findType(function).getType());
}
@@ -315,15 +305,15 @@ public class ContextFunctionCatalogAutoConfiguration {
}
final Object value = function;
lookup.computeIfAbsent(name, key -> value);
if (!types.containsKey(name)) {
if (types.containsKey(stages[0])
&& types.containsKey(stages[stages.length - 1])) {
FunctionType input = types.get(stages[0]);
FunctionType output = types.get(stages[stages.length - 1]);
types.put(name, FunctionType.compose(input, output));
if (!this.types.containsKey(name)) {
if (this.types.containsKey(stages[0])
&& this.types.containsKey(stages[stages.length - 1])) {
FunctionType input = this.types.get(stages[0]);
FunctionType output = this.types.get(stages[stages.length - 1]);
this.types.put(name, FunctionType.compose(input, output));
}
}
names.put(function, name);
this.names.put(function, name);
return function;
}
@@ -341,12 +331,14 @@ public class ContextFunctionCatalogAutoConfiguration {
Supplier<Flux<Object>> supplier = (Supplier<Flux<Object>>) a;
if (b instanceof FluxConsumer) {
if (supplier instanceof FluxSupplier) {
FluxConsumer<Object> fConsumer = ((FluxConsumer<Object>)b);
return (Supplier<Mono<Void>>) () -> Mono.from(supplier.get().compose(v -> fConsumer.apply(supplier.get())));
FluxConsumer<Object> fConsumer = ((FluxConsumer<Object>) b);
return (Supplier<Mono<Void>>) () -> Mono.from(supplier.get()
.compose(v -> fConsumer.apply(supplier.get())));
}
else {
throw new IllegalStateException("The provided supplier is finite (i.e., already composed with Consumer) "
+ "therefore it can not be composed with another consumer");
throw new IllegalStateException(
"The provided supplier is finite (i.e., already composed with Consumer) "
+ "therefore it can not be composed with another consumer");
}
}
else {
@@ -362,13 +354,16 @@ public class ContextFunctionCatalogAutoConfiguration {
return function1.andThen(function2);
}
else {
throw new IllegalStateException("The provided function is finite (i.e., returns Mono<?>) "
+ "therefore it can *only* be composed with compatible function (i.e., Function<Mono, Flux>");
throw new IllegalStateException(
"The provided function is finite (i.e., returns Mono<?>) "
+ "therefore it can *only* be composed with compatible function (i.e., Function<Mono, Flux>");
}
}
else if (function2 instanceof FluxToMonoFunction) {
return new FluxToMonoFunction<Object, Object>(((Function<Flux<Object>, Flux<Object>>)a)
.andThen(((FluxToMonoFunction<Object,Object>) b).getTarget()));
return new FluxToMonoFunction<Object, Object>(
((Function<Flux<Object>, Flux<Object>>) a)
.andThen(((FluxToMonoFunction<Object, Object>) b)
.getTarget()));
}
else {
return function1.andThen(function2);
@@ -391,18 +386,18 @@ public class ContextFunctionCatalogAutoConfiguration {
@PreDestroy
public void close() {
if (publisher != null) {
if (!functions.isEmpty()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this,
Function.class, functions.keySet()));
if (this.publisher != null) {
if (!this.functions.isEmpty()) {
this.publisher.publishEvent(new FunctionUnregistrationEvent(this,
Function.class, this.functions.keySet()));
}
if (!consumers.isEmpty()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this,
Consumer.class, consumers.keySet()));
if (!this.consumers.isEmpty()) {
this.publisher.publishEvent(new FunctionUnregistrationEvent(this,
Consumer.class, this.consumers.keySet()));
}
if (!suppliers.isEmpty()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this,
Supplier.class, suppliers.keySet()));
if (!this.suppliers.isEmpty()) {
this.publisher.publishEvent(new FunctionUnregistrationEvent(this,
Supplier.class, this.suppliers.keySet()));
}
}
}
@@ -443,8 +438,8 @@ public class ContextFunctionCatalogAutoConfiguration {
private Collection<String> getAliases(String key) {
Collection<String> names = new LinkedHashSet<>();
String value = getQualifier(key);
if (value.equals(key) && registry != null) {
names.addAll(Arrays.asList(registry.getAliases(key)));
if (value.equals(key) && this.registry != null) {
names.addAll(Arrays.asList(this.registry.getAliases(key)));
}
names.add(value);
return names;
@@ -485,8 +480,8 @@ public class ContextFunctionCatalogAutoConfiguration {
}
// this.names.remove(target);
this.names.put(registration.getTarget(), key);
if (publisher != null) {
publisher.publishEvent(new FunctionRegistrationEvent(
if (this.publisher != null) {
this.publisher.publishEvent(new FunctionRegistrationEvent(
registration.getTarget(), type, registration.getNames()));
}
}
@@ -552,8 +547,8 @@ public class ContextFunctionCatalogAutoConfiguration {
}
private String getQualifier(String key) {
if (registry != null && registry.containsBeanDefinition(key)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(key);
if (this.registry != null && this.registry.containsBeanDefinition(key)) {
BeanDefinition beanDefinition = this.registry.getBeanDefinition(key);
Object source = beanDefinition.getSource();
if (source instanceof StandardMethodMetadata) {
StandardMethodMetadata metadata = (StandardMethodMetadata) source;
@@ -568,13 +563,13 @@ public class ContextFunctionCatalogAutoConfiguration {
}
private FunctionType findType(Object function) {
String name = names.get(function);
if (types.containsKey(name)) {
return types.get(name);
String name = this.names.get(function);
if (this.types.containsKey(name)) {
return this.types.get(name);
}
FunctionType param;
if (name == null || registry == null
|| !registry.containsBeanDefinition(name)) {
if (name == null || this.registry == null
|| !this.registry.containsBeanDefinition(name)) {
if (function != null) {
param = new FunctionType(function.getClass());
}
@@ -583,9 +578,10 @@ public class ContextFunctionCatalogAutoConfiguration {
}
}
else {
param = new FunctionType(FunctionContextUtils.findType(name, registry));
param = new FunctionType(
FunctionContextUtils.findType(name, this.registry));
}
types.computeIfAbsent(name, str -> param);
this.types.computeIfAbsent(name, str -> param);
return param;
}
@@ -597,7 +593,7 @@ public class ContextFunctionCatalogAutoConfiguration {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false)
@ConditionalOnProperty(name = PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false)
static class GsonPreferred {
}
@@ -609,4 +605,21 @@ public class ContextFunctionCatalogAutoConfiguration {
}
protected class BeanFactoryFunctionInspector implements FunctionInspector {
private ContextFunctionRegistry processor;
public BeanFactoryFunctionInspector(ContextFunctionRegistry processor) {
this.processor = processor;
}
@Override
public FunctionRegistration<?> getRegistration(Object function) {
FunctionRegistration<?> registration = this.processor
.getRegistration(function);
return registration;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -50,8 +50,14 @@ import org.springframework.util.ClassUtils;
public class ContextFunctionCatalogInitializer
implements ApplicationContextInitializer<GenericApplicationContext> {
/**
* Property name for ignoring pre initilizer.
*/
public static final String IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME = "spring.backgroundpreinitializer.ignore";
/**
* Flag for enabling the context function catalog initializer.
*/
public static boolean enabled = true;
@Override
@@ -69,7 +75,7 @@ public class ContextFunctionCatalogInitializer
private GenericApplicationContext context;
public ContextFunctionCatalogBeanRegistrar(
ContextFunctionCatalogBeanRegistrar(
GenericApplicationContext applicationContext) {
this.context = applicationContext;
}
@@ -101,65 +107,67 @@ public class ContextFunctionCatalogInitializer
performPreinitialization();
if (context.getBeanFactory().getBeanNamesForType(
if (this.context.getBeanFactory().getBeanNamesForType(
PropertySourcesPlaceholderConfigurer.class, false,
false).length == 0) {
context.registerBean(PropertySourcesPlaceholderConfigurer.class,
this.context.registerBean(PropertySourcesPlaceholderConfigurer.class,
() -> PropertyPlaceholderAutoConfiguration
.propertySourcesPlaceholderConfigurer());
}
if (!context.getBeanFactory().containsBean(
if (!this.context.getBeanFactory().containsBean(
AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// Switch off the ConfigurationClassPostProcessor
context.registerBean(
this.context.registerBean(
AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME,
DummyProcessor.class, () -> new DummyProcessor());
// But switch on other annotation processing
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.context);
}
if (!context.getBeanFactory()
if (!this.context.getBeanFactory()
.containsBean(ConfigurationBeanFactoryMetadata.BEAN_NAME)) {
context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME,
this.context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME,
ConfigurationBeanFactoryMetadata.class,
() -> new ConfigurationBeanFactoryMetadata());
context.registerBean(
this.context.registerBean(
ConfigurationPropertiesBindingPostProcessor.BEAN_NAME,
ConfigurationPropertiesBindingPostProcessor.class,
() -> new ConfigurationPropertiesBindingPostProcessor());
}
if (ClassUtils.isPresent("com.google.gson.Gson", null)
&& "gson".equals(context.getEnvironment().getProperty(
&& "gson".equals(this.context.getEnvironment().getProperty(
ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY,
"gson"))) {
if (context.getBeanFactory().getBeanNamesForType(Gson.class, false,
if (this.context.getBeanFactory().getBeanNamesForType(Gson.class, false,
false).length == 0) {
context.registerBean(Gson.class, () -> new Gson());
this.context.registerBean(Gson.class, () -> new Gson());
}
context.registerBean(JsonMapper.class,
this.context.registerBean(JsonMapper.class,
() -> new ContextFunctionCatalogAutoConfiguration.GsonConfiguration()
.jsonMapper(context.getBean(Gson.class)));
.jsonMapper(this.context.getBean(Gson.class)));
}
else if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
null)) {
if (context.getBeanFactory().getBeanNamesForType(ObjectMapper.class,
if (this.context.getBeanFactory().getBeanNamesForType(ObjectMapper.class,
false, false).length == 0) {
context.registerBean(ObjectMapper.class, () -> new ObjectMapper());
this.context.registerBean(ObjectMapper.class,
() -> new ObjectMapper());
}
context.registerBean(JsonMapper.class,
this.context.registerBean(JsonMapper.class,
() -> new ContextFunctionCatalogAutoConfiguration.JacksonConfiguration()
.jsonMapper(context.getBean(ObjectMapper.class)));
.jsonMapper(this.context.getBean(ObjectMapper.class)));
}
if (context.getBeanFactory().getBeanNamesForType(FunctionCatalog.class, false,
false).length == 0) {
context.registerBean(InMemoryFunctionCatalog.class,
if (this.context.getBeanFactory().getBeanNamesForType(FunctionCatalog.class,
false, false).length == 0) {
this.context.registerBean(InMemoryFunctionCatalog.class,
() -> new InMemoryFunctionCatalog());
context.registerBean(FunctionRegistrationPostProcessor.class,
() -> new FunctionRegistrationPostProcessor(
context.getAutowireCapableBeanFactory()
this.context
.registerBean(FunctionRegistrationPostProcessor.class,
() -> new FunctionRegistrationPostProcessor(this.context
.getAutowireCapableBeanFactory()
.getBeanProvider(FunctionRegistration.class)));
}
}
@@ -193,10 +201,11 @@ public class ContextFunctionCatalogInitializer
}
private class FunctionRegistrationPostProcessor implements BeanPostProcessor {
@SuppressWarnings("rawtypes")
private final ObjectProvider<FunctionRegistration> functions;
public FunctionRegistrationPostProcessor(
FunctionRegistrationPostProcessor(
@SuppressWarnings("rawtypes") ObjectProvider<FunctionRegistration> functions) {
this.functions = functions;
}
@@ -206,7 +215,7 @@ public class ContextFunctionCatalogInitializer
throws BeansException {
if (bean instanceof FunctionRegistry) {
FunctionRegistry catalog = (FunctionRegistry) bean;
for (FunctionRegistration<?> registration : functions) {
for (FunctionRegistration<?> registration : this.functions) {
Assert.notEmpty(registration.getNames(),
"FunctionRegistration must define at least one name. Was empty");
if (registration.getType() == null) {
@@ -222,13 +231,19 @@ public class ContextFunctionCatalogInitializer
}
return bean;
}
}
}
/**
* Dummy implementation of a processor.
*/
public static class DummyProcessor {
public void setMetadataReaderFactory(MetadataReaderFactory obj) {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-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.
@@ -38,103 +38,106 @@ import org.springframework.util.ReflectionUtils;
/**
* @author Oleg Zhurakousky
*
* @since 2.0
*/
abstract class FunctionContextUtils {
public static Type findType(String name, ConfigurableListableBeanFactory registry) {
AbstractBeanDefinition definition = (AbstractBeanDefinition) registry.getBeanDefinition(name);
Object source = definition.getSource();
Type param = null;
// Start by assuming output -> Function
if (source instanceof StandardMethodMetadata) {
// Standard @Bean metadata
param = ((StandardMethodMetadata) source).getIntrospectedMethod()
.getGenericReturnType();
}
else if (source instanceof MethodMetadataReadingVisitor) {
// A component scan with @Beans
MethodMetadataReadingVisitor visitor = (MethodMetadataReadingVisitor) source;
param = findBeanType(definition, visitor);
}
else if (source instanceof Resource) {
param = registry.getType(name);
}
else {
ResolvableType type = (ResolvableType) getField(definition, "targetType");
if (type != null) {
param = type.getType();
}
else {
Class<?> beanClass = definition.getBeanClass();
if (beanClass != null && !FunctionFactoryMetadata.class.isAssignableFrom(beanClass)) {
param = beanClass;
}
else {
//assume FunctionFactoryMetadata
FunctionFactoryMetadata<?> factory = (FunctionFactoryMetadata<?>) registry.getBean(name);
param = factory.getFactoryMethod().getGenericReturnType();
}
}
}
return param;
}
public static Type findType(String name, ConfigurableListableBeanFactory registry) {
AbstractBeanDefinition definition = (AbstractBeanDefinition) registry
.getBeanDefinition(name);
Object source = definition.getSource();
Type param = null;
// Start by assuming output -> Function
if (source instanceof StandardMethodMetadata) {
// Standard @Bean metadata
param = ((StandardMethodMetadata) source).getIntrospectedMethod()
.getGenericReturnType();
}
else if (source instanceof MethodMetadataReadingVisitor) {
// A component scan with @Beans
MethodMetadataReadingVisitor visitor = (MethodMetadataReadingVisitor) source;
param = findBeanType(definition, visitor);
}
else if (source instanceof Resource) {
param = registry.getType(name);
}
else {
ResolvableType type = (ResolvableType) getField(definition, "targetType");
if (type != null) {
param = type.getType();
}
else {
Class<?> beanClass = definition.getBeanClass();
if (beanClass != null
&& !FunctionFactoryMetadata.class.isAssignableFrom(beanClass)) {
param = beanClass;
}
else {
// assume FunctionFactoryMetadata
FunctionFactoryMetadata<?> factory = (FunctionFactoryMetadata<?>) registry
.getBean(name);
param = factory.getFactoryMethod().getGenericReturnType();
}
}
}
return param;
}
private static Type findBeanType(AbstractBeanDefinition definition,
MethodMetadataReadingVisitor visitor) {
Class<?> factory = ClassUtils
.resolveClassName(visitor.getDeclaringClassName(), null);
Class<?>[] params = getParamTypes(factory, definition);
Method method = ReflectionUtils.findMethod(factory, visitor.getMethodName(),
params);
Type type = method.getGenericReturnType();
return type;
}
private static Type findBeanType(AbstractBeanDefinition definition,
MethodMetadataReadingVisitor visitor) {
Class<?> factory = ClassUtils.resolveClassName(visitor.getDeclaringClassName(),
null);
Class<?>[] params = getParamTypes(factory, definition);
Method method = ReflectionUtils.findMethod(factory, visitor.getMethodName(),
params);
Type type = method.getGenericReturnType();
return type;
}
private static Class<?>[] getParamTypes(Class<?> factory,
AbstractBeanDefinition definition) {
if (definition instanceof RootBeanDefinition) {
RootBeanDefinition root = (RootBeanDefinition) definition;
for (Method method : getCandidateMethods(factory, root)) {
if (root.isFactoryMethod(method)) {
return method.getParameterTypes();
}
}
}
List<Class<?>> params = new ArrayList<>();
for (ConstructorArgumentValues.ValueHolder holder : definition.getConstructorArgumentValues()
.getIndexedArgumentValues().values()) {
params.add(ClassUtils.resolveClassName(holder.getType(), null));
}
return params.toArray(new Class<?>[0]);
}
private static Class<?>[] getParamTypes(Class<?> factory,
AbstractBeanDefinition definition) {
if (definition instanceof RootBeanDefinition) {
RootBeanDefinition root = (RootBeanDefinition) definition;
for (Method method : getCandidateMethods(factory, root)) {
if (root.isFactoryMethod(method)) {
return method.getParameterTypes();
}
}
}
List<Class<?>> params = new ArrayList<>();
for (ConstructorArgumentValues.ValueHolder holder : definition
.getConstructorArgumentValues().getIndexedArgumentValues().values()) {
params.add(ClassUtils.resolveClassName(holder.getType(), null));
}
return params.toArray(new Class<?>[0]);
}
private static Method[] getCandidateMethods(final Class<?> factoryClass,
final RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
@Override
public Method[] run() {
return (mbd.isNonPublicAccessAllowed()
? ReflectionUtils.getAllDeclaredMethods(factoryClass)
: factoryClass.getMethods());
}
});
}
else {
return (mbd.isNonPublicAccessAllowed()
? ReflectionUtils.getAllDeclaredMethods(factoryClass)
: factoryClass.getMethods());
}
}
private static Method[] getCandidateMethods(final Class<?> factoryClass,
final RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
@Override
public Method[] run() {
return (mbd.isNonPublicAccessAllowed()
? ReflectionUtils.getAllDeclaredMethods(factoryClass)
: factoryClass.getMethods());
}
});
}
else {
return (mbd.isNonPublicAccessAllowed()
? ReflectionUtils.getAllDeclaredMethods(factoryClass)
: factoryClass.getMethods());
}
}
private static Object getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
if (field == null) {
return null;
}
ReflectionUtils.makeAccessible(field);
return ReflectionUtils.getField(field, target);
}
private static Object getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
if (field == null) {
return null;
}
ReflectionUtils.makeAccessible(field);
return ReflectionUtils.getField(field, target);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -39,7 +39,6 @@ public abstract class MessageUtils {
* isolated class loader, then the message will be created with the target class
* loader (therefore the {@link Message} class must be on the classpath of the target
* class loader).
*
* @param handler the function that will be applied to the message
* @param payload the payload of the message
* @param headers the headers for the message
@@ -74,7 +73,6 @@ public abstract class MessageUtils {
* class loader. If the handler is a wrapper for a function in an isolated class
* loader, then the message will be created with the target class loader (therefore
* the {@link Message} class must be on the classpath of the target class loader).
*
* @param handler the function that generated the message
* @param message the message to convert
* @return a message with the correct class loader

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-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.
@@ -42,16 +42,16 @@ import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(loader = FunctionalTestContextLoader.class)
public @interface FunctionalSpringBootTest {
@AliasFor(annotation=SpringBootTest.class, attribute="properties")
@AliasFor(annotation = SpringBootTest.class, attribute = "properties")
String[] value() default {};
@AliasFor(annotation=SpringBootTest.class, attribute="value")
@AliasFor(annotation = SpringBootTest.class, attribute = "value")
String[] properties() default {};
@AliasFor(annotation=SpringBootTest.class, attribute="classes")
@AliasFor(annotation = SpringBootTest.class, attribute = "classes")
Class<?>[] classes() default {};
@AliasFor(annotation=SpringBootTest.class, attribute="webEnvironment")
@AliasFor(annotation = SpringBootTest.class, attribute = "webEnvironment")
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-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.
@@ -34,4 +34,5 @@ class FunctionalTestContextLoader extends SpringBootContextLoader {
protected SpringApplication getSpringApplication() {
return new FunctionalSpringApplication();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.json;
import java.lang.reflect.Type;
@@ -34,11 +35,12 @@ public class GsonMapper implements JsonMapper {
@Override
public <T> T toObject(String json, Type type) {
return gson.fromJson(json, type);
return this.gson.fromJson(json, type);
}
@Override
public String toString(Object value) {
return gson.toJson(value);
return this.gson.toJson(value);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.json;
import java.lang.reflect.Type;
@@ -36,7 +37,8 @@ public class JacksonMapper implements JsonMapper {
@Override
public <T> T toObject(String json, Type type) {
try {
return mapper.readValue(json, TypeFactory.defaultInstance().constructType(type));
return this.mapper.readValue(json,
TypeFactory.defaultInstance().constructType(type));
}
catch (Exception e) {
throw new IllegalArgumentException("Cannot convert JSON " + json, e);
@@ -46,10 +48,11 @@ public class JacksonMapper implements JsonMapper {
@Override
public String toString(Object value) {
try {
return mapper.writeValueAsString(value);
return this.mapper.writeValueAsString(value);
}
catch (JsonProcessingException e) {
throw new IllegalArgumentException("Cannot convert to JSON", e);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.json;
import java.lang.reflect.Type;
@@ -28,6 +29,10 @@ import org.springframework.core.ResolvableType;
public interface JsonMapper {
/**
* @param <T> type for list arguments
* @param json JSON input
* @param type type of list arguments
* @return list of elements
* @deprecated since v2.0 in favor of {@link #toObject(String, Type)}
*/
@Deprecated
@@ -40,11 +45,19 @@ public interface JsonMapper {
}
/**
* @param <T> return type
* @param json JSON input
* @param type type
* @return object
* @since 2.0
*/
<T> T toObject(String json, Type type);
/**
* @param <T> type for list arguments
* @param json JSON input
* @param type type of list arguments
* @return single object
* @deprecated since v2.0 in favor of {@link #toObject(String, Type)}
*/
default <T> T toSingle(String json, Class<T> type) {

View File

@@ -1,18 +1,18 @@
{
"hints": [],
"groups": [],
"properties": [
{
"name": "spring.cloud.function.scan.packages",
"type": "java.lang.String",
"description": "Triggers scanning within the specified base packages for any class that is assignable to java.util.function.Function. For each detected Function class, a bean instance will be added to the context.",
"defaultValue": "functions"
},
{
"name": "spring.cloud.function.definition",
"type": "java.lang.String",
"description": "Name (e.g., 'foo') or composition instruction (e.g., 'foo|bar') used to resolve default function especially for cases where there is more then once function available in catalog.",
"defaultValue": ""
}
]
}
"hints": [],
"groups": [],
"properties": [
{
"name": "spring.cloud.function.scan.packages",
"type": "java.lang.String",
"description": "Triggers scanning within the specified base packages for any class that is assignable to java.util.function.Function. For each detected Function class, a bean instance will be added to the context.",
"defaultValue": "functions"
},
{
"name": "spring.cloud.function.definition",
"type": "java.lang.String",
"description": "Name (e.g., 'foo') or composition instruction (e.g., 'foo|bar') used to resolve default function especially for cases where there is more then once function available in catalog.",
"defaultValue": ""
}
]
}

View File

@@ -1,8 +1,6 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration
org.springframework.cloud.function.context.WrapperDetector=\
org.springframework.cloud.function.context.config.FluxWrapperDetector
org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.function.context.config.ContextFunctionCatalogInitializer
org.springframework.cloud.function.context.config.ContextFunctionCatalogInitializer

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -46,10 +46,12 @@ public class FunctionRegistrationTests {
}
private static class Foos implements Function<Integer, String> {
@Override
public String apply(Integer t) {
return "i=" + t;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -23,6 +23,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.junit.Test;
import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
import org.springframework.messaging.Message;
@@ -30,8 +31,6 @@ import org.springframework.messaging.support.MessageBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
/**
* @author Dave Syer
*
@@ -50,7 +49,8 @@ public class FunctionTypeTests {
@Test
public void supplierOfRegistration() {
FunctionType function = new FunctionType(SupplierOfRegistrationOfIntegerToString.class);
FunctionType function = new FunctionType(
SupplierOfRegistrationOfIntegerToString.class);
assertThat(function.getInputType()).isEqualTo(Integer.class);
assertThat(function.getOutputType()).isEqualTo(String.class);
assertThat(function.getInputWrapper()).isEqualTo(Integer.class);
@@ -247,60 +247,80 @@ public class FunctionTypeTests {
assertThat(function).isSameAs(function.wrap(Object.class));
}
private static class SupplierOfRegistrationOfIntegerToString implements Supplier<FunctionRegistration<Function<Integer, String>>> {
private static class SupplierOfRegistrationOfIntegerToString
implements Supplier<FunctionRegistration<Function<Integer, String>>> {
@Override
public FunctionRegistration<Function<Integer, String>> get() {
return new FunctionRegistration<Function<Integer,String>>(new IntegerToString(), "ints");
return new FunctionRegistration<Function<Integer, String>>(
new IntegerToString(), "ints");
}
}
private static class SupplierOfIntegerToString implements Supplier<Function<Integer, String>> {
private static class SupplierOfIntegerToString
implements Supplier<Function<Integer, String>> {
@Override
public Function<Integer, String> get() {
return new IntegerToString();
}
}
private static class IntegerToString implements Function<Integer, String> {
@Override
public String apply(Integer t) {
return "" + t;
}
}
private static class StringToMap implements Function<String, Map<String, Integer>> {
@Override
public Map<String, Integer> apply(String t) {
return Collections.emptyMap();
}
}
private static class FooToFoo implements Function<Foo, Bar> {
@Override
public Bar apply(Foo t) {
return new Bar();
}
}
private static class FluxToFlux implements Function<Flux<Foo>, Flux<Bar>> {
@Override
public Flux<Bar> apply(Flux<Foo> t) {
return t.map(f -> new Bar());
}
}
private static class FluxMessageToFluxMessage
implements Function<Flux<Message<Foo>>, Flux<Message<Bar>>> {
@Override
public Flux<Message<Bar>> apply(Flux<Message<Foo>> t) {
return t.map(f -> MessageBuilder.withPayload(new Bar())
.copyHeadersIfAbsent(f.getHeaders()).build());
}
}
private static class Foo {
}
private static class Bar {
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-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
* 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,
@@ -16,20 +16,20 @@
package org.springframework.cloud.function.context.catalog;
import java.util.function.Function;
import org.junit.Test;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionType;
import org.springframework.cloud.function.core.FluxFunction;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.function.Function;
import org.junit.Test;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionType;
import org.springframework.cloud.function.core.FluxFunction;
/**
*
* @author Oleg Zhurakousky
*
*/
@@ -38,8 +38,8 @@ public class InMemoryFunctionCatalogTests {
@Test
public void testFunctionRegistration() {
TestFunction function = new TestFunction();
FunctionRegistration<TestFunction> registration = new FunctionRegistration<>(function, "foo")
.type(FunctionType.of(TestFunction.class).getType());
FunctionRegistration<TestFunction> registration = new FunctionRegistration<>(
function, "foo").type(FunctionType.of(TestFunction.class).getType());
InMemoryFunctionCatalog catalog = new InMemoryFunctionCatalog();
catalog.register(registration);
FunctionRegistration<?> registration2 = catalog.getRegistration(function);
@@ -49,8 +49,8 @@ public class InMemoryFunctionCatalogTests {
@Test
public void testFunctionLookup() {
TestFunction function = new TestFunction();
FunctionRegistration<TestFunction> registration = new FunctionRegistration<>(function, "foo")
.type(FunctionType.of(TestFunction.class).getType());
FunctionRegistration<TestFunction> registration = new FunctionRegistration<>(
function, "foo").type(FunctionType.of(TestFunction.class).getType());
InMemoryFunctionCatalog catalog = new InMemoryFunctionCatalog();
catalog.register(registration);
@@ -63,9 +63,12 @@ public class InMemoryFunctionCatalogTests {
}
private static class TestFunction implements Function<Integer, String> {
@Override
public String apply(Integer t) {
return "i=" + t;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -26,6 +26,8 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionType;
@@ -34,9 +36,6 @@ import org.springframework.cloud.function.context.config.ContextFunctionCatalogA
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
*
@@ -48,56 +47,59 @@ public class BeanFactoryFunctionCatalogTests {
@Test
public void basicRegistrationFeatures() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class,
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Function<Flux<Integer>, Flux<String>> foos = this.processor.lookup(Function.class,
"foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void lookupFunctionWithEmptyName() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "");
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Function<Flux<Integer>, Flux<String>> foos = this.processor.lookup(Function.class,
"");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void lookupFunctionWithNoType() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Function<Flux<Integer>, Flux<String>> foos = processor.lookup("foos");
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Function<Flux<Integer>, Flux<String>> foos = this.processor.lookup("foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void registerFunctionWithType() {
processor.register(new FunctionRegistration<Function<Integer, String>>(
this.processor.register(new FunctionRegistration<Function<Integer, String>>(
(Integer i) -> "i=" + i, "foos").type(
FunctionType.from(Integer.class).to(String.class).getType()));
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "");
Function<Flux<Integer>, Flux<String>> foos = this.processor.lookup(Function.class,
"");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("i=2");
}
@Test
public void registerFunctionWithFluxType() {
processor
this.processor
.register(new FunctionRegistration<Function<Flux<Integer>, Flux<String>>>(
ints -> ints.map(i -> "i=" + i), "foos")
.type(FunctionType.from(Integer.class).to(String.class)
.wrap(Flux.class).getType()));
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "");
Function<Flux<Integer>, Flux<String>> foos = this.processor.lookup(Function.class,
"");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("i=2");
}
@Test
public void registerFunctionWithMonoType() {
processor.register(
this.processor.register(
new FunctionRegistration<Function<Flux<String>, Mono<Map<String, Integer>>>>(
flux -> flux.collect(HashMap::new,
(map, word) -> map.merge(word, 1, Integer::sum)), "foos")
.type(FunctionType.from(String.class)
.to(Map.class)
.wrap(Flux.class, Mono.class).getType()));
Function<Flux<String>, Mono<Map<String, Integer>>> foos = processor
(map, word) -> map.merge(word, 1, Integer::sum)),
"foos").type(
FunctionType.from(String.class).to(Map.class)
.wrap(Flux.class, Mono.class).getType()));
Function<Flux<String>, Mono<Map<String, Integer>>> foos = this.processor
.lookup(Function.class, "");
assertThat(foos.apply(Flux.just("one", "one", "two")).block())
.containsEntry("one", 2);
@@ -105,16 +107,16 @@ public class BeanFactoryFunctionCatalogTests {
@Test
public void lookupNonExistentConsumerWithEmptyName() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Consumer<Flux<String>> foos = processor.lookup(Consumer.class, "");
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Consumer<Flux<String>> foos = this.processor.lookup(Consumer.class, "");
assertThat(foos).isNull();
}
@Test
public void composeFunction() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
processor.register(new FunctionRegistration<>(new Bars(), "bars"));
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class,
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
this.processor.register(new FunctionRegistration<>(new Bars(), "bars"));
Function<Flux<Integer>, Flux<String>> foos = this.processor.lookup(Function.class,
"foos,bars");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4");
}
@@ -122,51 +124,60 @@ public class BeanFactoryFunctionCatalogTests {
@Test
public void composeWithFiniteFunction() {
Function<String, String> func1 = x -> x.toUpperCase();
processor.register(new FunctionRegistration<>(func1, "func1"));
processor.register(new FunctionRegistration<>(new FluxThenMonoFunction(), "func2"));
Function<Flux<String>, Mono<Long>> foos = processor.lookup(Function.class, "func1,func2");
assertThat(foos.apply(Flux.fromArray(new String[] {"a", "b", "c"})).block()).isEqualTo(3);
this.processor.register(new FunctionRegistration<>(func1, "func1"));
this.processor.register(
new FunctionRegistration<>(new FluxThenMonoFunction(), "func2"));
Function<Flux<String>, Mono<Long>> foos = this.processor.lookup(Function.class,
"func1,func2");
assertThat(foos.apply(Flux.fromArray(new String[] { "a", "b", "c" })).block())
.isEqualTo(3);
}
@Test
public void composeWithFiniteFunctionAndContinueWithCompatible() {
Function<String, String> func1 = x -> x.toUpperCase();
processor.register(new FunctionRegistration<>(func1, "func1"));
processor.register(new FunctionRegistration<>(new FluxThenMonoFunction(), "func2"));
processor.register(new FunctionRegistration<>(new MonoThenFluxFunction(), "func3"));
Function<Flux<String>, Flux<Integer>> foos = processor.lookup(Function.class, "func1,func2,func3");
assertThat(foos.apply(Flux.fromArray(new String[] {"a", "b", "c"})).collectList().block().size()).isEqualTo(3);
this.processor.register(new FunctionRegistration<>(func1, "func1"));
this.processor.register(
new FunctionRegistration<>(new FluxThenMonoFunction(), "func2"));
this.processor.register(
new FunctionRegistration<>(new MonoThenFluxFunction(), "func3"));
Function<Flux<String>, Flux<Integer>> foos = this.processor.lookup(Function.class,
"func1,func2,func3");
assertThat(foos.apply(Flux.fromArray(new String[] { "a", "b", "c" }))
.collectList().block().size()).isEqualTo(3);
}
@Test(expected=IllegalStateException.class)
@Test(expected = IllegalStateException.class)
public void composeIncompatibleFunctions() {
Function<String, String> func1 = x -> x.toUpperCase();
processor.register(new FunctionRegistration<>(func1, "func1"));
processor.register(new FunctionRegistration<>(new FluxThenMonoFunction(), "func2"));
processor.lookup(Function.class, "func2,func1");
this.processor.register(new FunctionRegistration<>(func1, "func1"));
this.processor.register(
new FunctionRegistration<>(new FluxThenMonoFunction(), "func2"));
this.processor.lookup(Function.class, "func2,func1");
}
@Test
public void composeSupplier() {
processor.register(new FunctionRegistration<>(new Source(), "numbers"));
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Supplier<Flux<String>> foos = processor.lookup(Supplier.class, "numbers,foos");
this.processor.register(new FunctionRegistration<>(new Source(), "numbers"));
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Supplier<Flux<String>> foos = this.processor.lookup(Supplier.class,
"numbers,foos");
assertThat(foos.get().blockFirst()).isEqualTo("6");
}
@Test
public void composeUniqueSupplier() {
processor.register(new FunctionRegistration<>(new Source(), "numbers"));
Supplier<Flux<Integer>> foos = processor.lookup(Supplier.class, "");
this.processor.register(new FunctionRegistration<>(new Source(), "numbers"));
Supplier<Flux<Integer>> foos = this.processor.lookup(Supplier.class, "");
assertThat(foos.get().blockFirst()).isEqualTo(3);
}
@Test
public void composeConsumer() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
Sink sink = new Sink();
processor.register(new FunctionRegistration<>(sink, "sink"));
Function<Flux<Integer>, Mono<Void>> foos = processor.lookup(Function.class,
this.processor.register(new FunctionRegistration<>(sink, "sink"));
Function<Flux<Integer>, Mono<Void>> foos = this.processor.lookup(Function.class,
"foos,sink");
foos.apply(Flux.just(2)).subscribe();
assertThat(sink.values).contains("4");
@@ -175,8 +186,9 @@ public class BeanFactoryFunctionCatalogTests {
@Test
public void composeUniqueConsumer() {
Sink sink = new Sink();
processor.register(new FunctionRegistration<>(sink, "sink"));
Function<Flux<String>, Mono<Void>> foos = processor.lookup(Function.class, "");
this.processor.register(new FunctionRegistration<>(sink, "sink"));
Function<Flux<String>, Mono<Void>> foos = this.processor.lookup(Function.class,
"");
foos.apply(Flux.just("2")).subscribe();
assertThat(sink.values).contains("2");
}
@@ -185,36 +197,36 @@ public class BeanFactoryFunctionCatalogTests {
public void composeSupplierAndConsumer() {
AtomicReference<String> ref = new AtomicReference<String>();
Supplier<String> s = () -> "hello";
processor.register(new FunctionRegistration<>(s, "supplier"));
this.processor.register(new FunctionRegistration<>(s, "supplier"));
Consumer<String> c = x -> ref.set(x.toUpperCase());
processor.register(new FunctionRegistration<>(c, "consumer"));
Supplier<Mono<Void>> f = processor.lookup("supplier|consumer");
((Mono<Void>)f.get()).block();
this.processor.register(new FunctionRegistration<>(c, "consumer"));
Supplier<Mono<Void>> f = this.processor.lookup("supplier|consumer");
((Mono<Void>) f.get()).block();
assertThat(ref.get()).isEqualTo("HELLO");
}
@Test(expected=IllegalStateException.class)
@Test(expected = IllegalStateException.class)
public void failComposeSupplierWithMultipleConsumers() {
AtomicReference<String> ref = new AtomicReference<String>();
Supplier<String> s = () -> "hello";
processor.register(new FunctionRegistration<>(s, "supplier"));
this.processor.register(new FunctionRegistration<>(s, "supplier"));
Consumer<String> c = x -> ref.set(x.toUpperCase());
processor.register(new FunctionRegistration<>(c, "consumer"));
this.processor.register(new FunctionRegistration<>(c, "consumer"));
Consumer<String> z = x -> ref.set(x.toUpperCase());
processor.register(new FunctionRegistration<>(z, "z"));
processor.lookup("supplier|consumer|z");
this.processor.register(new FunctionRegistration<>(z, "z"));
this.processor.lookup("supplier|consumer|z");
}
@Test
public void composeSupplierAndMultipleFunctions() {
Supplier<String> s = () -> "hello";
processor.register(new FunctionRegistration<>(s, "supplier"));
this.processor.register(new FunctionRegistration<>(s, "supplier"));
Function<String, String> uppercase = x -> x.toUpperCase();
processor.register(new FunctionRegistration<>(uppercase, "uppercase"));
this.processor.register(new FunctionRegistration<>(uppercase, "uppercase"));
Function<String, String> concat = x -> x + x;
processor.register(new FunctionRegistration<>(concat, "concat"));
this.processor.register(new FunctionRegistration<>(concat, "concat"));
Supplier<Flux<String>> f = processor.lookup("supplier|uppercase|concat");
Supplier<Flux<String>> f = this.processor.lookup("supplier|uppercase|concat");
assertThat(f.get().blockFirst()).isEqualTo("HELLOHELLO");
}
@@ -234,7 +246,7 @@ public class BeanFactoryFunctionCatalogTests {
@Override
public void accept(String value) {
values.add(value);
this.values.add(value);
}
}
@@ -257,20 +269,24 @@ public class BeanFactoryFunctionCatalogTests {
}
protected static class FluxThenMonoFunction implements Function<Flux<String>, Mono<Long>> {
protected static class FluxThenMonoFunction
implements Function<Flux<String>, Mono<Long>> {
@Override
public Mono<Long> apply(Flux<String> t) {
return t.count();
}
}
protected static class MonoThenFluxFunction implements Function<Mono<Long>, Flux<Integer>> {
protected static class MonoThenFluxFunction
implements Function<Mono<Long>, Flux<Integer>> {
@Override
public Flux<Integer> apply(Mono<Long> t) {
return Flux.range(0, Integer.parseInt(t.block().toString()));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2018 the original author or authors.
* Copyright 2012-2019-2018 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.
@@ -30,6 +30,8 @@ import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -65,9 +67,6 @@ import org.springframework.util.StreamUtils;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
* @author Artem Bilan
@@ -75,15 +74,22 @@ import reactor.core.publisher.Mono;
*/
public class ContextFunctionCatalogAutoConfigurationTests {
private ConfigurableApplicationContext context;
private FunctionCatalog catalog;
private FunctionInspector inspector;
private static String value;
private ConfigurableApplicationContext context;
private FunctionCatalog catalog;
private FunctionInspector inspector;
public static void set(Object value) {
ContextFunctionCatalogAutoConfigurationTests.value = value.toString();
}
@After
public void close() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
ContextFunctionCatalogAutoConfigurationTests.value = null;
}
@@ -91,280 +97,325 @@ public class ContextFunctionCatalogAutoConfigurationTests {
@Test
public void lookUps() {
create(SimpleConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(context.getBean("function2")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function,function2"))
.isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = catalog.lookup(Function.class,
assertThat(this.context.getBean("function2")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class,
"function,function2")).isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = this.catalog.lookup(Function.class,
"function,function2,function3");
assertThat(f).isInstanceOf(Function.class);
assertThat(f.apply(Flux.just("hello")).blockFirst())
.isEqualTo("HELLOfunction2function3");
assertThat(context.getBean("supplierFoo")).isInstanceOf(Supplier.class);
assertThat((Supplier<?>) catalog.lookup(Supplier.class, "supplierFoo"))
assertThat(this.context.getBean("supplierFoo")).isInstanceOf(Supplier.class);
assertThat((Supplier<?>) this.catalog.lookup(Supplier.class, "supplierFoo"))
.isInstanceOf(Supplier.class);
assertThat(context.getBean("supplier_Foo")).isInstanceOf(Supplier.class);
assertThat((Supplier<?>) catalog.lookup(Supplier.class, "supplier_Foo"))
assertThat(this.context.getBean("supplier_Foo")).isInstanceOf(Supplier.class);
assertThat((Supplier<?>) this.catalog.lookup(Supplier.class, "supplier_Foo"))
.isInstanceOf(Supplier.class);
}
@Test
public void ambiguousFunction() {
create(AmbiguousConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat((Supplier<?>) catalog.lookup(Supplier.class, "foos"))
assertThat((Supplier<?>) this.catalog.lookup(Supplier.class, "foos"))
.isInstanceOf(Supplier.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(inspector.getOutputType(catalog.lookup(Supplier.class, "foos")))
.isEqualTo(Foo.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(
this.inspector.getOutputType(this.catalog.lookup(Supplier.class, "foos")))
.isEqualTo(Foo.class);
}
@Test
public void configurationFunction() {
create(FunctionConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(Foo.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(Flux.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(
this.inspector.getOutputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(Foo.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(Flux.class);
}
@Test
public void dependencyInjection() {
create(DependencyInjectionConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@Test
public void externalDependencyInjection() {
create(ExternalDependencyConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@Test
public void composedFunction() {
create(MultipleConfiguration.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos,bars"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos,bars"))
.isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "names,foos"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "names,foos"))
.isNull();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos,bars")))
.isAssignableFrom(String.class);
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos,bars")))
.isAssignableFrom(Bar.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "foos,bars")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getOutputType(this.catalog.lookup(Function.class, "foos,bars")))
.isAssignableFrom(Bar.class);
}
@Test
public void composedSupplier() {
create(MultipleConfiguration.class);
assertThat((Supplier<?>) catalog.lookup(Supplier.class, "names,foos"))
assertThat((Supplier<?>) this.catalog.lookup(Supplier.class, "names,foos"))
.isInstanceOf(Supplier.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "names,foos"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "names,foos"))
.isNull();
assertThat(inspector.getOutputType(catalog.lookup(Supplier.class, "names,foos")))
.isAssignableFrom(Foo.class);
assertThat(this.inspector
.getOutputType(this.catalog.lookup(Supplier.class, "names,foos")))
.isAssignableFrom(Foo.class);
// The input type is the same as the input type of the first element in the chain
assertThat(inspector.getInputType(catalog.lookup(Supplier.class, "names,foos")))
.isAssignableFrom(Void.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Supplier.class, "names,foos")))
.isAssignableFrom(Void.class);
}
@Test
public void composedConsumer() {
create(MultipleConfiguration.class);
assertThat((Consumer<?>) catalog.lookup(Consumer.class, "foos,print")).isNull();
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos,print"))
assertThat((Consumer<?>) this.catalog.lookup(Consumer.class, "foos,print"))
.isNull();
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos,print"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos,print")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "foos,print")))
.isAssignableFrom(String.class);
// The output type is the same as the output type of the last element in the chain
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos,print")))
.isAssignableFrom(Void.class);
assertThat(this.inspector
.getOutputType(this.catalog.lookup(Function.class, "foos,print")))
.isAssignableFrom(Void.class);
}
@Test
public void genericFunction() {
create(GenericConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@Test
public void fluxMessageFunction() {
create(FluxMessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
assertThat(
this.inspector.isMessage(this.catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
}
@Test
public void publisherMessageFunction() {
create(PublisherMessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Publisher.class);
assertThat(
this.inspector.isMessage(this.catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Publisher.class);
}
@Test
public void monoFunction() {
create(MonoConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isFalse();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
assertThat(inspector.getOutputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Mono.class);
assertThat(
this.inspector.isMessage(this.catalog.lookup(Function.class, "function")))
.isFalse();
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
assertThat(this.inspector
.getOutputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Mono.class);
}
@Test
public void messageFunction() {
create(MessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(
this.inspector.isMessage(this.catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
}
@Test
public void genericFluxFunction() {
create(GenericFluxConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
}
@Test
public void externalFunction() {
create(ExternalConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@Test
public void singletonFunction() {
create(SingletonConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
}
@Test
public void singletonMessageFunction() {
create(SingletonMessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(
this.inspector.isMessage(this.catalog.lookup(Function.class, "function")))
.isTrue();
}
@Test
public void nonParametericTypeFunction() {
create(NonParametricTypeSingletonConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
}
@Test
public void componentScanBeanFunction() {
create(ComponentScanBeanConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@Test
public void componentScanFunction() {
create(ComponentScanConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@Test
public void componentScanJarFunction() {
try {
create("greeter.jar", ComponentScanJarConfiguration.class);
assertThat(context.getBean("greeter")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "greeter"))
assertThat(this.context.getBean("greeter")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "greeter"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "greeter")))
.isAssignableFrom(String.class);
assertThat(
inspector.getInputWrapper(catalog.lookup(Function.class, "greeter")))
assertThat(this.inspector
.getInputType(this.catalog.lookup(Function.class, "greeter")))
.isAssignableFrom(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "greeter")))
.isAssignableFrom(String.class);
}
finally {
@@ -372,7 +423,6 @@ public class ContextFunctionCatalogAutoConfigurationTests {
}
}
private void create(String jarfile, Class<?> config, String... props) {
try {
URL[] urls = new URL[] { new ClassPathResource(jarfile).getURL() };
@@ -388,64 +438,67 @@ public class ContextFunctionCatalogAutoConfigurationTests {
@Test
public void simpleFunction() {
create(SimpleConfiguration.class);
Object bean = context.getBean("function");
Object bean = this.context.getBean("function");
assertThat(bean).isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> function = catalog.lookup(Function.class,
"function");
Function<Flux<String>, Flux<String>> function = this.catalog
.lookup(Function.class, "function");
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO");
assertThat(bean).isNotSameAs(function);
assertThat(inspector.getRegistration(bean)).isNotNull();
assertThat(inspector.getRegistration(bean).getType())
.isEqualTo(inspector.getRegistration(function).getType());
assertThat(this.inspector.getRegistration(bean)).isNotNull();
assertThat(this.inspector.getRegistration(bean).getType())
.isEqualTo(this.inspector.getRegistration(function).getType());
}
@Test
public void simpleSupplier() {
create(SimpleConfiguration.class);
assertThat(context.getBean("supplier")).isInstanceOf(Supplier.class);
Supplier<Flux<String>> supplier = catalog.lookup(Supplier.class, "supplier");
assertThat(this.context.getBean("supplier")).isInstanceOf(Supplier.class);
Supplier<Flux<String>> supplier = this.catalog.lookup(Supplier.class, "supplier");
assertThat(supplier.get().blockFirst()).isEqualTo("hello");
}
@Test
public void simpleConsumer() {
create(SimpleConfiguration.class);
assertThat(context.getBean("consumer")).isInstanceOf(Consumer.class);
Function<Flux<String>, Mono<Void>> consumer = catalog.lookup(Function.class,
assertThat(this.context.getBean("consumer")).isInstanceOf(Consumer.class);
Function<Flux<String>, Mono<Void>> consumer = this.catalog.lookup(Function.class,
"consumer");
consumer.apply(Flux.just("foo", "bar")).subscribe();
assertThat(context.getBean(SimpleConfiguration.class).list).hasSize(2);
assertThat(this.context.getBean(SimpleConfiguration.class).list).hasSize(2);
}
@Test
public void qualifiedBean() {
create(QualifiedConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function")).isNull();
assertThat((Function<?, ?>) catalog.lookup(Function.class, "other"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isNull();
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "other"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "other")))
.isEqualTo(String.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "other")))
.isEqualTo(String.class);
}
@Test
public void aliasBean() {
create(AliasConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isNotNull();
assertThat((Function<?, ?>) catalog.lookup(Function.class, "other"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "other"))
.isInstanceOf(Function.class);
}
@Test
public void registrationBean() {
create(RegistrationConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function")).isNull();
assertThat((Function<?, ?>) catalog.lookup(Function.class, "registration"))
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isNull();
assertThat((Function<?, ?>) catalog.lookup(Function.class, "other"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "registration"))
.isNull();
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "other"))
.isInstanceOf(Function.class);
}
@@ -455,11 +508,12 @@ public class ContextFunctionCatalogAutoConfigurationTests {
"spring.cloud.function.compile.foos.lambda=v -> v.toUpperCase()",
"spring.cloud.function.compile.foos.inputType=String",
"spring.cloud.function.compile.foos.outputType=String");
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@Test
@@ -471,11 +525,12 @@ public class ContextFunctionCatalogAutoConfigurationTests {
StreamUtils.copy(compiled.getGeneratedClassBytes(), resource.getOutputStream());
create(EmptyConfiguration.class,
"spring.cloud.function.imports.foos.location=file:./target/foos.fun");
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@Test
@@ -485,12 +540,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
+ "::set",
"spring.cloud.function.compile.foos.type=consumer",
"spring.cloud.function.compile.foos.inputType=String");
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
@SuppressWarnings("unchecked")
Consumer<String> consumer = (Consumer<String>) context.getBean("foos");
Consumer<String> consumer = (Consumer<String>) this.context.getBean("foos");
consumer.accept("hello");
assertThat(ContextFunctionCatalogAutoConfigurationTests.value).isEqualTo("hello");
}
@@ -501,12 +557,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
"spring.cloud.function.compile.foos.lambda=f -> f.subscribe("
+ getClass().getName() + "::set)",
"spring.cloud.function.compile.foos.type=consumer");
assertThat((Consumer<?>) catalog.lookup(Consumer.class, "foos"))
assertThat((Consumer<?>) this.catalog.lookup(Consumer.class, "foos"))
.isInstanceOf(Consumer.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Consumer.class, "foos")))
.isEqualTo(Flux.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Consumer.class, "foos")))
.isEqualTo(Flux.class);
@SuppressWarnings("unchecked")
Consumer<Flux<String>> consumer = (Consumer<Flux<String>>) context
Consumer<Flux<String>> consumer = (Consumer<Flux<String>>) this.context
.getBean("foos");
consumer.accept(Flux.just("hello"));
assertThat(ContextFunctionCatalogAutoConfigurationTests.value).isEqualTo("hello");
@@ -516,7 +573,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void factoryBeanFunction() {
create(FactoryBeanConfiguration.class);
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = this.catalog.lookup(Function.class,
"function");
@@ -528,23 +585,21 @@ public class ContextFunctionCatalogAutoConfigurationTests {
}
private void create(Class<?>[] types, String... props) {
context = new SpringApplicationBuilder(types).properties(props).run();
catalog = context.getBean(FunctionCatalog.class);
inspector = context.getBean(FunctionInspector.class);
}
public static void set(Object value) {
ContextFunctionCatalogAutoConfigurationTests.value = value.toString();
this.context = new SpringApplicationBuilder(types).properties(props).run();
this.catalog = this.context.getBean(FunctionCatalog.class);
this.inspector = this.context.getBean(FunctionInspector.class);
}
@EnableAutoConfiguration
@Configuration
protected static class EmptyConfiguration {
}
@EnableAutoConfiguration
@Configuration
protected static class SimpleConfiguration {
private List<String> list = new ArrayList<>();
@Bean
@@ -574,8 +629,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
@Bean
public Consumer<String> consumer() {
return value -> list.add(value);
return value -> this.list.add(value);
}
}
@EnableAutoConfiguration
@@ -591,6 +647,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public String value() {
return "Hello";
}
}
@EnableAutoConfiguration
@@ -607,6 +664,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public String value() {
return "Hello";
}
}
@EnableAutoConfiguration
@@ -618,6 +676,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public String value() {
return "Hello";
}
}
@EnableAutoConfiguration
@@ -634,11 +693,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public Supplier<Foo> supplier() {
return () -> new Foo("bar");
}
}
@EnableAutoConfiguration
@Configuration
protected static class MultipleConfiguration {
@Bean
public Function<String, Foo> foos() {
return value -> new Foo(value.toUpperCase());
@@ -658,22 +719,26 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public Supplier<String> names() {
return () -> "Mark";
}
}
@EnableAutoConfiguration
@Configuration
protected static class GenericConfiguration {
@Bean
public Function<Map<String, String>, Map<String, String>> function() {
return m -> m.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(),
e -> e.getValue().toString().toUpperCase()));
}
}
@EnableAutoConfiguration
@Configuration
@Import(GenericFunction.class)
protected static class ExternalConfiguration {
}
@EnableAutoConfiguration
@@ -685,6 +750,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
throws BeansException {
beanFactory.registerSingleton("function", new SingletonFunction());
}
}
@EnableAutoConfiguration
@@ -697,15 +763,18 @@ public class ContextFunctionCatalogAutoConfigurationTests {
throws BeansException {
beanFactory.registerSingleton("function", new SingletonMessageFunction());
}
}
@EnableAutoConfiguration
@Configuration
protected static class NonParametricTypeSingletonConfiguration {
@Bean
public SingletonFunction function() {
return new SingletonFunction();
}
}
protected static class SingletonFunction implements Function<Integer, String> {
@@ -731,90 +800,108 @@ public class ContextFunctionCatalogAutoConfigurationTests {
@Configuration
@ComponentScan(basePackageClasses = GenericFunction.class)
protected static class ComponentScanBeanConfiguration {
}
@EnableAutoConfiguration
@Configuration
@ComponentScan(basePackageClasses = ScannedFunction.class)
protected static class ComponentScanConfiguration {
}
@EnableAutoConfiguration
@Configuration
protected static class ComponentScanJarConfiguration {
}
@EnableAutoConfiguration
@Configuration
protected static class GenericFluxConfiguration {
@Bean
public Function<Flux<Map<String, String>>, Flux<Map<String, String>>> function() {
return flux -> flux.map(m -> m.entrySet().stream().collect(Collectors
.toMap(e -> e.getKey(), e -> e.getValue().toString().toUpperCase())));
}
}
@EnableAutoConfiguration
@Configuration
protected static class FluxMessageConfiguration {
@Bean
public Function<Flux<Message<String>>, Flux<Message<String>>> function() {
return flux -> flux.map(m -> MessageBuilder
.withPayload(m.getPayload().toUpperCase()).build());
}
}
@EnableAutoConfiguration
@Configuration
protected static class PublisherMessageConfiguration {
@Bean
public Function<Publisher<Message<String>>, Publisher<Message<String>>> function() {
return flux -> Flux.from(flux).map(m -> MessageBuilder
.withPayload(m.getPayload().toUpperCase()).build());
}
}
@EnableAutoConfiguration
@Configuration
protected static class MonoConfiguration {
@Bean
public Function<Flux<String>, Mono<Map<String, Integer>>> function() {
return flux -> flux.collect(HashMap::new,
(map, word) -> map.merge(word, 1, Integer::sum));
}
}
@EnableAutoConfiguration
@Configuration
protected static class MessageConfiguration {
@Bean
public Function<Message<String>, Message<String>> function() {
return m -> MessageBuilder.withPayload(m.getPayload().toUpperCase()).build();
}
}
@EnableAutoConfiguration
@Configuration
protected static class QualifiedConfiguration {
@Bean
@Qualifier("other")
public Function<String, String> function() {
return value -> value.toUpperCase();
}
}
@EnableAutoConfiguration
@Configuration
protected static class AliasConfiguration {
@Bean({ "function", "other" })
public Function<String, String> function() {
return value -> value.toUpperCase();
}
}
@EnableAutoConfiguration
@Configuration
protected static class RegistrationConfiguration {
@Bean
public FunctionRegistration<Function<String, String>> registration() {
return new FunctionRegistration<Function<String, String>>(function(),
@@ -825,6 +912,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public Function<String, String> function() {
return value -> value.toUpperCase();
}
}
@EnableAutoConfiguration
@@ -865,6 +953,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
}
public static class Foo {
private String value;
public Foo(String value) {
@@ -875,15 +964,17 @@ public class ContextFunctionCatalogAutoConfigurationTests {
}
public String getValue() {
return value;
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class Bar {
private String message;
public Bar(String value) {
@@ -902,4 +993,5 @@ public class ContextFunctionCatalogAutoConfigurationTests {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2018 the original author or authors.
* Copyright 2012-2019-2018 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.
@@ -26,10 +26,11 @@ import java.util.function.Function;
import java.util.function.Supplier;
import com.google.gson.Gson;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanCreationException;
@@ -47,9 +48,6 @@ import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Dave Syer
*
@@ -57,30 +55,34 @@ import reactor.core.publisher.Mono;
public class ContextFunctionCatalogInitializerTests {
private GenericApplicationContext context;
private FunctionCatalog catalog;
private FunctionInspector inspector;
@After
public void close() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@Test
public void lookUps() {
create(SimpleConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function"))
.isInstanceOf(FunctionRegistration.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
}
@Test
public void properties() {
create(PropertiesConfiguration.class, "app.greeting=hello");
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat(this.context.getBean("function"))
.isInstanceOf(FunctionRegistration.class);
@SuppressWarnings("unchecked")
Function<Flux<String>, Flux<String>> function = (Function<Flux<String>, Flux<String>>) catalog
Function<Flux<String>, Flux<String>> function = (Function<Flux<String>, Flux<String>>) this.catalog
.lookup(Function.class, "function");
assertThat(function).isInstanceOf(Function.class);
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("hello foo");
@@ -89,9 +91,10 @@ public class ContextFunctionCatalogInitializerTests {
@Test
public void value() {
create(ValueConfiguration.class, "app.greeting=hello");
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat(this.context.getBean("function"))
.isInstanceOf(FunctionRegistration.class);
@SuppressWarnings("unchecked")
Function<Flux<String>, Flux<String>> function = (Function<Flux<String>, Flux<String>>) catalog
Function<Flux<String>, Flux<String>> function = (Function<Flux<String>, Flux<String>>) this.catalog
.lookup(Function.class, "function");
assertThat(function).isInstanceOf(Function.class);
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("hello foo");
@@ -101,9 +104,10 @@ public class ContextFunctionCatalogInitializerTests {
@Ignore
public void compose() {
create(SimpleConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat(this.context.getBean("function"))
.isInstanceOf(FunctionRegistration.class);
@SuppressWarnings("unchecked")
Supplier<Flux<String>> supplier = (Supplier<Flux<String>>) catalog
Supplier<Flux<String>> supplier = (Supplier<Flux<String>>) this.catalog
.lookup(Supplier.class, "supplier|function");
assertThat(supplier).isInstanceOf(Supplier.class);
assertThat(supplier.get().blockFirst()).isEqualTo("HELLO");
@@ -113,8 +117,9 @@ public class ContextFunctionCatalogInitializerTests {
@Test(expected = BeanCreationException.class)
public void missingType() {
create(MissingTypeConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "function"))
assertThat(this.context.getBean("function"))
.isInstanceOf(FunctionRegistration.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "function"))
.isInstanceOf(Function.class);
// TODO: support for type inference from functional bean registrations
}
@@ -122,64 +127,70 @@ public class ContextFunctionCatalogInitializerTests {
@Test
public void configurationFunction() {
create(FunctionConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(Function.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(Foo.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(Flux.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(
this.inspector.getOutputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(Foo.class);
assertThat(this.inspector
.getInputWrapper(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(Flux.class);
}
@Test
public void dependencyInjection() {
create(DependencyInjectionConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(FunctionRegistration.class);
assertThat((Function<?, ?>) catalog.lookup(Function.class, "foos"))
assertThat(this.context.getBean("foos")).isInstanceOf(FunctionRegistration.class);
assertThat((Function<?, ?>) this.catalog.lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(
this.inspector.getInputType(this.catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@Test
public void simpleFunction() {
create(SimpleConfiguration.class);
Object bean = context.getBean("function");
Object bean = this.context.getBean("function");
assertThat(bean).isInstanceOf(FunctionRegistration.class);
Function<Flux<String>, Flux<String>> function = catalog.lookup(Function.class,
"function");
Function<Flux<String>, Flux<String>> function = this.catalog
.lookup(Function.class, "function");
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO");
assertThat(bean).isNotSameAs(function);
assertThat(inspector.getRegistration(function)).isNotNull();
assertThat(inspector.getRegistration(function).getType()).isEqualTo(
assertThat(this.inspector.getRegistration(function)).isNotNull();
assertThat(this.inspector.getRegistration(function).getType()).isEqualTo(
FunctionType.from(String.class).to(String.class).wrap(Flux.class));
}
@Test
public void simpleSupplier() {
create(SimpleConfiguration.class);
assertThat(context.getBean("supplier")).isInstanceOf(FunctionRegistration.class);
Supplier<Flux<String>> supplier = catalog.lookup(Supplier.class, "supplier");
assertThat(this.context.getBean("supplier"))
.isInstanceOf(FunctionRegistration.class);
Supplier<Flux<String>> supplier = this.catalog.lookup(Supplier.class, "supplier");
assertThat(supplier.get().blockFirst()).isEqualTo("hello");
}
@Test
public void simpleConsumer() {
create(SimpleConfiguration.class);
assertThat(context.getBean("consumer")).isInstanceOf(FunctionRegistration.class);
Function<Flux<String>, Mono<Void>> consumer = catalog.lookup(Function.class,
assertThat(this.context.getBean("consumer"))
.isInstanceOf(FunctionRegistration.class);
Function<Flux<String>, Mono<Void>> consumer = this.catalog.lookup(Function.class,
"consumer");
consumer.apply(Flux.just("foo", "bar")).subscribe();
assertThat(context.getBean(SimpleConfiguration.class).list).hasSize(2);
assertThat(this.context.getBean(SimpleConfiguration.class).list).hasSize(2);
}
@Test
public void overrideGson() {
create(GsonConfiguration.class);
Gson user = context.getBean(GsonConfiguration.class).gson();
Gson bean = context.getBean(Gson.class);
Gson user = this.context.getBean(GsonConfiguration.class).gson();
Gson bean = this.context.getBean(Gson.class);
assertThat(user).isSameAs(bean);
}
@@ -193,7 +204,7 @@ public class ContextFunctionCatalogInitializerTests {
private void create(ApplicationContextInitializer<GenericApplicationContext>[] types,
String... props) {
context = new GenericApplicationContext();
this.context = new GenericApplicationContext();
Map<String, Object> map = new HashMap<>();
for (String prop : props) {
String[] array = StringUtils.delimitedListToStringArray(prop, "=");
@@ -202,17 +213,17 @@ public class ContextFunctionCatalogInitializerTests {
map.put(key, value);
}
if (!map.isEmpty()) {
context.getEnvironment().getPropertySources()
this.context.getEnvironment().getPropertySources()
.addFirst(new MapPropertySource("testProperties", map));
}
for (ApplicationContextInitializer<GenericApplicationContext> type : types) {
type.initialize(context);
type.initialize(this.context);
}
new ContextFunctionCatalogInitializer.ContextFunctionCatalogBeanRegistrar(context)
.postProcessBeanDefinitionRegistry(context);
context.refresh();
catalog = context.getBean(FunctionCatalog.class);
inspector = context.getBean(FunctionInspector.class);
new ContextFunctionCatalogInitializer.ContextFunctionCatalogBeanRegistrar(
this.context).postProcessBeanDefinitionRegistry(this.context);
this.context.refresh();
this.catalog = this.context.getBean(FunctionCatalog.class);
this.inspector = this.context.getBean(FunctionInspector.class);
}
protected static class EmptyConfiguration
@@ -221,6 +232,7 @@ public class ContextFunctionCatalogInitializerTests {
@Override
public void initialize(GenericApplicationContext applicationContext) {
}
}
protected static class MissingTypeConfiguration
@@ -270,8 +282,9 @@ public class ContextFunctionCatalogInitializerTests {
@Bean
public Consumer<String> consumer() {
return value -> list.add(value);
return value -> this.list.add(value);
}
}
@ConfigurationProperties("app")
@@ -298,7 +311,7 @@ public class ContextFunctionCatalogInitializerTests {
@Bean
public Function<String, String> function() {
return value -> greeting + " " + value;
return value -> this.greeting + " " + value;
}
}
@@ -319,7 +332,7 @@ public class ContextFunctionCatalogInitializerTests {
@Bean
public Function<String, String> function() {
return value -> greeting + " " + value;
return value -> this.greeting + " " + value;
}
}
@@ -363,6 +376,7 @@ public class ContextFunctionCatalogInitializerTests {
public String value() {
return "Hello";
}
}
protected static class FunctionConfiguration
@@ -386,9 +400,11 @@ public class ContextFunctionCatalogInitializerTests {
public String value() {
return "Hello";
}
}
public static class Foo {
private String value;
public Foo(String value) {
@@ -399,12 +415,13 @@ public class ContextFunctionCatalogInitializerTests {
}
public String getValue() {
return value;
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-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,9 +16,6 @@
package org.springframework.cloud.function.context.config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNull;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
@@ -33,14 +30,17 @@ import java.util.function.Supplier;
import org.junit.After;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration.ContextFunctionRegistry;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ClassUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNull;
/**
* @author Dave Syer
@@ -51,7 +51,9 @@ import reactor.core.publisher.Mono;
public class ContextFunctionPostProcessorTests {
private ContextFunctionRegistry processor = new ContextFunctionRegistry();
private URLClassLoader classLoader;
private ClassLoader contextClassLoader;
@After
@@ -60,128 +62,136 @@ public class ContextFunctionPostProcessorTests {
this.classLoader.close();
}
if (Thread.currentThread().getContextClassLoader() != null) {
ClassUtils.overrideThreadContextClassLoader(contextClassLoader);
ClassUtils.overrideThreadContextClassLoader(this.contextClassLoader);
}
}
@Test
public void basicRegistrationFeatures() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
@SuppressWarnings("unchecked")
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) processor
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) this.processor
.lookupFunction("foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void registrationThroughMerge() {
FunctionRegistration<Foos> registration = new FunctionRegistration<>(new Foos(), "foos");
processor.merge(Collections.singletonMap("foos", registration),
FunctionRegistration<Foos> registration = new FunctionRegistration<>(new Foos(),
"foos");
this.processor.merge(Collections.singletonMap("foos", registration),
Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap());
@SuppressWarnings("unchecked")
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) processor
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) this.processor
.lookupFunction("foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void registrationThroughMergeFromNamedFunction() {
processor.merge(Collections.emptyMap(), Collections.emptyMap(),
this.processor.merge(Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(), Collections.singletonMap("foos", new Foos()));
@SuppressWarnings("unchecked")
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) processor
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) this.processor
.lookupFunction("foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void composeWithComma() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
processor.register(new FunctionRegistration<>(new Bars(), "bars"));
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
this.processor.register(new FunctionRegistration<>(new Bars(), "bars"));
@SuppressWarnings("unchecked")
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) processor
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) this.processor
.lookupFunction("foos,bars");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4");
assertThat(processor.getRegistration(foos).getNames())
assertThat(this.processor.getRegistration(foos).getNames())
.containsExactly("foos|bars");
}
@Test
public void supplierAndFunction() {
processor.register(new FunctionRegistration<Supplier<String>>(() -> "foo", "supplier"));
processor.register(new FunctionRegistration<Function<String, String>>((x) -> x.toUpperCase(), "function"));
this.processor.register(
new FunctionRegistration<Supplier<String>>(() -> "foo", "supplier"));
this.processor.register(new FunctionRegistration<Function<String, String>>(
(x) -> x.toUpperCase(), "function"));
@SuppressWarnings("unchecked")
Supplier<Flux<String>> supplier = (Supplier<Flux<String>>) processor.lookupSupplier("supplier|function");
Supplier<Flux<String>> supplier = (Supplier<Flux<String>>) this.processor
.lookupSupplier("supplier|function");
assertThat(supplier.get().blockFirst()).isEqualTo("FOO");
assertThat(processor.getRegistration(supplier).getNames()).containsExactly("supplier|function");
assertThat(this.processor.getRegistration(supplier).getNames())
.containsExactly("supplier|function");
}
@SuppressWarnings("unchecked")
@Test
public void supplierAndConsumer() {
processor.register(new FunctionRegistration<Supplier<String>>(() -> "foo", "supplier"));
processor.register(new FunctionRegistration<Consumer<String>>(System.out::println, "consumer"));
Supplier<Mono<Void>> supplier = (Supplier<Mono<Void>>) processor.lookupSupplier("supplier|consumer");
this.processor.register(
new FunctionRegistration<Supplier<String>>(() -> "foo", "supplier"));
this.processor.register(new FunctionRegistration<Consumer<String>>(
System.out::println, "consumer"));
Supplier<Mono<Void>> supplier = (Supplier<Mono<Void>>) this.processor
.lookupSupplier("supplier|consumer");
assertNull(supplier.get().block());
}
@Test
public void compose() {
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
processor.register(new FunctionRegistration<>(new Bars(), "bars"));
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
this.processor.register(new FunctionRegistration<>(new Bars(), "bars"));
@SuppressWarnings("unchecked")
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) processor
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) this.processor
.lookupFunction("foos|bars");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4");
assertThat(processor.getRegistration(foos).getNames())
assertThat(this.processor.getRegistration(foos).getNames())
.containsExactly("foos|bars");
}
@Test
public void composeWrapper() {
processor.register(new FunctionRegistration<>(new WrappedSource(), "ints"));
processor.register(new FunctionRegistration<>(new Foos(), "foos"));
this.processor.register(new FunctionRegistration<>(new WrappedSource(), "ints"));
this.processor.register(new FunctionRegistration<>(new Foos(), "foos"));
@SuppressWarnings("unchecked")
Supplier<Flux<String>> foos = (Supplier<Flux<String>>) processor
Supplier<Flux<String>> foos = (Supplier<Flux<String>>) this.processor
.lookupSupplier("ints|foos");
assertThat(foos.get().blockFirst()).isEqualTo("8");
assertThat(processor.getRegistration(foos).getNames())
assertThat(this.processor.getRegistration(foos).getNames())
.containsExactly("ints|foos");
assertThat(processor.getRegistration(foos).getType().getOutputWrapper())
assertThat(this.processor.getRegistration(foos).getType().getOutputWrapper())
.isEqualTo(Flux.class);
}
@Test
public void isolatedFunction() {
contextClassLoader = ClassUtils
this.contextClassLoader = ClassUtils
.overrideThreadContextClassLoader(getClass().getClassLoader());
processor.register(new FunctionRegistration<>(create(Foos.class), "foos"));
this.processor.register(new FunctionRegistration<>(create(Foos.class), "foos"));
@SuppressWarnings("unchecked")
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) processor
Function<Flux<Integer>, Flux<String>> foos = (Function<Flux<Integer>, Flux<String>>) this.processor
.lookupFunction("foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void isolatedSupplier() {
contextClassLoader = ClassUtils
this.contextClassLoader = ClassUtils
.overrideThreadContextClassLoader(getClass().getClassLoader());
processor.register(
new FunctionRegistration<>(create(Source.class), "source"));
this.processor
.register(new FunctionRegistration<>(create(Source.class), "source"));
@SuppressWarnings("unchecked")
Supplier<Flux<Integer>> source = (Supplier<Flux<Integer>>) processor
Supplier<Flux<Integer>> source = (Supplier<Flux<Integer>>) this.processor
.lookupSupplier("source");
assertThat(source.get().blockFirst()).isEqualTo(4);
}
@Test
public void isolatedConsumer() {
contextClassLoader = ClassUtils
this.contextClassLoader = ClassUtils
.overrideThreadContextClassLoader(getClass().getClassLoader());
Object target = create(Sink.class);
processor.register(new FunctionRegistration<>(target, "sink"));
this.processor.register(new FunctionRegistration<>(target, "sink"));
@SuppressWarnings("unchecked")
Function<Flux<String>, Mono<Void>> sink = (Function<Flux<String>, Mono<Void>>) processor
Function<Flux<String>, Mono<Void>> sink = (Function<Flux<String>, Mono<Void>>) this.processor
.lookupFunction("sink");
sink.apply(Flux.just("Hello")).subscribe();
@SuppressWarnings("unchecked")
@@ -199,14 +209,14 @@ public class ContextFunctionPostProcessorTests {
String pathEntry = jcpEntries.nextToken();
try {
urls.add(new File(pathEntry).toURI().toURL());
} catch (MalformedURLException e) {
}
catch (MalformedURLException e) {
}
}
this.classLoader = new URLClassLoader(
urls.toArray(new URL[0]),
this.classLoader = new URLClassLoader(urls.toArray(new URL[0]),
getClass().getClassLoader().getParent());
return BeanUtils
.instantiateClass(ClassUtils.resolveClassName(type.getName(), classLoader));
return BeanUtils.instantiateClass(
ClassUtils.resolveClassName(type.getName(), this.classLoader));
}
public static class Foos implements Function<Integer, String> {
@@ -239,7 +249,7 @@ public class ContextFunctionPostProcessorTests {
public void accept(String t) {
assertThat(ClassUtils.resolveClassName(Bar.class.getName(), null)
.getClassLoader()).isEqualTo(getClass().getClassLoader());
values.add(t);
this.values.add(t);
}
}
@@ -263,6 +273,7 @@ public class ContextFunctionPostProcessorTests {
}
public static class Foo {
private String value;
public Foo(String value) {
@@ -273,15 +284,17 @@ public class ContextFunctionPostProcessorTests {
}
public String getValue() {
return value;
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class Bar {
private String message;
public Bar(String value) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-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.
@@ -20,6 +20,7 @@ import java.util.function.Function;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.function.context.FunctionCatalog;
@@ -28,11 +29,9 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
/**
* Test that spring.main.sources works with the functional approach.
*
*
* @author Dave Syer
*
*/
@@ -45,15 +44,18 @@ public class FunctionalStringSourceTests {
@Test
public void words() throws Exception {
Function<Flux<String>, Flux<String>> function = catalog.lookup(Function.class,
"function");
Function<Flux<String>, Flux<String>> function = this.catalog
.lookup(Function.class, "function");
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO");
}
protected static class TestConfiguration implements Function<String, String> {
@Override
public String apply(String value) {
return value.toUpperCase();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2012-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.
@@ -20,6 +20,7 @@ import java.util.function.Function;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
@@ -28,8 +29,6 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
/**
* @author Dave Syer
*
@@ -43,16 +42,19 @@ public class FunctionalTests {
@Test
public void words() throws Exception {
Function<Flux<String>, Flux<String>> function = catalog.lookup(Function.class,
"function");
Function<Flux<String>, Flux<String>> function = this.catalog
.lookup(Function.class, "function");
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO");
}
@SpringBootConfiguration
protected static class TestConfiguration implements Function<String, String> {
@Override
public String apply(String value) {
return value.toUpperCase();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -23,8 +23,10 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class FooConfiguration {
@Bean
public Function<String, Foo> foos(String foo) {
return value -> new Foo(foo + ": " + value.toUpperCase());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -29,9 +29,11 @@ import org.springframework.stereotype.Component;
@Component("function")
public class ScannedFunction
implements Function<Map<String, String>, Map<String, String>> {
@Override
public Map<String, String> apply(Map<String, String> m) {
return m.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(),
e -> e.getValue().toString().toUpperCase()));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 the original author or authors.
* Copyright 2012-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.
@@ -29,10 +29,11 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
public class GenericFunction {
@Bean
public Function<Map<String, String>, Map<String, String>> function() {
return m -> m.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(),
e -> e.getValue().toString().toUpperCase()));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2012-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.
@@ -20,7 +20,6 @@ import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -43,29 +42,29 @@ public class JsonMapperTests {
private JsonMapper mapper;
public JsonMapperTests(JsonMapper mapper) {
this.mapper = mapper;
}
@Parameters
public static List<Object[]> params() {
return Arrays.asList(new Object[] { new GsonMapper(new Gson()) },
new Object[] { new JacksonMapper(new ObjectMapper()) });
}
public JsonMapperTests(JsonMapper mapper) {
this.mapper = mapper;
}
@Test
public void vanillaArray() {
String json = "[{\"value\":\"foo\"},{\"value\":\"foo\"}]";
List<Foo> list = mapper.toObject(json,
List<Foo> list = this.mapper.toObject(json,
ResolvableType.forClassWithGenerics(List.class, Foo.class).getType());
assertThat(list).hasSize(2);
assertThat(list.get(0).getValue()).isEqualTo("foo");
assertThat(mapper.toString(list)).isEqualTo(json);
assertThat(this.mapper.toString(list)).isEqualTo(json);
}
@Test
public void intArray() {
List<Integer> list = mapper.toObject("[123,456]",
List<Integer> list = this.mapper.toObject("[123,456]",
ResolvableType.forClassWithGenerics(List.class, Integer.class).getType());
assertThat(list).hasSize(2);
assertThat(list.get(0)).isEqualTo(123);
@@ -73,7 +72,7 @@ public class JsonMapperTests {
@Test
public void emptyArray() {
List<Foo> list = mapper.toObject("[]",
List<Foo> list = this.mapper.toObject("[]",
ResolvableType.forClassWithGenerics(List.class, Foo.class).getType());
assertThat(list).hasSize(0);
}
@@ -81,28 +80,29 @@ public class JsonMapperTests {
@Test
public void vanillaObject() {
String json = "{\"value\":\"foo\"}";
Foo foo = mapper.toObject(json, Foo.class);
Foo foo = this.mapper.toObject(json, Foo.class);
assertThat(foo.getValue()).isEqualTo("foo");
assertThat(mapper.toString(foo)).isEqualTo(json);
assertThat(this.mapper.toString(foo)).isEqualTo(json);
}
@Test
public void intValue() {
int foo = mapper.toObject("123", Integer.class);
int foo = this.mapper.toObject("123", Integer.class);
assertThat(foo).isEqualTo(123);
}
@Test
public void empty() {
Foo foo = mapper.toObject("{}", Foo.class);
Foo foo = this.mapper.toObject("{}", Foo.class);
assertThat(foo.getValue()).isNull();
}
public static class Foo {
private String value;
public String getValue() {
return value;
return this.value;
}
public void setValue(String value) {
@@ -110,4 +110,5 @@ public class JsonMapperTests {
}
}
}