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

GCP HTTP Example fails to deploy - ClassNotFound exception - JarLauncher #1085

Closed
ggranum opened this issue Oct 24, 2023 · 16 comments
Closed

Comments

@ggranum
Copy link

ggranum commented Oct 24, 2023

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.

@SND33
Copy link

SND33 commented Dec 12, 2023

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

@ecky-l
Copy link

ecky-l commented Feb 22, 2024

Same here. Also looking for a workaround or a solution.

@cfranzen
Copy link

Looking for a solution for Gradel. There seems to be no solution at the moment.

@Masahito-I
Copy link

Masahito-I commented Mar 23, 2024

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.

@PMG-VascoSaavedra
Copy link

PMG-VascoSaavedra commented Mar 29, 2024

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.

@MawsFr
Copy link

MawsFr commented Apr 23, 2024

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>

@petrosyanar
Copy link

petrosyanar commented May 28, 2024

The same issue here. The Spring Boot 3.3.x is blocked now in our cloud functions

@Mowee
Copy link

Mowee commented Jun 5, 2024

We have the same problem with Gradle. We are currently still using Spring Boot 3.1 which unfortunately lost support last month.

@gfourny-sfeir
Copy link

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...😥

@olegz olegz closed this as completed in abdb1ac Jun 24, 2024
olegz added a commit that referenced this issue Jun 24, 2024
@tdadashov1-clgx
Copy link

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?

@Cathesso
Copy link

Cathesso commented Aug 7, 2024

@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.

@btrajkovski-mms
Copy link

spring-cloud-function 4.1.3 not working for me also. I got same error as the one described here: #1164

@olegz could it be related to the fix you provided ?

@Mowee
Copy link

Mowee commented Aug 13, 2024

@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.

@alayne-xumo
Copy link

I am still getting this today. with spring 3.4.0. I thought it was something I did wrong but I get the same problem when I try to deploy https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-gcp-background unchanged.

@SND33
Copy link

SND33 commented Dec 20, 2024

@alayne-xumo If it's any help, for me the issue is resolved with Spring Cloud Function Adapter GCP 4.1.4, Spring Cloud Release Train 2023.0.4 and Spring Boot 3.3.6. Haven't tested with Spring Boot 3.4.0 yet though.

@alayne-xumo
Copy link

I got it to work with the 3.1.10 version but still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests