【GradleでJakartaEE 8 アプリケーション開発】2. プロジェクト作成

#はじめに
本記事は [【GradleでJakartaEE 8 アプリケーション開発】1. 環境構築](https://qiita.com/sunnycloudy764/items/1431d78f05dc092a23b2) の続きです。
前回の記事では開発環境の構築を行いました。本記事ではGradleプロジェクトを作成します。

#EclipseのGradle設定
EclipseでGradleプロジェクトを使う際、前回の環境設定でインストールしたGradleを使用するために下記設定を行います。
Eclipseを起動し、ウィンドウ > 設定 を開き、Gradle を選択し、下記の変更を行います。

| 項目 | 内容 |
|:------|:--------|
| ローカル・インストール・ディレクトリー| Gradleのインストールフォルダ |
| Java ホーム | Jakarta EE 8 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/47bf4ab9-91d1-198f-e646-1d30180b32af.png)

変更後、適用して閉じる をクリックします。

#Gradleプロジェクトの作成
Gradleプロジェクトの作成方法ですが、Eclipseを使う方法とコマンドライン上で作成する方法の二つがあります。
それぞれ紹介していきます。

## EclipseでGradleプロジェクト作成
Eclipseにて、ファイル > 新規 > Graldeプロジェクト をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/3f37d9e7-bc53-9fb8-fb58-465888b8a80d.png)

プロジェクト名を入力し、次へ をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/34f68bf3-1794-68aa-349d-42a3de1fb2ef.png)

設定はそのまま、次へ をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/0fdc96a8-0439-1dd5-8f28-09a7e9c823ea.png)

しばらくすると下記画面が表示されるので、完了 をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/acf67abb-0009-7003-ee11-253123e8269c.png)

Gradleプロジェクトが作成され、パッケージ・エクスプローラー上に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/1e26ff75-a7d7-9c28-4add-05b669f25f2c.png)

##コマンドラインでGradleプロジェクト作成
コマンドラインを開き、プロジェクトを作成するフォルダへ移動します。
プロジェクト名となるフォルダを作成します。

```
c:\projects>mkdir jakartaeesample2

c:\projects>dir
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は F06A-A652 です

 c:\projects のディレクトリ

2020/03/29  12:11    <DIR>          .
2020/03/29  12:11    <DIR>          ..
2020/03/29  12:11    <DIR>          jakartaeesample2
               0 個のファイル                   0 バイト
               3 個のディレクトリ  134,858,534,912 バイトの空き領域

c:\projects>
```

作成したフォルダへ移動し、 ```gradle init --type java-library``` を実行します。
build script DSL の選択肢では 1 を、test frameworkの選択肢では 1 を入力します。
Project name、Source package はdefaultのままとしますので、空欄のままEnterを入力して下さい。

```
c:\projects>cd jakartaeesample2

c:\projects\jakartaeesample2>gradle init --type java-library
Starting a Gradle Daemon (subsequent builds will be faster)

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4] 1

Project name (default: jakartaeesample2):
Source package (default: jakartaeesample2):

> Task :init
Get more help with your project: https://docs.gradle.org/6.2.2/userguide/java_library_plugin.html

BUILD SUCCESSFUL in 3m 57s
2 actionable tasks: 2 executed
c:\projects\jakartaeesample2>
```

BUILD SUCCESSFUL が表示されたらプロジェクト作成は完了です。
作成したプロジェクトをEclipseをからプロジェクトをインポートします。
Eclipseを起動し、ファイル > インポートをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/690bfcfe-9a1a-9e66-1b10-26d7a170ef14.png)

Gradle > 既存の Gradle プロジェクト を選択し、次へ をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/d300bd37-d2ec-a273-0da5-0615abbe56af.png)

プロジェクト・ルート・ディレクトリーに先ほど作成したプロジェクトのフォルダを選択し、次へ をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/220de249-5e6f-def8-2e5c-dcbfa9b63e69.png)

デフォルト設定のまま、次へ をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/3c258ebf-c442-f717-fdff-4466d5c9821f.png)

しばらくすると下記画面が表示されるので、完了 をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/e9cc1773-0e54-ea0f-60fc-f36309e87aa7.png)

