목차

Gradle Java Plugin

apply plugin: 'java'

Java Project 기본 build.gradle

apply plugin: 'java'
apply plugin: 'eclipse'
 
ext {
  javaVersion='1.6'
}
 
buildDir = 'build'
 
repositories {
  mavenCentral()
}
 
dependencies {
  compile '원하는 모듈'
  testCompile group: 'junit', name: 'junit', version: '4.+'
}
 
task initSrc << {
    project.sourceSets*.allSource.srcDirTrees.flatten().dir.each { dir ->
        dir.mkdirs()
    }
}
 
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
 
// 소스 인코딩 지정방법 1
[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'
// 소스 인코딩 지정밥법 2
tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}
javadoc {
    options.encoding = 'UTF-8'
}
 
/* Eclipse 관련 설정들 */
tasks.eclipse.dependsOn cleanEclipse
tasks.eclipse.dependsOn initSrc
 
eclipse {
  classpath {
    downloadSources = true
    defaultOutputDir = file("${buildDir}/classes/main")
  }
}

기본 디렉토리 구조

기본 태스크

기본 의존성 설정

repositories {
    mavenCentral()
}
 
dependencies {
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

Publishing Jar

// 저장소를 지정하고,
uploadArchives {
    repositories {
       flatDir {
           dirs 'repos'
       }
    }
}

gradle uploadArchives 명령으로 퍼블리싱한다.

Source Sets

프로젝트 레이아웃

자바 프로젝트의 기본 프로젝트 레이아웃은 다음과 같다.

의존성 관리

다음과 같은 의존성 설정(configurations)이 추가되다. 이 의존성 설정은 자바 플러그인의 태스크들에 의해 참조 된다.

이름 부모 사용하는 태스크 의미
compile - compileJava 컴파일 시점 의존성
runtime compile - 실행시 의존성
testCompile compile compileTestJava 테스트를 컴파일할 때 필요한 추가적인 의존성
testRuntime runtime, testCompile test 테스트만 실행할 때 필요한 추가적인 의존성
archives - uploadArchives 해당 프로젝트가 생성한 Artifact(jar 등)
default runtime - 이 프로젝트에서 기본으로 사용되는 의존성. 이 프로젝트의 실행시에 필요한 Artifact들과 의존성을 포함한다.

소스 셋을 추가하면 다음과 같은 의존성 설정도 함께 추가된다.

이름 부모 사용하는 태스크 의미
소스셋Compile - compile소스셋Java 특정 소스셋의 컴파일시점 의존성
소스셋Runtime 소스셋Compile - 특정 소스셋의 실행시 의존성

관례 프라퍼티들

Gradle 문서 참조. JavaPluginConvention, BasePluginConvention 참조.

Source Set 다루기

저기서 main 은 SourceSet이다.

저기서 'java'와 'resources'는 SourceDirectorySet이며 srcDir()메소드는 소스 디렉토리를 추가하는 것이다.

Source Set 프라퍼티들

프라퍼티 이름 Type 기본값 설명
name String(read-only) not null 소스셋 이름
output SourceSetOutput not null 소스셋의 출력 디렉토리. 컴파일된 클래스와 리소스를 저장할 곳
output.classesDir File buildDir/classes/name 소스셋의 클래스를 생성할 디렉토리
output.resourcesDir File buildDir/resources/name 소스셋의 리소스를 생성할 디렉토리
compileClasspath FileCollection compileSourceSet configuration 소스를 컴파일할 때 사용할 클래스패스
runtimeClasspath FileCollection output + runtimeSourceSet configuration 클래스 실행시의 클래스패스
java SourceDirectorySet (read-only) not null 소스셋의 자바 소스파일들. *.java 파일만 포함호며 그 외 파일은 제외된다.
java.srcDirs Set<File>, Project.files()에서 사용할 수 있는 모든 값 [projectDir/src/name/java] 자바 소스 파일을 포함하고 있는 소스 디렉토리들, srcDir()로 추가가능
resources SourceDirectorySet (read-only) not null 소스셋의 리소스들. *.java 파일은 제외된다. 플러그인에 때라 제외되는 목록이 추가된다.
resources.srcDirs Set<File>, Project.files()에서 사용할 수 있는 모든 값 [projectDir/src/name/resources] 리소스를 포함하고 있는 소스 디렉토리들
allJava SourceDirectorySet (read-only) java 모든 *.java 파일들. 플러그인에 따라 더 추가 될 수 있음
allSource SourceDirectorySet (read-only) resources + java 모든 소스 파일들(리소스 + *.java). 플러그인에 따라 더 추가 될 수 있음.

main/resources에 java 디렉토리를 추가하면서 *.java 파일은 제외하기

때로는 src/main/java 를 리소스에 포함시켜야 할 경우가 있다. 개발자들이 resources에 리소스를 넣지 않고 java에 넣고서 클래스와 리소스간의 결합성을 쉽게 파악할 수 있고자 할 경우가 있기 때문이다(iBATIS SqlMapper 사용하는 경우 등).

sourceSets {
    main {
        resources {
            srcDir "${project.projectDir}/src/main/java"
            // exclude "**/*.java" : 하지 말것. Gradle에서 문제 없지만 Eclipse에서 문제를 일으킴.
        }
    }
}

새로운 소스셋 만들기

소스셋 태스크 예제

Javadoc

태스크 프라퍼티 타입 기본값
classpath FileCollection sourceSets.main.output + sourceSets.main.compileClasspath
source FileTree sourceSets.main.allJava]]
destincationDir File
title String 프로젝트 이름과 버전

