GH-596 Add support for handling conversion of complex types
Resolves #596
This commit is contained in:
@@ -676,11 +676,7 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Class<?> inputType = this.isTypePublisher(type) || this.isInputTypeMessage()
|
convertedInput = this.convertNonMessageInputIfNecessary(type, input);
|
||||||
? TypeResolver.resolveRawClass(FunctionTypeUtils.getImmediateGenericType(type, 0), null)
|
|
||||||
: this.getRawClassFor(type);
|
|
||||||
|
|
||||||
convertedInput = this.convertNonMessageInputIfNecessary(inputType, input);
|
|
||||||
}
|
}
|
||||||
// wrap in Message if necessary
|
// wrap in Message if necessary
|
||||||
if (this.isWrapConvertedInputInMessage(convertedInput)) {
|
if (this.isWrapConvertedInputInMessage(convertedInput)) {
|
||||||
@@ -721,18 +717,25 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private Object convertNonMessageInputIfNecessary(Class<?> inputType, Object input) {
|
private Object convertNonMessageInputIfNecessary(Type inputType, Object input) {
|
||||||
Object convertedInput = input;
|
Object convertedInput = input;
|
||||||
if (!inputType.isAssignableFrom(input.getClass())) {
|
Class<?> rawInputType = this.isTypePublisher(inputType) || this.isInputTypeMessage()
|
||||||
if (inputType != input.getClass()
|
? TypeResolver.resolveRawClass(FunctionTypeUtils.getImmediateGenericType(inputType, 0), null)
|
||||||
&& SimpleFunctionRegistry.this.conversionService != null
|
: this.getRawClassFor(inputType);
|
||||||
&& SimpleFunctionRegistry.this.conversionService.canConvert(input.getClass(), inputType)) {
|
|
||||||
convertedInput = SimpleFunctionRegistry.this.conversionService.convert(input, inputType);
|
if (JsonMapper.isJsonString(input) && !Message.class.isAssignableFrom(rawInputType)) {
|
||||||
|
if (FunctionTypeUtils.isMessage(inputType)) {
|
||||||
|
inputType = FunctionTypeUtils.getGenericType(inputType);
|
||||||
}
|
}
|
||||||
else {
|
if (Object.class != inputType) {
|
||||||
convertedInput = SimpleFunctionRegistry.this.jsonMapper.fromJson(input, inputType);
|
convertedInput = SimpleFunctionRegistry.this.jsonMapper.fromJson(input, inputType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (SimpleFunctionRegistry.this.conversionService != null
|
||||||
|
&& !rawInputType.equals(input.getClass())
|
||||||
|
&& SimpleFunctionRegistry.this.conversionService.canConvert(input.getClass(), rawInputType)) {
|
||||||
|
convertedInput = SimpleFunctionRegistry.this.conversionService.convert(input, rawInputType);
|
||||||
|
}
|
||||||
return convertedInput;
|
return convertedInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,6 +767,10 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isConversionHintRequired(Object actualType, Class<?> rawType) {
|
||||||
|
return rawType != actualType;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -778,7 +785,7 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect
|
|||||||
Object convertedInput = message;
|
Object convertedInput = message;
|
||||||
type = this.extractActualValueTypeIfNecessary(type);
|
type = this.extractActualValueTypeIfNecessary(type);
|
||||||
Class rawType = TypeResolver.resolveRawClass(type, null);
|
Class rawType = TypeResolver.resolveRawClass(type, null);
|
||||||
convertedInput = FunctionTypeUtils.isTypeCollection(type)
|
convertedInput = this.isConversionHintRequired(type, rawType)
|
||||||
? SimpleFunctionRegistry.this.messageConverter.fromMessage(message, rawType, type)
|
? SimpleFunctionRegistry.this.messageConverter.fromMessage(message, rawType, type)
|
||||||
: SimpleFunctionRegistry.this.messageConverter.fromMessage(message, rawType);
|
: SimpleFunctionRegistry.this.messageConverter.fromMessage(message, rawType);
|
||||||
|
|
||||||
|
|||||||
@@ -98,12 +98,16 @@ public abstract class JsonMapper {
|
|||||||
*/
|
*/
|
||||||
public static boolean isJsonString(Object value) {
|
public static boolean isJsonString(Object value) {
|
||||||
boolean isJson = false;
|
boolean isJson = false;
|
||||||
|
if (value instanceof byte[]) {
|
||||||
|
value = new String((byte[]) value, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
String str = ((String) value).trim();
|
String str = ((String) value).trim();
|
||||||
isJson = (str.startsWith("\"") && str.endsWith("\"")) ||
|
isJson = (str.startsWith("\"") && str.endsWith("\"")) ||
|
||||||
(str.startsWith("{") && str.endsWith("}")) ||
|
(str.startsWith("{") && str.endsWith("}")) ||
|
||||||
(str.startsWith("[") && str.endsWith("]"));
|
(str.startsWith("[") && str.endsWith("]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return isJson;
|
return isJson;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,6 +269,29 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
|||||||
assertThat(block).isNull();
|
assertThat(block).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
@Test
|
||||||
|
public void textTypeConversionWithComplexInputType() {
|
||||||
|
FunctionCatalog catalog = this.configureCatalog(ComplexTypeFunctionConfiguration.class);
|
||||||
|
Function function = catalog.lookup("function");
|
||||||
|
|
||||||
|
// as String
|
||||||
|
String result = (String) function.apply("{\"key\":\"purchase\",\"data\":{\"name\":\"bike\"}}");
|
||||||
|
assertThat(result).isEqualTo("BIKE");
|
||||||
|
|
||||||
|
// as byte[]
|
||||||
|
result = (String) function.apply("{\"key\":\"purchase\",\"data\":{\"name\":\"bike\"}}".getBytes());
|
||||||
|
assertThat(result).isEqualTo("BIKE");
|
||||||
|
|
||||||
|
// as Message<String>
|
||||||
|
result = (String) function.apply(MessageBuilder.withPayload("{\"key\":\"purchase\",\"data\":{\"name\":\"bike\"}}").build());
|
||||||
|
assertThat(result).isEqualTo("BIKE");
|
||||||
|
|
||||||
|
// as Message<BYTE[]>
|
||||||
|
result = (String) function.apply(MessageBuilder.withPayload("{\"key\":\"purchase\",\"data\":{\"name\":\"bike\"}}".getBytes()).build());
|
||||||
|
assertThat(result).isEqualTo("BIKE");
|
||||||
|
}
|
||||||
|
|
||||||
// MULTI INPUT/OUTPUT
|
// MULTI INPUT/OUTPUT
|
||||||
|
|
||||||
|
|
||||||
@@ -919,4 +942,48 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
@Configuration
|
||||||
|
public static class ComplexTypeFunctionConfiguration {
|
||||||
|
@Bean
|
||||||
|
public Function<Event<String, Product>, String> function() {
|
||||||
|
return v -> v.getData().getName().toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Product {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Event<K, V> {
|
||||||
|
|
||||||
|
private K key;
|
||||||
|
|
||||||
|
public K getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(K key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private V data;
|
||||||
|
|
||||||
|
public V getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(V data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ public class SimpleFunctionRegistryTests {
|
|||||||
assertThat(lookedUpFunction).isNull();
|
assertThat(lookedUpFunction).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFunctionComposition() {
|
public void testFunctionComposition() {
|
||||||
FunctionRegistration<UpperCase> upperCaseRegistration = new FunctionRegistration<>(
|
FunctionRegistration<UpperCase> upperCaseRegistration = new FunctionRegistration<>(
|
||||||
@@ -500,5 +502,4 @@ public class SimpleFunctionRegistryTests {
|
|||||||
.map(lst -> lst.stream().map(Person::getName).collect(Collectors.toList()));
|
.map(lst -> lst.stream().map(Person::getName).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user