パッケージ・エクスプローラーにインポートしたGradleプロジェクトが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/f85755ec-5fde-9261-0a36-7055048f786a.png)

#gradle.properties の追加
Gradleプロジェクトを作成したら、build.gradle に使用するためのプロパティファイル gradle.properties を追加します。
パッケージ・エクスプローラーにてプロジェクト名を右クリックし、新規 > ファイル を選択します。

ファイル名に gradle.properties を入力し、完了 をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/12989d8a-db91-709f-94ab-97ad228ba58f.png)

gradle.properties ファイルが追加されエディタ表示されるので、下記内容を入力してください。

``` gradle.properties
#########################
 # gradle.properties for jakartaeesample2
 # author:         sunnycloudy764
 # since:          2020/03/27
 # Gradle version: 6.2.2
#########################

#########################
# base setting
#########################
groupName=jakartaeesample2
artifactid=jakartaeesample2
buildVersion=0.0.1
appName=jakartaeesample2
encoding=UTF-8
jdkVersion=11

#####################
# plugin version
#####################
spotbugsVersion = 4.0.5
flywayVersion = 6.3.2

#####################
# plugin tool version
#####################
checkstyleToolVersion = 8.31
spotbugsToolVersion = 4.0.1

#####################
# library version
#####################
JakartaEEAPIVersion = 8.0
PostgreSQLVersion=42.2.11

slf4jVersion = 1.7.30
logbackVersion = 1.2.3

commonsCollections4Version = 4.4
commonsLang3Version = 3.10
commonsIoVersion = 2.6

lombokVersion=1.18.12

junitVersion = 4.13
hamcrestVersion = 1.3
assertjVersion = 3.15.0
assertjdbVersion = 1.3.0
mockitoVersion = 3.3.3
jacocoCoreVersion=0.8.5

h2Version = 1.4.200
dbSetupVersion = 2.1.0

arquillianJunitContainerVersion=1.6.0.Final
arquillianJacocoVersion=1.1.0
arquillianPayaraEmbeddedVersion=2.2
payaraEmbeddedAllVersion=5.201

#####################
# flyway settings
#####################
flywayuser=postgresql
flywaypassword=xxxxxxx
flywaydriver = org.postgresql.Driver
flywayurl = jdbc:postgresql://localhost:5432/testdb
flywaytarget = 0.0.1
outOfOrder = false
validateOnMigrate = true

#####################
# project facet
#####################
javaFacet = 11
webFacet = 4.0
jsfFacet = 2.3
glassfishFacet = 5.0

#####################
# glassfish settings
#####################
glassfishHome = C:/payara/payara-5.201/payara5/glassfish
glassfishDomain = domain1
isRemote = false
remoteIP = 127.0.0.1
```

#build.gradle の変更
次に、Jakarta EE アプリケーションを開発するためにbuild.gradleを変更します。
下記の通り変更してください。

