Tools for generating executable JAR/WAR files with embedded containers for Spring Boot applications
—
Automatic discovery of classes with public static main methods using breadth-first search algorithms. The main class finder can analyze both directory structures and JAR files, with support for annotation-based filtering and validation.
Find main classes by scanning directory structures containing compiled Java classes.
public abstract class MainClassFinder {
/**
* Find the first main class in the given directory.
* Uses breadth-first search to locate classes with public static main methods.
*
* @param rootDirectory the root directory to search
* @return the fully qualified name of the first main class found, or null if none found
* @throws IOException if directory scanning fails
*/
public static String findMainClass(File rootDirectory) throws IOException;
/**
* Find a single main class in the given directory.
* Throws an exception if multiple main classes are found.
*
* @param rootDirectory the root directory to search
* @return the fully qualified name of the single main class
* @throws IOException if directory scanning fails
* @throws IllegalStateException if multiple main classes are found
*/
public static String findSingleMainClass(File rootDirectory) throws IOException;
/**
* Find a single main class with a specific annotation.
* Filters main classes to only include those with the specified annotation.
*
* @param rootDirectory the root directory to search
* @param annotationName the fully qualified annotation name to filter by
* @return the fully qualified name of the annotated main class
* @throws IOException if directory scanning fails
* @throws IllegalStateException if multiple annotated main classes are found
*/
public static String findSingleMainClass(File rootDirectory, String annotationName) throws IOException;
}Find main classes by analyzing compiled classes within JAR files.
public abstract class MainClassFinder {
/**
* Find the first main class in the given JAR file.
* Searches within the specified classes location inside the JAR.
*
* @param jarFile the JAR file to search
* @param classesLocation the location within the JAR where classes are stored (e.g., "BOOT-INF/classes/")
* @return the fully qualified name of the first main class found, or null if none found
* @throws IOException if JAR reading fails
*/
public static String findMainClass(JarFile jarFile, String classesLocation) throws IOException;
/**
* Find a single main class in the given JAR file.
* Throws an exception if multiple main classes are found.
*
* @param jarFile the JAR file to search
* @param classesLocation the location within the JAR where classes are stored
* @return the fully qualified name of the single main class
* @throws IOException if JAR reading fails
* @throws IllegalStateException if multiple main classes are found
*/
public static String findSingleMainClass(JarFile jarFile, String classesLocation) throws IOException;
/**
* Find a single main class with a specific annotation in a JAR file.
* Filters main classes to only include those with the specified annotation.
*
* @param jarFile the JAR file to search
* @param classesLocation the location within the JAR where classes are stored
* @param annotationName the fully qualified annotation name to filter by
* @return the fully qualified name of the annotated main class
* @throws IOException if JAR reading fails
* @throws IllegalStateException if multiple annotated main classes are found
*/
public static String findSingleMainClass(JarFile jarFile, String classesLocation, String annotationName) throws IOException;
}import org.springframework.boot.loader.tools.MainClassFinder;
import java.io.File;
import java.io.IOException;
// Find any main class in the compiled classes directory
File classesDir = new File("target/classes");
try {
String mainClass = MainClassFinder.findMainClass(classesDir);
if (mainClass != null) {
System.out.println("Found main class: " + mainClass);
} else {
System.out.println("No main class found");
}
} catch (IOException e) {
System.err.println("Error scanning directory: " + e.getMessage());
}import org.springframework.boot.loader.tools.MainClassFinder;
import java.io.File;
// Ensure only one main class exists
File classesDir = new File("target/classes");
try {
String mainClass = MainClassFinder.findSingleMainClass(classesDir);
System.out.println("Application main class: " + mainClass);
} catch (IllegalStateException e) {
System.err.println("Multiple main classes found: " + e.getMessage());
} catch (IOException e) {
System.err.println("Error scanning directory: " + e.getMessage());
}import org.springframework.boot.loader.tools.MainClassFinder;
import java.io.File;
// Find main class with Spring Boot annotation
File classesDir = new File("target/classes");
try {
String mainClass = MainClassFinder.findSingleMainClass(
classesDir,
"org.springframework.boot.autoconfigure.SpringBootApplication"
);
System.out.println("Spring Boot main class: " + mainClass);
} catch (IllegalStateException e) {
System.err.println("Multiple Spring Boot applications found: " + e.getMessage());
} catch (IOException e) {
System.err.println("Error scanning directory: " + e.getMessage());
}import org.springframework.boot.loader.tools.MainClassFinder;
import java.io.File;
import java.util.jar.JarFile;
// Analyze an existing JAR file
File jarFile = new File("myapp.jar");
try (JarFile jar = new JarFile(jarFile)) {
// Standard location for classes in a Spring Boot JAR
String classesLocation = "BOOT-INF/classes/";
String mainClass = MainClassFinder.findMainClass(jar, classesLocation);
if (mainClass != null) {
System.out.println("JAR main class: " + mainClass);
}
// For regular JAR files, classes are typically at the root
String regularLocation = "";
String regularMainClass = MainClassFinder.findMainClass(jar, regularLocation);
if (regularMainClass != null) {
System.out.println("Regular JAR main class: " + regularMainClass);
}
} catch (IOException e) {
System.err.println("Error reading JAR file: " + e.getMessage());
}import org.springframework.boot.loader.tools.*;
import java.io.File;
// Automatic main class detection during repackaging
File sourceJar = new File("myapp.jar");
Repackager repackager = new Repackager(sourceJar);
// Add timeout warning for main class detection
repackager.addMainClassTimeoutWarningListener((duration, mainClass) -> {
if (duration.toSeconds() > 30) {
System.out.println("Main class detection is taking longer than expected...");
}
if (mainClass == null) {
System.err.println("Warning: No main class found after " + duration.toMillis() + "ms");
} else {
System.out.println("Detected main class: " + mainClass + " (took " + duration.toMillis() + "ms)");
}
});
// Let repackager automatically detect main class
repackager.repackage(Libraries.NONE);import org.springframework.boot.loader.tools.*;
import java.io.File;
// Override automatic detection with explicit main class
File sourceJar = new File("myapp.jar");
Repackager repackager = new Repackager(sourceJar);
// Manually specify main class to skip detection
repackager.setMainClass("com.example.MyApplication");
// Repackage with specified main class
repackager.repackage(Libraries.NONE);The main class finder uses a breadth-first search algorithm that:
public static void main(String[] args) methodsThe breadth-first approach ensures that classes in the root package are found before classes in nested packages, which typically aligns with application structure conventions.
Install with Tessl CLI
npx tessl i tessl/maven-org-springframework-boot--spring-boot-loader-tools