* StandardJavadocDocletOptions (Gradle API 1.10) 참조하여 javadoc 옵션들 지정.

Java 9 HTML5 javadoc

javadoc {
    options.addBooleanOption('html5', true)
}

멀티 모듈의 소스를 합쳐 Javadoc 생성

task javadoc(type: Javadoc) {
    source subprojects.collect {project ->
        project.sourceSets.main.allJava
    }
    destinationDir = new File(buildDir, 'javadoc')
    // Might need a classpath
    classpath = files(subprojects.collect {project ->
        project.sourceSets.main.compileClasspath})
    }
}

Delombok

Clean

태스크 프라퍼티 타입 기본값
dir File buildDir

Resources

태스크 프라퍼티 타입 기본값
srcDirs files()가 받을 수 있는 모든 값 sourceSet.resources
destinationDir File sourceSet.output.resourcesDir

CompileJava

태스크 프라퍼티 타입 기본값
classpath FileCollection sourceSet.compileClasspath
source FileTree files()가 받을 수 있는 모든 인자]] sourceSet.java
sourceCompatibility String Java 소스의 Java 언어 레벨 (…, 1.4,1.5,1.6,1.7 …) project.sourceCompatibilty
targetCompatibility Strign Java 클래스의 Java 언어레벨 project.targetCompatibility
destinationDir File sourceSet.output.classesDir
options CompileOptions 컴파일 관련 각종 옵션 설정

컴파일 옵션들

아래 값들은 Java 플러그인을 적용한 뒤에 설정해야 한다. 그렇지 않으면 Java 플러그인이 값을 초기화 해 버릴 수도 있다. 아래 값들은 ext 블럭으로 만들면 “안” 된다.

Test

테스트 실행

성공한 Test 강제 실행(force run test)

System Properties

gradle -Dtest.single=ThisUniquelyNamedTest test
 
gradle -Dtest.single=a/b/ test
 
gradle -DintegTest.single=*IntegrationTest integTest
 
gradle -Dtest.single=:proj1:test:Customer build
 
gradle -DintegTest.single=c/d/ :proj1:integTest

테스트 감지

JUnit

TestNG

테스트의 분리 - 소스셋이 동일하고 이름으로 구분 - 더이상 사용하지 말 것

test {
    exclude '**/*IntegrationTest.class'
}
 
task integrationTest(type: Test, dependsOn: testClasses) {
    description = 'Integration test'
    group = 'verification'
 
    include '**/*IntegrationTest.class'
    testReportDir file("${buildDir}/reports/integration-test")
}
 
tasks.withType(Test) {
    // Test 들의 공통 설정
    useJUnit()
    maxHeapSize '2048m'
    jvmArgs '-XX:MaxPermSize=256m'
 
    testLogging {
        events 'started', 'passed'
    }
}

테스트의 분리 - 소스셋 분리 - 권장

// 별도 소스셋 구성
sourceSets {
    integrationTest {
        java {
            compileClasspath += main.output + test.output
            runtimeClasspath += main.output + test.output
            srcDir file('src/integration-test/java')
        }
        groovy { // for Spock
            compileClasspath += main.output + test.output
             runtimeClasspath += main.output + test.output
            srcDir file('src/integration-test/groovy')
        }
        resources.srcDir file('src/integration-test/resources')
    }
}
 