```gradle:build.gradle
/*
 ******************************
 * build.gradle for jakartaeesample2
 * author:         sunnycloudy764
 * since:          2020/03/27
 * Gradle version: 6.2.2
 ******************************
 */
plugins {
  id "com.github.spotbugs" version "${spotbugsVersion}"
  id "org.flywaydb.flyway" version "${flywayVersion}"
}

apply plugin: 'project-report'
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse'
apply plugin: 'eclipse-wtp'
apply plugin: 'checkstyle'
apply plugin: 'jacoco'

sourceCompatibility = "${jdkVersion}"
targetCompatibility = "${jdkVersion}"

tasks.withType(AbstractCompile)*.options*.encoding = "${encoding}"
tasks.withType(GroovyCompile)*.groovyOptions*.encoding = "${encoding}"
[compileJava, compileTestJava, javadoc].each { it.options.encoding = "${encoding}" }

version = "${buildVersion}"
group = "${groupName}"

configurations {
	all*.exclude module: 'slf4j-jdk12'
	all*.exclude module: 'slf4j-jdk14'
    all*.exclude module: 'servlet-api'
    assertj
}

repositories {
   mavenCentral()
   maven { url 'http://repository.jboss.org/nexus/content/groups/public' }
}

dependencies {
	//Jakarta EE API
	compileOnly group: 'jakarta.platform', name: 'jakarta.jakartaee-api', version: "${JakartaEEAPIVersion}"
	testCompileOnly group: 'jakarta.platform', name: 'jakarta.jakartaee-api', version: "${JakartaEEAPIVersion}"

	//JDBC driver (PostgreSQL)
	implementation group: 'org.postgresql', name: 'postgresql', version: "${PostgreSQLVersion}"

	//SLF4j + logback
	implementation group:'org.slf4j', name: 'slf4j-api', version: "${slf4jVersion}"
	implementation group:'ch.qos.logback', name: 'logback-classic', version: "${logbackVersion}"
	implementation group:'ch.qos.logback', name: 'logback-core', version: "${logbackVersion}"

	//Apache Commons
	implementation group:'org.apache.commons', name: 'commons-collections4', version: "${commonsCollections4Version}"
	implementation group:'org.apache.commons',name:'commons-lang3',version:"${commonsLang3Version}"
	implementation group:'commons-io', name:'commons-io',version:"${commonsIoVersion}"

	//Lombok
	annotationProcessor group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}"
	compileOnly group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}"
	testAnnotationProcessor  group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}"
	testCompileOnly group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}"

	//Test libraries
	//JUnit
	testImplementation (group: 'junit', name: 'junit', version: "${junitVersion}"){
        exclude module: 'hamcrest-core'
	}
	testImplementation group:'org.hamcrest', name: 'hamcrest-all', version: "${hamcrestVersion}"
	testImplementation group: 'org.assertj', name: 'assertj-core', version: "${assertjVersion}"
	testImplementation group: 'org.assertj', name: 'assertj-db', version: "${assertjdbVersion}"

	//Mock libraries
	testImplementation group:'org.mockito', name:'mockito-inline', version: "${mockitoVersion}"

	//jacoco
	testImplementation group: 'org.jacoco', name: 'org.jacoco.core', version: "${jacocoCoreVersion}"

	//for DB Test
	testImplementation group: 'com.h2database', name: 'h2', version: "${h2Version}"
	testImplementation group: 'com.ninja-squad', name: 'DbSetup', version: "${dbSetupVersion}"

	//CDI Test(Arquillian)
	testImplementation group: 'org.jboss.arquillian.junit', name: 'arquillian-junit-container', version: "${arquillianJunitContainerVersion}"
	testImplementation group:'org.jboss.arquillian.extension', name: 'arquillian-jacoco', version: "${arquillianJacocoVersion}"
	testImplementation group:'fish.payara.arquillian', name: 'arquillian-payara-server-embedded', version: "${arquillianPayaraEmbeddedVersion}"
   	testImplementation group: 'fish.payara.extras', name: 'payara-embedded-all', version: "${payaraEmbeddedAllVersion}"

	//assertj assertion generator
	assertj 'org.assertj:assertj-assertions-generator:2.2.0'
    assertj project
}

// flyway settings
flyway {
    driver = "${flywaydriver}"
    url = "${flywayurl}"
    user = "${flywayuser}"
    password = "${flywaypassword}"
    target = "${flywaytarget}"
    outOfOrder = false
    validateOnMigrate = true
    cleanOnValidationError = false
}

//assertj assertion generator
def assertjOutput = file('src-gen/test/java')
task assertjClean(type: Delete) {
    delete assertjOutput
}

task assertjGen(dependsOn: assertjClean, type: JavaExec) {
    doFirst {
        if (!assertjOutput.exists()) {
            if (!assertjOutput.mkdirs()) {
                throw new InvalidUserDataException("Unable to create `$assertjOutput` directory")
            }
        }
    }
    main 'org.assertj.assertions.generator.cli.AssertionGeneratorLauncher'
    classpath = files(configurations.assertj)
    workingDir = assertjOutput
    args = [    ]
}
compileTestJava.dependsOn(assertjGen)

// assertj generator生成のコードをsourceSetsに追加
sourceSets {
    test {
        java {
            srcDir 'src/test/java'
            srcDir 'src-gen/test/java'
        }
    }
}

war {
	webAppDirName = "WebContent"
	baseName = "${artifactid}"
}

test {
    systemProperties 'property': 'value'
    ignoreFailures = true
    reports {
    	html.enabled = true
    	junitXml.enabled = true
	}
}

jacoco {
	toolVersion = "${jacocoCoreVersion}"
}
jacocoTestReport {
	reports {
		html.enabled = true
		xml.enabled = true
		csv.enabled = false
	}
}

checkstyle {
    toolVersion = "${checkstyleToolVersion}"
    ignoreFailures = true
    sourceSets = subprojects.sourceSets.main
	configFile file("$rootDir/config/checkstyle.xml")
}

spotbugs {
    toolVersion =  "${spotbugsToolVersion}"
    ignoreFailures = true
    effort = "max"
    reportLevel = 'low'
}

//Eclipse IDE用の設定
eclipse {
  wtp {
	facet {
        facet name: 'jst.java', version: "${javaFacet}"
        facet name: 'jst.web', version: "${webFacet}"
        facet name: 'jst.jsf', version: "${jsfFacet}"
        facet name: 'glassfish.web', version: "${glassfishFacet}"
    }
    component {
      contextPath = 'WebContent'
    }
  }
}

//OSチェックを行います。
def isWindows() {
    return System.properties['os.name'].toLowerCase().contains('windows')
}

//Payara Server設定
ext {
	asadmin = "${glassfishHome}" + (isWindows() ? '/bin/asadmin.bat' : '/bin/asadmin')
	domain = "${glassfishDomain}"
}

//Payara Server を起動します。
task startServer(type: Exec) {
	description 'アプリケーションサーバを起動します。'
    commandLine asadmin, 'start-domain', '--debug=true', domain
}

//Payara Server を停止します。
task stopServer(type: Exec) {
	description 'アプリケーションサーバを停止します。'
    commandLine asadmin, 'stop-domain', domain
}

//Payara Server にWARファイルをデプロイします。
task deploy(type: Exec, dependsOn: ':war') {
	appName = "${appName}"
	description 'WARファイルをデプロイします。'
	if("${isRemote}" == 'true'){
		commandLine asadmin, '--host', "${remoteIP}", '--user', 'admin', '--passwordfile', '..\\glassfishpassword.txt', '--port', '4848' , 'deploy', '--force=true', '--contextroot', appName, '--name', appName, war.archivePath
	}else{
	    commandLine asadmin, 'deploy', '--force=true', "--contextroot", appName, "--name", appName, war.archivePath
    }
}
```
Jakarta EEの開発をするためには dependency に Jakarta EE API を追加すればOKですが、ここでは普段の開発で使用するためのライブラリを色々と追加しています。

