GH-762 Fix condition for parsing JSON collection strings into individual messages

Resolves #762
This commit is contained in:
Oleg Zhurakousky
2021-11-08 11:09:51 +01:00
parent 11e528f38a
commit 5447465cc8
3 changed files with 145 additions and 5 deletions

View File

@@ -23,6 +23,7 @@ import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -37,6 +38,8 @@ import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionType;
import org.springframework.cloud.function.context.config.FunctionContextUtils;
@@ -45,7 +48,9 @@ import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Set of utility operations to interrogate function definitions.
@@ -80,6 +85,10 @@ public final class FunctionTypeUtils {
return Collection.class.isAssignableFrom(rawType);
}
public static boolean isTypeArray(Type type) {
return getRawType(type).isArray();
}
/**
* A convenience method identical to {@link #getImmediateGenericType(Type, int)}
* for cases when provided 'type' is {@link Publisher} or {@link Message}.
@@ -271,9 +280,23 @@ public final class FunctionTypeUtils {
type = FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), functionBeanDefinitionName)).getType();
}
}
else if (!(type instanceof ParameterizedType)) {
String beanDefinitionName = discoverBeanDefinitionNameByQualifier(applicationContext.getBeanFactory(), functionName);
if (StringUtils.hasText(beanDefinitionName)) {
type = FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), beanDefinitionName)).getType();
}
}
return type;
}
public static String discoverBeanDefinitionNameByQualifier(ListableBeanFactory beanFactory, String qualifier) {
Map<String, Object> beanMap = BeanFactoryAnnotationUtils.qualifiedBeansOfType(beanFactory, Object.class, qualifier);
if (!CollectionUtils.isEmpty(beanMap) && beanMap.size() == 1) {
return beanMap.keySet().iterator().next();
}
return null;
}
@SuppressWarnings("unchecked")
public static Type getOutputType(Type functionType) {
assertSupportedTypes(functionType);

View File

@@ -764,12 +764,22 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect
if (input instanceof Message) {
payload = ((Message) input).getPayload();
}
if (JsonMapper.isJsonStringRepresentsCollection(payload) && !FunctionTypeUtils.isTypeCollection(this.inputType)) {
payload = jsonMapper.fromJson(payload, List.class);
if (JsonMapper.isJsonStringRepresentsCollection(payload)
&& !FunctionTypeUtils.isTypeCollection(this.inputType) && !FunctionTypeUtils.isTypeArray(this.inputType)) {
MessageHeaders headers = ((Message) input).getHeaders();
input = ((List) payload).stream()
.map(p -> MessageBuilder.withPayload(p).copyHeaders(headers).build())
.collect(Collectors.toList());
Collection collectionPayload = jsonMapper.fromJson(payload, Collection.class);
Class inputClass = FunctionTypeUtils.getRawType(this.inputType);
if (this.isInputTypeMessage()) {
inputClass = FunctionTypeUtils.getRawType(FunctionTypeUtils.getImmediateGenericType(this.inputType, 0));
}
if (!inputClass.isAssignableFrom(Object.class) && !inputClass.isAssignableFrom(byte[].class)) {
logger.debug("Converting JSON string representing collection to a list of Messages. Function '"
+ this + "' will be invoked iteratively");
input = collectionPayload.stream()
.map(p -> MessageBuilder.withPayload(p).copyHeaders(headers).build())
.collect(Collectors.toList());
}
}
}