From 1f188e8e366af6a7b39b4828b76f2fb320be37d7 Mon Sep 17 00:00:00 2001 From: Rob Cash Date: Wed, 4 Oct 2023 19:20:19 -0400 Subject: [PATCH] GH-1077 Update AWSLambdaUtils.java with null check Resolves #1077 by checking for a null package, which can happen when the inputType is a Message that encloses a primitive generic type Update AWSTypesMessageConverter.java Added additional fixes for #1077 in AWTypesMessageConverter Update FunctionInvokerTests.java Added unit tests to verify fix for #1077 Checkstyle fix Resolves #1078 --- .../function/adapter/aws/AWSLambdaUtils.java | 4 ++- .../adapter/aws/AWSTypesMessageConverter.java | 6 +++-- .../adapter/aws/FunctionInvokerTests.java | 26 +++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSLambdaUtils.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSLambdaUtils.java index 0923e234b..30c9bad3f 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSLambdaUtils.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSLambdaUtils.java @@ -74,7 +74,9 @@ public final class AWSLambdaUtils { if (FunctionTypeUtils.isMessage(inputType) || FunctionTypeUtils.isPublisher(inputType)) { inputType = FunctionTypeUtils.getImmediateGenericType(inputType, 0); } - return FunctionTypeUtils.getRawType(inputType).getPackage().getName().startsWith("com.amazonaws.services.lambda.runtime.events"); + return FunctionTypeUtils.getRawType(inputType).getPackage() != null && + FunctionTypeUtils.getRawType(inputType).getPackage().getName().startsWith( + "com.amazonaws.services.lambda.runtime.events"); } @SuppressWarnings("rawtypes") diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSTypesMessageConverter.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSTypesMessageConverter.java index b94a48181..f90f80dee 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSTypesMessageConverter.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSTypesMessageConverter.java @@ -63,7 +63,8 @@ class AWSTypesMessageConverter extends JsonMessageConverter { return ((boolean) message.getHeaders().get(AWSLambdaUtils.AWS_EVENT)); } //TODO Do we really need the ^^ above? It seems like the line below dows the trick - else if (targetClass.getPackage().getName().startsWith("com.amazonaws.services.lambda.runtime.events")) { + else if (targetClass.getPackage() != null && + targetClass.getPackage().getName().startsWith("com.amazonaws.services.lambda.runtime.events")) { return true; } return false; @@ -75,7 +76,8 @@ class AWSTypesMessageConverter extends JsonMessageConverter { return message.getPayload(); } - if (targetClass.getPackage().getName().startsWith("com.amazonaws.services.lambda.runtime.events")) { + if (targetClass.getPackage() != null && + targetClass.getPackage().getName().startsWith("com.amazonaws.services.lambda.runtime.events")) { PojoSerializer serializer = LambdaEventSerializers.serializerFor(targetClass, Thread.currentThread().getContextClassLoader()); Object event = serializer.fromJson(new ByteArrayInputStream((byte[]) message.getPayload())); return event; diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/FunctionInvokerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/FunctionInvokerTests.java index 83959248e..f03c2a303 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/FunctionInvokerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/FunctionInvokerTests.java @@ -1407,6 +1407,21 @@ public class FunctionInvokerTests { assertThat(result.get("body")).isEqualTo("\"olleh\""); } + @Test + public void testPrimitiveMessage() throws Exception { + System.setProperty("MAIN_CLASS", PrimitiveConfiguration.class.getName()); + System.setProperty("spring.cloud.function.definition", "returnByteArrayAsMessage"); + FunctionInvoker invoker = new FunctionInvoker(); + + String testString = "{ \"message\": \"Hello, world!\" }"; + InputStream targetStream = new ByteArrayInputStream(testString.getBytes()); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + invoker.handleRequest(targetStream, output, null); + + String result = output.toString(); + assertThat(result).isEqualTo(testString); + } + @EnableAutoConfiguration @Configuration public static class AuthorizerConfiguration { @@ -1811,6 +1826,17 @@ public class FunctionInvokerTests { } } + @EnableAutoConfiguration + @Configuration + public static class PrimitiveConfiguration { + @Bean + public Function, byte[]> returnByteArrayAsMessage() { + return v -> { + return v.getPayload(); + }; + } + } + public static class Person { private String name;