- JDBCドライバ：今回はPostgreSQL
- ロガー：slf4j + logback
- Apache Commons：Commons Collection, Commons lang, Commons IO
- 冗長コード削減：Lombok
- 単体テスト：JUnit, mockito, assertj
- コードカバレッジ：jacoco
- スルーテスト：Arquillian

また、DB作成のためflywayDB pluginを追加し、静的解析としてcheckstyleとspotbugsを追加しています。
そして、Gradleタスクでデプロイが可能となるようにdeployタスクを作成しています。

#checkstyle 定義ファイル作成
今回のプロジェクトでは静的解析ツールの一つとしてcheckstyleを使用しているため、checkstyleの定義ファイルをプロジェクト内に配置する必要があります。
まず、定義ファイル配置先となるconfigフォルダを作成します。
パッケージ・エクスプローラーにてプロジェクト名を右クリックし、新規 > フォルダー を選択します。
フォルダー名に config と入力し、完了 をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226889/ad3b9bed-fb50-9994-49e5-c36ceb3feb6d.png)

config フォルダが作成されたら、config フォルダを右クリックし、 新規 > ファイル を選択します。
ファイル名に checkstyle.xml と入力し、完了 をクリックします。
checkstyle.xmlについては、[公式の google_check.xml](https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml) を参考に作成するとよいと思います。

checkstyle.xmlを作成し、Eclipse上でエラーが発生しない場合はプロジェクト作成の完了となります。