You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@SpringBootApplication
public class CloudFunctionMain {
private static final Logger log = LoggerFactory.getLogger(CloudFunctionMain.class);
public static void main(String[] args) {
SpringApplication.run(CloudFunctionMain.class, args);
}
@Bean
public Function<MultiValueMap<String, Object>, ResponseEntity<Object>> function() {
return this::handleNotify;
}
private ResponseEntity<Object> handleNotify(final MultiValueMap<String, Object> request) {
for (final String key : request.keySet()) {
log.info("Key: " + key + " Value: " + request.getFirst(key));
}
return new ResponseEntity<>(null, new HttpHeaders(), HttpStatus.OK);
}
}
Step 5: Create Unit test for startup
@SpringBootTest(classes = CloudFunctionMain.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class CloudFunctionMainTest {
@Autowired
private TestRestTemplate restTemplate;
private final URI functionUri = URI.create("/function");
@Test
void testStartUp() throws URISyntaxException {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
// Adding values
map.add("key1", "value1");
map.add("key2", "value2");
final ResponseEntity<Object> result = restTemplate.exchange(RequestEntity.post(functionUri).body(map),
Object.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
Step 6: Execute unit test:
»» mvn clean test
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running CloudFunctionMainTest
:: Spring Boot :: (v3.2.3)
2024-03-20T21:13:03.478Z INFO --- [ main] c.p.c.email.tests.CloudFunctionMainTest : Starting CloudFunctionMainTest using Java 22 with PID
2024-03-20T21:13:05.106Z INFO --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 53070 (http) with context path ''
2024-03-20T21:13:05.106Z INFO --- [ main] c.p.c.email.tests.CloudFunctionMainTest : Started CloudFunctionMainTest in 2.129 seconds (process running for 3.465)
2024-03-20T21:13:05.891Z INFO --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-03-20T21:13:05.891Z INFO --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
2024-03-20T21:13:05.982Z INFO --- [o-auto-1-exec-1] c.p.cloud.email.CloudFunctionMain : Key: key1 Value: value1
2024-03-20T21:13:05.982Z INFO --- [o-auto-1-exec-1] c.p.cloud.email.CloudFunctionMain : Key: key2 Value: value2
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.858 s -- in CloudFunctionMainTest
Step 7: Run the function locally
»» mvn clean function:run
[INFO] Calling Invoker with [--classpath,
21:24:26.419 [main] INFO org.springframework.cloud.function.adapter.gcp.FunctionInvoker -- Initializing: class CloudFunctionMain
======> SOURCE: class CloudFunctionMain
2024-03-20T21:24:26.781Z INFO 32664 --- [ main] c.g.c.functions.invoker.runner.Invoker : Starting Invoker using Java 22 with PID [INFO] jetty-9.4.51.v20230217; built: 2023-02-17T08:19:37.309Z; git: b45c405e4544384de066f814ed42ae3dceacdd49; jvm 22+36-2370
[INFO] Started o.e.j.s.ServletContextHandler@2842ef02{/,null,AVAILABLE}
[INFO] Started ServerConnector@6b2aafbc{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
[INFO] Started @4452ms
2024-03-20T21:24:27.577Z INFO 32664 --- [ main] c.g.c.functions.invoker.runner.Invoker : Serving function...
2024-03-20T21:24:27.577Z INFO 32664 --- [ main] c.g.c.functions.invoker.runner.Invoker : Function: org.springframework.cloud.function.adapter.gcp.GcfJarLauncher
2024-03-20T21:24:27.577Z INFO 32664 --- [ main] c.g.c.functions.invoker.runner.Invoker : URL: http://localhost:8080/
Step 8: Use CURL to send a x-www-form-urlencoded Request:
curl -i -X POST http://localhost:8080/ -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1¶m2=value2"
Which generates the following error:
2024-03-20T21:28:59.107Z ERROR 32664 --- [qtp343722304-76] com.google.cloud.functions.invoker : Failed to execute org.springframework.cloud.function.adapter.gcp.GcfJarLauncher
java.lang.ClassCastException: class org.eclipse.jetty.server.Request$1 cannot be cast to class org.springframework.util.MultiValueMap (org.eclipse.jetty.server.Request$1 is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @374c40ba; org.springframework.util.MultiValueMap is in unnamed module of loader com.google.cloud.functions.invoker.runner.Invoker$FunctionClassLoader @4f2ac7e0)
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunctionAndEnrichResultIfNecessary(SimpleFunctionRegistry.java:958) ~[spring-cloud-function-context-4.1.1-SNAPSHOT.jar:4.1.1-SNAPSHOT]
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeFunction(SimpleFunctionRegistry.java:904) ~[spring-cloud-function-context-4.1.1-SNAPSHOT.jar:4.1.1-SNAPSHOT]
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.doApply(SimpleFunctionRegistry.java:740) ~[spring-cloud-function-context-4.1.1-SNAPSHOT.jar:4.1.1-SNAPSHOT]
at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.apply(SimpleFunctionRegistry.java:580) ~[spring-cloud-function-context-4.1.1-SNAPSHOT.jar:4.1.1-SNAPSHOT]
at org.springframework.cloud.function.adapter.gcp.FunctionInvoker.service(FunctionInvoker.java:120) ~[spring-cloud-function-adapter-gcp-4.1.1-SNAPSHOT.jar:4.1.1-SNAPSHOT]
at org.springframework.cloud.function.adapter.gcp.GcfJarLauncher.service(GcfJarLauncher.java:53) ~[spring-cloud-function-adapter-gcp-4.1.1-SNAPSHOT.jar:4.1.1-SNAPSHOT]
at com.google.cloud.functions.invoker.HttpFunctionExecutor.service(HttpFunctionExecutor.java:68) ~[na:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) ~[java-function-invoker-1.3.0.jar:na]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) ~[na:na]
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:554) ~[na:na]
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) ~[na:na]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) ~[na:na]
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) ~[na:na]
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505) ~[na:na]
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) ~[na:na]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) ~[na:na]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[na:na]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[na:na]
at com.google.cloud.functions.invoker.runner.Invoker$NotFoundHandler.handle(Invoker.java:474) ~[na:na]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[na:na]
at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[na:na]
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) ~[na:na]
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) ~[na:na]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) ~[na:na]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) ~[na:na]
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[na:na]
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) ~[na:na]
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) ~[na:na]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) ~[na:na]
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1570) ~[na:na]
Question: It seems that the error is due to the Tests using Tomcat, and when the function runs, it uses Jetty via spring-cloud-function-adapter-gcp.
Why does this happen, and what can i do to overcome this error?
I was able to sort this out, with the help of a friend.
Basically, i would have to change the signature to receive an Object, and then cast to a BufferedReader.
Afterwards, i would have to read from it line by line, parse the lines and create a Key/Value Map.
I tested this and it worked.
@SpringBootApplication
public class CloudFunctionMain {
private static final Logger log = LoggerFactory.getLogger(CloudFunctionMain.class);
public static void main(String[] args) {
SpringApplication.run(CloudFunctionMain.class, args);
}
@Bean
public Function<Object, ResponseEntity<Object>> function() {
return this::handleNotify;
}
private ResponseEntity<Object> handleNotify(final Object values) {
BufferedReader request = ((BufferedReader) values);
//Read BufferedReader, parse the lines and add values to a Map.
return new ResponseEntity<>(null, new HttpHeaders(), HttpStatus.OK);
}
}
I actually believe the error was related to some of the changes we have made in ObjectMapper provided by the framework.
In any event, the issue has been resolved (albeit indirectly) and I was able to successfully execute your code.
So, i'll close it but feel free to file a new issue if you stil see a problem
I have a simple Spring cloud function, which was developed according to the guidelines provided by Spring Cloud documentation.
Step 1: Add the spring-cloud-function-adapter-gcp dependency:
Step 2: Add the spring-boot-maven-plugin which will build the JAR of the function to deploy
Step 3: Add the Maven plugin provided as part of the Google Functions Framework for Java. This allows to test locally via mvn function:run.
Step 4: The Spring Cloud Function Code
Step 5: Create Unit test for startup
Step 6: Execute unit test:
Step 7: Run the function locally
Step 8: Use CURL to send a x-www-form-urlencoded Request:
curl -i -X POST http://localhost:8080/ -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1¶m2=value2"
Which generates the following error:
Question: It seems that the error is due to the Tests using Tomcat, and when the function runs, it uses Jetty via spring-cloud-function-adapter-gcp.
Why does this happen, and what can i do to overcome this error?
The project can be downloaded here:
cloud-function.zip
The text was updated successfully, but these errors were encountered: