spring-bootjdbcbuild.gradleexecutable-jar

(Springboot Gradle with Log4j2, Executable Jar) Could not find or load main class


I encountered the following error when I execute my JAR with

java -jar .\QuartzScheduler-0.0.1-SNAPSHOT.jar
Error: Could not find or load main class com.quartz.QuartzSchedulerApplication
Caused by: java.lang.ClassNotFoundException: com.quartz.QuartzSchedulerApplication

This is a snippet of my build.gradle, please help to shed some light on this.

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.1'
    id 'io.spring.dependency-management' version '1.1.5'
}

group = 'com.quartz'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-quartz'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc:2.4.1'
    implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
    implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
    implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
    implementation files('C:\\Program Files\\Microsoft JDBC DRIVER 12.6 for SQL Server\\sqljdbc_12.6\\enu\\jars\\mssql-jdbc-12.6.3.jre11.jar')
    runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.withType(Jar) {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    manifest {
        attributes["Main-Class"] = "com.quartz.QuartzSchedulerApplication"
    }
}

jar {
    enabled = true
    archiveClassifier = ''

    manifest {
        attributes 'Main-Class' : "com.quartz.QuartzSchedulerApplication"
    }

    from {
        configurations.runtimeClasspath.collect {it.isDirectory() ? it : zipTree(it)}
    }
}

tasks.named('test') {
    useJUnitPlatform()
}

QuartzSchedulerApplication.class

package com.quartz;

import com.quartz.info.TriggerInfo;
import com.quartz.jobs.HelloWorldJob;
import com.quartz.services.SchedulerService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class QuartzSchedulerApplication {

    private static final Logger LOG = LogManager.getLogger(QuartzSchedulerApplication.class);

    private final SchedulerService scheduler;

    @Autowired
    public QuartzSchedulerApplication(SchedulerService scheduler) {
        this.scheduler = scheduler;
    }

    public static void main(String[] args) {
        SpringApplication.run(QuartzSchedulerApplication.class, args).getBean(QuartzSchedulerApplication.class).scheduleJobs();
    }

    public void scheduleJobs() {
        final TriggerInfo info = new TriggerInfo();

        info.setCronExp("5 0/1 * * * ?"); // Run every min, at 5th second
        info.setCallbackData("HelloWorldJob");
        scheduler.schedule(HelloWorldJob.class, info);
        LOG.debug("test");
    }
}

I started off building my Quartz project with Log4j and it was successful. Also, I verified that the JAR file contains my main class and manifest file also exists. When I run the application using bootJar, it was also successful.

I also tried executing the JAR file using:

java -cp .\QuartzScheduler-0.0.1-SNAPSHOT.jar com.quartz.QuartzSchedulerApplication

I'm not sure if it is due to the implementation of JDBC.

Apologies, I did not add the requirement of Log4j2 in my question. Although I am able to execute my jar file by removing the jar task and jar task configuration, my Log4j2 logging does not work anymore. I know this because I isolated my application, same as above, just without JDBC and the logging works fine. Any advice?


Solution

  • The problem is your build file. You are working around the work that the Gradle Spring Boot plugin is doing. Next to that you are mixing modules from different Spring Boot versions never do that either.

    The solution is thus quite simple, simplify/cleanup your build.gradle.

    1. Remove the version from the spring-boot-starter-jdbc
    2. Remove the jar task and jar task configuration.
    3. Remove the duplicate mssql-jdbc dependency (remove the file one)
    plugins {
        id 'java'
        id 'org.springframework.boot' version '3.3.1'
        id 'io.spring.dependency-management' version '1.1.5'
    }
    
    group = 'com.quartz'
    version = '0.0.1-SNAPSHOT'
    
    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(17)
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-quartz'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter-jdbc'
        implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
        implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
        implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
        runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    }
    
    tasks.named('test') {
        useJUnitPlatform()
    }
    

    Now just build your jar as you normally would with ./gradlew build and Spring Boot will automatically create a jar for you that you can run with java -jar QuartzScheduler-0.0.1-SNAPSHOT.jar.