// integrationTest 전용 configuration 지정.
// integrationTest에만 필요한 의존성 지정 가능.
 
configurations {
    integrationTestCompile.extendsFrom testCompile
    integrationTestRuntime.extendsFrom testRuntime
}
 
// Task 생성
task integrationTest(type: Test) {
    testClassesDirs = sourceSets.integrationTest.output.classesDirs // 구버전에서는 Dir 단수형으로만 지정됨.
    classpath = sourceSets.integrationTest.runtimeClasspath
    reports { // reports 는 원하는대로만.
        junitXml.enabled = true
        html.enabled = true
        ignoreFailures = true
    }
}
 
// 의존성 지정으로 check 실행시 자동 테스트
check.dependsOn integrationTest

TestSets Plugin 사용

Convention Values

태스크 프라퍼티 타입 기본값
testClassesDir File sourceSets.test.output.classesDir
classpath FileCollection sourceSets.test.runtimeClasspath
testResultsDir File testResultsDir
testReportDir File testReportDir
testSrcDirs List<File> sourceSets.test.java.srcDirs
jvmArgs List<String> [], 문자열 배열로 JVM 옵션을 지정한다.
maxHeapSize String null, '256m' 형태
systemProperty 키, 값 키, 값 쌍을 인자로 테스트 수행 JVM의 시스템 프라퍼티 지정
include String[] [], '**/*IntgrationTest.class', 'org/foo/**', …
exclude String[] [], '**/*IntgrationTest.class', 'org/foo/**', …

TestLogging

test 제외하기

multi project 테스트 결과 모아보기

Creating a unit test report for subprojects

subprojects {
    apply plugin: 'java'
 
    // Disable the test report for the individual test task
    test {
        reports.html.enabled = false
    }
}
 
task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    // Include the results from the `test` task in all subprojects
    reportOn subprojects*.test
}

Test 완료후에 실패건이 있는지 마킹만 하기

test {
    ignoreFailures = true
    afterSuite { TestDescriptor desc, TestResult result ->
        if (result.failedTestCount > 0) {
            rootProject.buildDir.mkdir()
            File testFailed = rootProject.file("${rootProject.buildDir}/testFailedMarker")
            if (!testFailed.exists()) {
                testFailed.createNewFile()
                testFailed.text = "이 파일이 존재하면 테스트중 실패한 건이 존재한다는 의미입니다."
            }
            logger.warn("testFailedMarker - {}", result.failedTestCount)
        }
    }
}
if [ -f "build/testFailedMarker" ]; then
    echo "file exists"
    exit 1
fi

Jar

Manifest

JavaExec

Java 클래스를 실행할 때 Ant를 사용하는 방법JavaExec를 사용하는 방법이 있다. project.javaexec() 메소드를 호출해도 된다. javaexec 메소드는 Closure를 인자로 받는데 거기 들어가는 내용은 JavaExec 설정과 같다. How to use in gradle javaexec with classpath dependency

Gradle Application Plugin도 참조한다.

// 외부 의존성 지정 필요시
configurations {
   newConfForJavaexec
}
 
dependencies {
    newConfForJavaexec "xxxx:xxx:1.1"
    // ...
}
 
task someTask(type: JavaExec) {
    main = 'xxx.yyy.MainClass'
 
    // 외부 의존성의 Java 클래스 실행시
    classpath = configurations.newConfForJavaexec
 
    // 외부 jar가 아닌 현재 프로젝트의 Java 클래스 실행시 - 1번 방식
    classpath = configurations.runtime
    classpath += sourceSets.main.output
    // 외부 jar가 아닌 현재 프로젝트의 Java 클래스 실행시 - 2번 방식
    classpath = sourceSets.main.runtimeClasspath
 
    args '인자1', '인자2', .....
    systemProperty 'simple.message', 'Hello '
    jvmArgs '-Xmx512m'
}

System Properties 전달

Gradle을 통해 실행되는 Java Application에 Gradle의 System Properties를그대로 전달하기 - Gradle Goodness: Pass Java System Properties To Java Tasks

// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {
// Assign all Java system properties from
// the command line to the JavaExec task.
    systemProperties System.properties
}