Maven에서 Gradle로
Gradle이 Maven보다 좋았던 점
프로젝트 구성과 빌드는 근본적으로 “구성”이라는 정적인 요소와 “빌드”라는 동적인 요소의 집합이다. 이를 Maven은 정적인 데이터를 저장하는 XML로 만들어서 동적인 행위 정의를 매우 어렵게 만들었다.
Maven의 가장 큰 문제이며 이로인한 복잡한 프로젝트에서 설정이 거의 불가능한 상황이 자주 발생한다.
Gradle은 DSL로 설정 정보를 구성하고, 그 자체가 Groovy 스크립트 언어이므로 동적인 작업은 그냥 Groovy 코드로 즉석에서 작성하면 된다.
Maven은 상속 구조를 사용해 멀티 모듈을 구현한다. Gradle은 구성 주입(Configuration Injection)을 사용한다.
Maven에서 특정 설정을 몇몇 모듈에서만 공통으로 사용하려면 불필요하게 부모 프로젝트를 생성하여 설정하고 그것을 자식들이 상속하게 해야 한다. 게다가 다른 모든게 같더라도 약간이라도 설정이 다른 프로젝트가 하나라도 있다면 그 프로젝트는 상속을 할 수 없고, 거의 모든 설정을 중복해서 해당 프로젝트에 넣어줘야 한다.
Gradle은 공통 설정을 조건에 따라 특정 프로젝트에만 주입 가능하다. 불필요한 상속 전용 프로젝트는 필요없다.
프로젝트에 상대적인 파일 경로로 작업을 할 때 Gradle은 rootProject.file()
로 쉽게 구성 가능하다.(특히 Eclipse linkedResources 적용할 때)
Maven은 자신만의 플러그인을 만들기가 힘들다. 하지만 Gradle은 build.gradle
혹은 buildSrc
를 통해 자신만의 플러그인과 태스크를 매우 쉽게 정의할 수 있다.
Gradle은 Ant 태스크를 바로 가져다가 사용할 수 있기 때문에 수많은 Java Ant 태스크들을 이미 내장하고 있는 것이나 다름 없다.
Gradle은 Task간의 작동 순서 정의가 매우 쉽다. Maven은 정적인 특성 때문에 특정 태스크를 반복 수행하거나 하는 등의 작업이 힘들고, 다른 Phase에 태스크를 끼워넣는 것도 직관적이지 못하다.
Gradle은 Maven플러그인으로는 있으나 Gradle 혹은 Ant 플러그인이 없을 경우 그냥 외부 프로그램을 실행해버리거나 Groovy로 Maven 플러그인의 Java 코드를 호출해서 실행하면 된다.
현재(1.2) Gradle의 문제점
의존성에서 provided
를 기본으로 제공하지 않고 있다. 하지만 방법은 있다. configurations
를 직접 구성해야한다.
Maven보다 프로젝트 컴파일/ 빌드 속도가 느리다.
이행적 의존성 충돌이 발생할 때 모르는 사이에 지정한 것보다 높은 버전의 라이브러리를 받아오는 현상이 생긴다. 이것은 문제라기 보다는 Gradle의 의도인데 이것을 이해하지 못하면 의도치 않은 일이 생길 수 있다.
Gradle Dependencies 에서 의존성 충돌에 관해 잘 참고할 것.
IDE 지원이 다소 미흡함. 그러나 Eclipse는 대부분 문제가 해결 가능하다.
pom.xml에서 의존성 문자열 모두 뽑아내기
dependencies.groovy
def pom = new XmlParser().parse(new File(args[0]))
def dependencies = pom.dependencies.dependency.each {
// GString을 사용할 수도 있어서 일부러 쌍따옴표로 했음
println "\"${it.groupId.text()}:${it.artifactId.text()}:${it.version.text()}\","
}
실행한 뒤에 맨 끝에 쉼표는 잘 조정해서 쓸 것
> groovy dependencies pom.xml
"com.google.guava:guava:10.0.1",
"spy:spymemcached:2.7",
"org.codehaus.jettison:jettison:1.3",
.....
provided
이행적 의존성으로 인한 라이브러리 버전 변경 대비
현재 프로젝트에서 spring-data-jpa를 사용하는데, 이 모듈이 Spring Core/Beans 등에 대해 가변 버전으로 의존하고 있다. 이에 따라 현재 프로젝트의 공식 Spring 버전은 3.1인데, 이행성과 가변 버전 변경에 따라 Core/Beans 등이 3.2.0.M2로 지정되는 현상이 발생하였다.
Gradle Dependencies를 참고하여 의존성 버전 관리 전략에 failOnVersionConflict()
을 넣어 주고 항상 명시하는 것이 좋아보인다.
Profile 흉내내기
Apache CXF
Apache CXF로 SOAP Client Class 생성하는 것은 JavaExec 태스크로 하면 된다. CXF 참조
Annotation Processing
Annotation Processing은 원칙적으로는 컴파일 과정에서 자동으로 수행된다.
하지만 JPA 2 MetaModel 생성같이 소스를 생성해야 할 경우가 있는데 그럴 때는 -proc:only
옵션으로 독립적으로 소스 생성만 하는 컴파일러를 돌려주고 그 뒤에 실제 컴파일을 수행하도록 실행 계획을 짜면 된다.
Lombok의 경우에도 아무 설정도 할 필요없다. 클래스패스에만 있으면 자동으로 수행된다.
Gradle에서 JPA2 MetaModel 생성 참조.
projectA의 단위테스트가 projectB의 단위테스트에 의존
projectA의 단위테스트가 projectB의 단위테스트에 의존하는 경우가 있다. 원칙적으로는 이러면 안된다. 근본적으로 projectA와 B간의 의존관계는 메인 자바 소스에 대한 것이어야지 테스트에 대한 것이면 안된다. 하지만 어쨌든 이런 상태로 컴파일과 실행이 가능하게 만들 수는 있다.
Multi Project 단위 테스트간의 의존성 참조