신비한 개발사전
.jar에 기본 Manifest 속성이 없습니다 문제의 원인과 해결 방법 본문
간단한 콘솔 기반 자바 애플리케이션을 빌드해서 java -jar로 실행하려고 했을 때 일어난 일이다.
"./build/libs/java-janggi-1.0-SNAPSHOT.jar에 기본 Manifest 속성이 없습니다." 오류 메세지가 뜨면서 애플리케이션이 실행되지 않았다. 이 한 줄 외에 다른 정보는 없었다.
무엇이 문제였나?
우리가 코딩한 자바 애플리케이션은 JVM이 실행해준다. 이때 JVM은 애플리케이션의 entrypoint, 즉 진입점을 알아야 한다. 어느 클래스에 구현된 main() 함수를 실행시켜야 이 애플리케이션이 우리가 설계한 대로 동작할지 JVM은 알 수 없기 때문에, 우리가 명시적으로 알려줘야 한다. 그리고 그 방법은 이정표 역할을 하는 manifest 파일(MANIFEST.MF)에 Main-Class 속성을 추가하는 것이다.
생각해보니 난 그동안 IDE의 인터페이스를 통해서만 애플리케이션을 실행시켰었다. Entrypoint 역할을 하는 main() 함수가 어떤 클래스에 있는지 개발자인 나는 가시적으로 알고 있으니, 편의상 늘 IDE에 의존해 애플리케이션을 실행해왔던 것이다.

기본적으로 새 프로젝트를 시작할 때 manifest 파일에 Main-Class 속성이 자동으로 설정되진 않기 때문에, 개발자가 직접 빌드 파일을 손봐야 한다.
Gradle로 entrypoint 설정하기
Gradle로 빌드할 경우 두가지 방식으로 애플리케이션의 entrypoint를 지정할 수 있다.
1. application 플러그인
build.gradle 파일에 다음과 같이 'application' 플러그인을 추가하고, 속성으로 mainClass를 추가해준다. 이때 mainClass에는 main() 함수를 가진 클래스의 전체 패키지 경로를 전달한다. (해결 방안과 무관한 내용은 생략)
plugins {
id 'java'
id 'application'
}
application {
mainClass = 'janggi.Application'
}
2. manifest 속성
build.gradle 파일에 jar.manifest 속성을 통해 entrypoint를 설정할 수도 있다. 이렇게 설정할 경우 'application' 플러그인이 필요 없다.
jar {
manifest {
attributes(
'Main-Class': 'janggi.Application'
)
}
}
참고로 Kotlin DSL을 사용한다면 문법이 약간 다르다:
tasks {
jar {
manifest {
attributes["Main-Class"] = "janggi.Application"
}
}
}
결과 확인
Entrypoint를 설정하기 전과 후의 manifest 파일을 비교해 봤다. 빌드한 .jar 파일에서 jar xf 명령어로 manifest 파일만 추출해 내용물을 읽을 수 있다.
Main-Class 설정 전:

아무것도 없는 상태에서는 MANIFEST.MF 파일에 버전 정보 한 줄만 들어있는 것을 확인할 수 있다.
Main-Class 설정 후:

Entrypoint를 지정하고 나니 "Main-Class: janggi.Application"이 추가됐다.
추가로 문득 Spring에서는 이렇게 entrypoint를 설정하지 않고도 java -jar을 실행하는 데에 문제가 없었다는 점이 떠올라서, Spring 프레임워크로 빌드한 애플리케이션의 manifest 파일을 확인해 봤다.

Spring은 프레임워크가 Main-Class를 대신 설정해준다. 차이점이라면 콘솔 애플리케이션과 달리 Main-Class에 JarLauncher가 들어가고, @SpringBootApplication 애노테이션이 달려있는 클래스가 Start-Class라는 속성에 들어간다.
참고:
'Java' 카테고리의 다른 글
| JUnit Jupiter와 Platform의 의존성 충돌 (0) | 2025.09.02 |
|---|---|
| 객체지향 프로그래밍의 4가지 특징 (0) | 2024.10.12 |