Automating Java compilation through Batch Script is essential for build workflows that need to run outside of heavyweight build tools like Maven or Gradle. Whether you are building a simple single-file utility, a multi-file project with package structure, or generating JAR archives, the javac compiler and jar tool can be orchestrated directly from a Batch Script for fast, lightweight, and transparent builds.
In this guide, we will explore how to compile Java projects from a Batch Script using javac, manage classpaths, create JAR files, and handle common build scenarios.
Prerequisites
Ensure the Java Development Kit (JDK) is installed and javac is on the system PATH:
@echo off
javac -version 2>nul
if %errorlevel% neq 0 (
echo [ERROR] JDK not found. Install JDK and add to PATH.
echo Download from: https://jdk.java.net/
pause
exit /b 1
)Method 1: Compiling a Single Java File
@echo off
setlocal
set "source=src\HelloWorld.java"
set "output=bin"
if not exist "%source%" (
echo [ERROR] Source file not found: %source%
pause
exit /b 1
)
echo Compiling %source%...
if not exist "%output%" mkdir "%output%"
javac -d "%output%" "%source%"
if %errorlevel%==0 (
echo [SUCCESS] Compiled.
echo Running...
java -cp "%output%" HelloWorld
) else (
echo [ERROR] Compilation failed.
exit /b 1
)
pauseKey javac Options
| Option | Description |
|---|---|
-d dir |
Output directory for compiled .class files |
-cp path |
Classpath for dependencies |
-source ver |
Source compatibility version (e.g., -source 11) |
-target ver |
Target bytecode version |
-Xlint |
Enable all recommended warnings |
-encoding UTF-8 |
Source file encoding |
Method 2: Compiling a Multi-File Project
For projects with multiple source files and package structure:
@echo off
setlocal enabledelayedexpansion
set "src_dir=src"
set "out_dir=bin"
set "lib_dir=lib"
set "sources_file=%temp%\java_sources_%random%.txt"
echo =============================================
echo JAVA BUILD
echo =============================================
echo.
:: Verify source directory exists
if not exist "%src_dir%\" (
echo [ERROR] Source directory not found: %src_dir%
pause
exit /b 1
)
:: Clean output directory
if exist "%out_dir%" rmdir /s /q "%out_dir%"
mkdir "%out_dir%"
:: Collect all .java files
echo [1/2] Finding source files...
dir /s /b "%src_dir%\*.java" > "%sources_file%" 2>nul
set "file_count=0"
for /f %%C in ('type "%sources_file%" ^| find /c /v ""') do set "file_count=%%C"
if %file_count%==0 (
echo [ERROR] No .java files found in %src_dir%.
del "%sources_file%" 2>nul
exit /b 1
)
echo Found %file_count% source files.
:: Build classpath from lib directory
set "classpath="
if exist "%lib_dir%\" (
for %%J in ("%lib_dir%\*.jar") do (
if defined classpath (
set "classpath=!classpath!;%%J"
) else (
set "classpath=%%J"
)
)
)
:: Compile
echo [2/2] Compiling...
if defined classpath (
javac -d "%out_dir%" -cp "!classpath!" -encoding UTF-8 -Xlint @"%sources_file%"
) else (
javac -d "%out_dir%" -encoding UTF-8 -Xlint @"%sources_file%"
)
set "compile_result=!errorlevel!"
del "%sources_file%" 2>nul
if !compile_result!==0 (
echo.
echo [SUCCESS] Compiled %file_count% files to %out_dir%
) else (
echo.
echo [ERROR] Compilation failed.
exit /b 1
)
pauseMethod 3: Build and Create JAR
Compile the project and package it into an executable JAR:
@echo off
setlocal enabledelayedexpansion
set "app_name=MyApp"
set "main_class=com.example.Main"
set "src_dir=src"
set "out_dir=bin"
set "lib_dir=lib"
set "dist_dir=dist"
set "jar_file=%dist_dir%\%app_name%.jar"
set "sources_file=%temp%\java_sources_%random%.txt"
echo =============================================
echo BUILD AND PACKAGE
echo =============================================
echo.
:: Clean
if exist "%out_dir%" rmdir /s /q "%out_dir%"
if exist "%dist_dir%" rmdir /s /q "%dist_dir%"
mkdir "%out_dir%"
mkdir "%dist_dir%"
:: Collect sources
dir /s /b "%src_dir%\*.java" > "%sources_file%" 2>nul
set "file_count=0"
for /f %%C in ('type "%sources_file%" ^| find /c /v ""') do set "file_count=%%C"
if %file_count%==0 (
echo [ERROR] No .java files found in %src_dir%.
del "%sources_file%" 2>nul
exit /b 1
)
:: Build classpath
set "classpath="
if exist "%lib_dir%\" (
for %%J in ("%lib_dir%\*.jar") do (
if defined classpath (set "classpath=!classpath!;%%J") else (set "classpath=%%J")
)
)
:: Compile
echo [1/3] Compiling %file_count% files...
if defined classpath (
javac -d "%out_dir%" -cp "!classpath!" @"%sources_file%"
) else (
javac -d "%out_dir%" @"%sources_file%"
)
del "%sources_file%" 2>nul
if !errorlevel! neq 0 (
echo [FAIL] Compilation failed.
exit /b 1
)
echo Compiled.
:: Create manifest
echo [2/3] Creating manifest...
for /f "tokens=2 delims==" %%T in ('wmic os get LocalDateTime /value') do set "dt=%%T"
set "build_date=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%"
(
echo Manifest-Version: 1.0
echo Main-Class: %main_class%
echo Built-By: %USERNAME%
echo Build-Date: %build_date%
) > "%out_dir%\MANIFEST.MF"
:: Manifest files require a trailing newline
echo.>> "%out_dir%\MANIFEST.MF"
:: Create JAR
echo [3/3] Packaging JAR...
jar cfm "%jar_file%" "%out_dir%\MANIFEST.MF" -C "%out_dir%" .
if !errorlevel!==0 (
for %%F in ("%jar_file%") do set "size=%%~zF"
echo.
echo [SUCCESS] JAR created: %jar_file% (!size! bytes^)
echo Run with: java -jar %jar_file%
) else (
echo [FAIL] JAR creation failed.
exit /b 1
)
pauseMethod 4: Full Build Pipeline with Tests
@echo off
setlocal enabledelayedexpansion
set "src_dir=src\main\java"
set "test_dir=src\test\java"
set "out_dir=build\classes"
set "test_out=build\test-classes"
set "lib_dir=lib"
echo =============================================
echo JAVA BUILD PIPELINE
echo =============================================
echo.
:: Clean
echo [1/4] Cleaning...
if exist "build" rmdir /s /q "build"
mkdir "%out_dir%"
mkdir "%test_out%"
echo Done.
:: Build classpath from lib/*.jar
set "classpath="
if exist "%lib_dir%\" (
for %%J in ("%lib_dir%\*.jar") do (
if defined classpath (set "classpath=!classpath!;%%J") else (set "classpath=%%J")
)
)
:: Compile main sources
echo [2/4] Compiling sources...
if not exist "%src_dir%\" (
echo [FAIL] Source directory not found: %src_dir%
exit /b 1
)
set "main_sources=%temp%\main_sources_%random%.txt"
dir /s /b "%src_dir%\*.java" > "!main_sources!" 2>nul
set "src_count=0"
for /f %%C in ('type "!main_sources!" ^| find /c /v ""') do set "src_count=%%C"
if !src_count!==0 (
echo [FAIL] No .java files found in %src_dir%.
del "!main_sources!" 2>nul
exit /b 1
)
if defined classpath (
javac -d "%out_dir%" -cp "!classpath!" -encoding UTF-8 @"!main_sources!" 2> build\compile_errors.txt
) else (
javac -d "%out_dir%" -encoding UTF-8 @"!main_sources!" 2> build\compile_errors.txt
)
if !errorlevel! neq 0 (
echo [FAIL] Compilation failed:
type build\compile_errors.txt
del "!main_sources!" 2>nul
exit /b 1
)
del "!main_sources!" 2>nul
echo Compiled !src_count! source files.
:: Compile tests
echo [3/4] Compiling tests...
if not exist "%test_dir%\" (
echo No test directory. Skipping.
goto run_tests
)
set "test_sources=%temp%\test_sources_%random%.txt"
dir /s /b "%test_dir%\*.java" > "!test_sources!" 2>nul
set "test_count=0"
for /f %%C in ('type "!test_sources!" ^| find /c /v ""') do set "test_count=%%C"
if !test_count!==0 (
echo No test files found. Skipping.
del "!test_sources!" 2>nul
goto run_tests
)
javac -d "%test_out%" -cp "%out_dir%;!classpath!" -encoding UTF-8 @"!test_sources!"
if !errorlevel! neq 0 (
echo [WARNING] Test compilation failed.
del "!test_sources!" 2>nul
goto run_tests
)
del "!test_sources!" 2>nul
echo Compiled !test_count! test files.
:: Run tests
:run_tests
echo [4/4] Running tests...
if not exist "%test_out%\" (
echo No compiled tests to run.
) else (
java -cp "%test_out%;%out_dir%;!classpath!" org.junit.runner.JUnitCore com.example.AllTests 2>nul
if !errorlevel!==0 (
echo Tests passed.
) else (
echo [WARNING] Tests failed or JUnit not available.
)
)
echo.
echo [BUILD COMPLETE]
pauseMethod 5: Setting JAVA_HOME and Managing JDK Versions
@echo off
setlocal
:: Explicitly set JDK path
set "JAVA_HOME=C:\Program Files\Java\jdk-17"
if not exist "%JAVA_HOME%\bin\javac.exe" (
echo [ERROR] JDK not found at: %JAVA_HOME%
pause
exit /b 1
)
set "PATH=%JAVA_HOME%\bin;%PATH%"
echo Using JDK: %JAVA_HOME%
javac -version
echo.
:: Build
javac -d bin src\*.java
pauseFor projects requiring a specific JDK version:
@echo off
setlocal
set "required_major=17"
:: Check current version
set "current="
for /f "tokens=2" %%V in ('javac -version 2^>^&1') do set "current=%%V"
if not defined current (
echo [ERROR] javac not found.
pause
exit /b 1
)
echo Current javac: %current%
:: Extract the major version number
for /f "tokens=1 delims=." %%M in ("%current%") do set "major=%%M"
if not "%major%"=="%required_major%" (
echo [ERROR] JDK %required_major% required. Found major version: %major%
pause
exit /b 1
)
echo [OK] JDK version matches (major: %major%^).Common Mistakes
The Wrong Way: Not Setting the Output Directory
:: WRONG - Class files are created next to source files
javac src\com\example\Main.java
:: Creates Main.class in src\com\example\, mixing source and outputOutput Concern:
Without -d, compiled .class files are placed alongside the .java source files, making the project messy and hard to package. Always use -d bin (or similar) to separate compiled output from source code.
The Wrong Way: Missing Classpath for Dependencies
:: WRONG - Fails if the project uses external JARs
javac -d bin src\com\example\Main.java
:: error: package org.apache.commons does not existIf the project uses external libraries, you must include them in the classpath with -cp lib\*.jar or by building the classpath string explicitly.
Best Practices
- Separate source and output: Always use
-dto send class files to a dedicated output directory. - Use
@filefor source lists: Avoids command-line length limits with many source files. - Build classpath dynamically: Loop over the
libdirectory to include all JARs. - Set
-encoding UTF-8: Prevents encoding-related compilation errors across different systems. - Enable warnings with
-Xlint: Catches common issues at compile time.
Conclusion
Compiling Java projects from a Batch Script using javac provides a lightweight, transparent build process without the overhead of Maven or Gradle. By collecting source files with dir /s /b, building classpaths from a library directory, and packaging output into JAR files with jar, Batch scripts can handle everything from simple single-file programs to multi-package projects. For larger projects with complex dependency management, consider using Maven or Gradle, but for straightforward builds and educational purposes, javac orchestrated by a Batch script is fast and effective.