Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invocation Function<InputStream, String> via FunctionInvoker causes ClassCastException #1018

Closed
antonovdmitriy opened this issue Mar 28, 2023 · 3 comments
Assignees
Milestone

Comments

@antonovdmitriy
Copy link

antonovdmitriy commented Mar 28, 2023

Describe the bug

ClassCastException after invocation Function<InputStream, String> via FunctionInvoker

From documentation:

There are times when you may want to have access to a raw input. In this case all you need is to declare your function signature to accept InputStream. For example, Function<InputStream, ?>. In this case we will not attempt any conversion and will pass the raw input directly to a function.

Function

@Component
public class StreamLambda implements Function<InputStream, String> {
    

    @Override
    public String apply(InputStream inputStream) {
        try {
            return new String(inputStream.readAllBytes()).toUpperCase();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

aws log

aws log
Premain-Class: Log4jPatch
Created-By: 11.0.13 (Amazon.com Inc.)
17:35:41.062 [main] INFO org.springframework.cloud.function.utils.FunctionClassUtils - Searching for start class in manifest: file:/var/task/META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.2.2
Build-Jdk-Spec: 11
Implementation-Title: learning-aws-lambdas-springboot
Implementation-Version: 1.0.1
Main-Class: org.springframework.boot.loader.wrapper.ThinJarWrapper
Start-Class: org.example.LambdaApplication
Spring-Boot-Version: 2.6.14
Spring-Boot-Classes: 
17:35:41.108 [main] INFO org.springframework.cloud.function.utils.FunctionClassUtils - Loaded Start Class: class org.example.LambdaApplication
17:35:41.108 [main] INFO org.springframework.cloud.function.utils.FunctionClassUtils - Main class: class org.example.LambdaApplication
.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
'  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::                        
2023-03-28 17:35:42.477  INFO 8 --- [           main] o.s.c.f.a.aws.CustomRuntimeInitializer   : AWS Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker
2023-03-28 17:35:42.512  INFO 8 --- [           main] lambdainternal.AWSLambda                 : Starting AWSLambda using Java 11.0.18 on 169.254.170.241 with PID 8 (/var/runtime/lib/aws-lambda-java-runtime-0.2.0.jar started by sbx_user1051 in /var/task)
2023-03-28 17:35:42.513  INFO 8 --- [           main] lambdainternal.AWSLambda                 : No active profile set, falling back to 1 default profile: "default"
2023-03-28 17:35:44.313  INFO 8 --- [           main] lambdainternal.AWSLambda                 : Started AWSLambda in 2.941 seconds (JVM running for 3.809)
2023-03-28 17:35:44.397  INFO 8 --- [           main] o.s.c.f.adapter.aws.FunctionInvoker      : Locating function: 'streamLambda'
2023-03-28 17:35:44.414  INFO 8 --- [           main] o.s.c.f.adapter.aws.FunctionInvoker      : Located function: 'streamLambda'
START RequestId: c7a93ebf-34fe-47d7-bef1-a3cba8929ee9 Version: $LATEST
2023-03-28 17:35:44.426  INFO 8 --- [           main] o.s.c.f.adapter.aws.AWSLambdaUtils       : Received: "test"
Invoking function: streamLambda<class java.io.InputStream, class java.lang.String>with input type: class java.io.InputStream
class [B cannot be cast to class java.io.InputStream ([B and java.io.InputStream are in module java.base of loader 'bootstrap'): java.lang.ClassCastException
java.lang.ClassCastException: class [B cannot be cast to class java.io.InputStream ([B and java.io.InputStream are in module java.base of loader 'bootstrap')
	at org.example.lambda.requestresponse.StreamLambda.apply(StreamLambda.java:9)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:931)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:886)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:747)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:590)
	at org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:92)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

END RequestId: c7a93ebf-34fe-47d7-bef1-a3cba8929ee9
REPORT RequestId: c7a93ebf-34fe-47d7-bef1-a3cba8929ee9	Duration: 911.78 ms	Billed Duration: 912 ms	Memory Size: 512 MB	Max Memory Used: 145 MB	Init Duration: 3930.00 ms	

Version

<spring-cloud-function.version>3.2.9</spring-cloud-function.version>

pom.xml

Sample

class StreamLambdaTest {

    @Test
    void handlerStream() throws IOException {

        System.setProperty("MAIN_CLASS", LambdaApplication.class.getName());
        System.setProperty("spring.cloud.function.definition", "streamLambda");
        FunctionInvoker invoker = new FunctionInvoker();

        InputStream targetStream = new ByteArrayInputStream("\"tadam\"".getBytes());
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        invoker.handleRequest(targetStream, output, null);
        String result = new String(output.toByteArray(), StandardCharsets.UTF_8);
        System.out.println(result);
    }
}
log from test
20:21:35.395 [main] INFO org.springframework.cloud.function.utils.FunctionClassUtils - Main class: class org.example.LambdaApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.9)

2023-03-28 20:21:36.319  INFO 58026 --- [           main] com.intellij.rt.junit.JUnitStarter       : Starting JUnitStarter using Java 11.0.18 on antonov-virtual-machine with PID 58026 (started by antonov in /home/antonov/CODE/learning-aws-lambda-springboot)
2023-03-28 20:21:36.323  INFO 58026 --- [           main] com.intellij.rt.junit.JUnitStarter       : No active profile set, falling back to 1 default profile: "default"
2023-03-28 20:21:37.611  INFO 58026 --- [           main] com.intellij.rt.junit.JUnitStarter       : Started JUnitStarter in 2.08 seconds (JVM running for 3.547)
2023-03-28 20:21:37.686  INFO 58026 --- [           main] o.s.c.f.adapter.aws.FunctionInvoker      : Locating function: 'streamLambda'
2023-03-28 20:21:37.700  INFO 58026 --- [           main] o.s.c.f.adapter.aws.FunctionInvoker      : Located function: 'streamLambda'
2023-03-28 20:21:37.702  INFO 58026 --- [           main] o.s.c.f.adapter.aws.AWSLambdaUtils       : Received: "tadam"
Invoking function: streamLambda<class java.io.InputStream, class java.lang.String>with input type: class java.io.InputStream

java.lang.ClassCastException: class [B cannot be cast to class java.io.InputStream ([B and java.io.InputStream are in module java.base of loader 'bootstrap')

	at org.example.lambda.requestresponse.StreamLambda.apply(StreamLambda.java:9)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:931)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:886)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:747)
	at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:590)
	at org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:92)
	at org.example.lambda.requestresponse.StreamLambdaTest.handlerStream(StreamLambdaTest.java:33)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

@olegz
Copy link
Contributor

olegz commented Mar 30, 2023

Indeed it is a bug, fixing it, but . . .
Just curious, why do you care about receiving such low level object? Wouldn't you be converting it to something anyway?

@antonovdmitriy
Copy link
Author

Indeed it is a bug, fixing it, but . . . Just curious, why do you care about receiving such low level object? Wouldn't you be converting it to something anyway?

Oleg, thanks for your reply.

Actually just academic interest.

Aws environment supports work with InputStream and even OutputStream. I can just imagine some streaming tasks, like big image processing or video with tight heap memory limit. Lambda does not good fit for this purpose, but who knows.

@olegz olegz added the AWS label Mar 30, 2023
olegz added a commit that referenced this issue Mar 30, 2023
@olegz olegz closed this as completed in 2a2fb1c Mar 30, 2023
@olegz
Copy link
Contributor

olegz commented Mar 30, 2023

Good point. Anyway, it's fixed and backported as well

olegz added a commit that referenced this issue Apr 18, 2023
olegz added a commit that referenced this issue Apr 18, 2023
olegz added a commit that referenced this issue Apr 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants