Closed ggranum closed 4 months ago
We're suffering from the same issue. After upgrading Spring Boot to 3.2.0, we started getting this error on startup when deployed on GCP. Upon inspecting the JAR built by the Spring Boot Maven plugin, we can see that indeed the JarLauncher class it not in that place. This causes the error because GcfJarLauncher
extends JarLauncher
.
The Spring Boot 3.2.0 release notes explain that the Spring Boot loader tools have moved to the launch
package, which explains the error. They also provide a workaround to use the classic loader tools by adding following configuration to the Spring Boot Maven plugin:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<loaderImplementation>CLASSIC</loaderImplementation>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
When doing that, the classic loader tools are packaged by the plugin, which should in theory resolve the issue. However, we found out that's in fact the spring-cloud-function-adapter-gcp
dependency, which must be added as a dependency for the plugin, that overwrites this behaviour and ends up not including the classic loader tools (we confirmed that without the adapter, and with the above change, the built JAR does include the classic loader tools).
Is anyone aware of a workaround? If not, we're forced to downgrade Spring Boot, as well as Spring Cloud.
UPDATE: downgrading to Spring Boot 3.1.6 resolved the issue as expected
Same here. Also looking for a workaround or a solution.
Looking for a solution for Gradel. There seems to be no solution at the moment.
I'm also facing this issue. Is there any solution?
P.S. for now, I decided to downgrade the SpringBoot version from 3.2.4 to 3.1.10. The deployment was successful after that. If you'd like to implement your function ASAP, please consider to downgrade it.
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);
}
}
In the end, i opted to use Quarkus.
Here is a working pom.xml based on what @Masahito-I said. It uses GCP spring cloud function + Webflux + gcp secret manager.
I think this is linked to the fact that JarLauncher has been moved but the current version of spring-cloud-function seems to point to the old JarLauncher folder (Source).
Hope it will be fixed soon ^^
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.examples</groupId>
<artifactId>example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>example</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.10</version> <!-- DO NOT UPGRADE see : https://github.com/spring-cloud/spring-cloud-function/issues/1085 -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>21</java.version>
<spring-cloud-function.version>4.1.1</spring-cloud-function.version>
<mockito-core.version>5.11.0</mockito-core.version>
<logstash-logback-encoder.version>7.4</logstash-logback-encoder.version>
<google-cloud-storage.version>2.36.1</google-cloud-storage.version>
<java-function-invoker.version>1.3.1</java-function-invoker.version>
<spring-cloud-gcp-starter-secretmanager.version>5.1.2</spring-cloud-gcp-starter-secretmanager.version>
<spring-cloud-gcp-dependencies.version>4.8.4</spring-cloud-gcp-dependencies.version>
<!-- JUnit Properties -->
<junit-bom.version>5.10.2</junit-bom.version>
<!-- JaCoCo Properties -->
<jacoco-maven-plugin.version>0.8.12</jacoco-maven-plugin.version>
<maven-failsafe-plugin.version>3.2.5</maven-failsafe-plugin.version>
<junit-jupiter-engine.version>5.10.2</junit-jupiter-engine.version>
<jacoco-maven-plugin.version>0.8.12</jacoco-maven-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-function-webflux</artifactId>
<version>${spring-cloud-function.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-adapter-gcp</artifactId>
<version>${spring-cloud-function.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- DO NOT DELETE THIS https://stackoverflow.com/a/78164824 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</dependency>
<!-- logs -->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<!-- To use gcp bucket -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-storage</artifactId>
<version>${google-cloud-storage.version}</version>
</dependency>
<!-- Add Secret Manager Starter -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-secretmanager</artifactId>
<version>${spring-cloud-gcp-starter-secretmanager.version}</version>
</dependency>
<!-- tools -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.cloud.functions.invoker</groupId>
<artifactId>java-function-invoker</artifactId>
<version>${java-function-invoker.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito-core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<outputDirectory>target/deploy</outputDirectory>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-adapter-gcp</artifactId>
<version>${spring-cloud-function.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>com.google.cloud.functions</groupId>
<artifactId>function-maven-plugin</artifactId>
<version>0.9.1</version>
<configuration>
<functionTarget>org.springframework.cloud.function.adapter.gcp.GcfJarLauncher</functionTarget>
<port>8080</port>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter-engine.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
</execution>
</executions>
<configuration>
<!-- failsafe coverage per test reports can be shown in Sonar
only if they are put in the same dir as surefire reports -->
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>prepare-agent-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
</configuration>
</execution>
<execution>
<id>report-it</id>
<goals>
<goal>report-integration</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/jacoco-it.exec</dataFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- DO NOT CHANGE : https://stackoverflow.com/a/78207517 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit-bom.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-dependencies</artifactId>
<version>${spring-cloud-gcp-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>macos-aarch64</id>
<activation>
<os>
<family>mac</family>
<arch>aarch64</arch>
</os>
</activation>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns-native-macos</artifactId>
<version>${netty.version}</version>
<classifier>osx-aarch_64</classifier>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
The same issue here. The Spring Boot 3.3.x is blocked now in our cloud functions
We have the same problem with Gradle. We are currently still using Spring Boot 3.1 which unfortunately lost support last month.
This is becoming problematic, no one is taking care of these issues that have been open for several months... 🥺
The Spring Boot 3.1 version is no longer supported and there is no solution from Spring other than forking the adapter project...😥
I've updated the spring-cloud-function to 4.1.3, but still got the same error. Are there any additional steps required to fix the error?
@tdadashov1-clgx have you found a solution for this problem yet? We also can't get the cloud functions to work properly in 4.1.3. The functions can be called and the logs say that they did execute, but actually nothing happens, so they are not being launched for real.
spring-cloud-function 4.1.3
not working for me also. I got same error as the one described here: https://github.com/spring-cloud/spring-cloud-function/issues/1164
@olegz could it be related to the fix you provided ?
@olegz I can still reproduce the issue. As a test setup I've used the function-sample-gcp-background
(https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-gcp-background)
I just followed the build and deploy process as described within the README.
While the application works fine locally I still get the same exception once I'm trying to deploy the function using the described gcloud command.
Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/loader/JarLauncher
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524)
at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427)
at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:420)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:592)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
at com.google.cloud.functions.invoker.runner.Invoker.loadFunctionClass(Invoker.java:357)
at com.google.cloud.functions.invoker.runner.Invoker.startServer(Invoker.java:294)
at com.google.cloud.functions.invoker.runner.Invoker.startServer(Invoker.java:244)
at com.google.cloud.functions.invoker.runner.Invoker.main(Invoker.java:127)
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:592)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
... 14 more. Please visit https://cloud.google.com/functions/docs/troubleshooting for in-depth troubleshooting documentation.
Describe the bug Building and deploying the Main branch version of spring-cloud-function-samples/function-sample-gcp-http fails with 'java.lang.ClassNotFoundException: org.springframework.boot.loader.JarLauncher'
The 4.0.x branch still packages and deploys as expected.
Steps Clone project && cd project ./mvnw install cd spring-cloud-function-samples/function-sample-gcp-http mvn package gcloud functions deploy function-sample-gcp-http \ --entry-point org.springframework.cloud.function.adapter.gcp.GcfJarLauncher \ --runtime java17 \ --trigger-http \ --source target/deploy \ --memory 512MB
deploy fails with above exception.
What works cd projectRoot git checkout 4.0.x mvn clean cd spring-cloud-function-samples/function-sample-gcp-http mvn package gcloud functions deploy function-sample-gcp-http \ --entry-point org.springframework.cloud.function.adapter.gcp.GcfJarLauncher \ --runtime java17 \ --trigger-http \ --source target/deploy \ --memory 512MB
Further Info I tried JDK20, 21 and 17. All Temurin.