しおしお

IntelliJ IDEAのことなんかを書いてます

Spring Cloud AWSを使ってS3にファイルを保存してみた

Spring Cloud for Amazon Web Servicesを使ってS3にファイルを保存してみたお話です。

依存ライブラリ

compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.cloud:spring-cloud-starter-aws')

バージョンはこんな感じです

+--- org.springframework.boot:spring-boot-starter-web -> 2.0.1.RELEASE
+--- org.springframework.cloud:spring-cloud-starter-aws -> 2.0.0.M4

S3にファイルを保存するコード

9.3 Uploading filesを参考に書いてみました

@RestController
@RequestMapping("/api")
class TestController(
        private val resourceLoader: ResourceLoader
) {

    @GetMapping("/test1")
    @ResponseStatus(HttpStatus.OK)
    fun test(): Unit {
        println("resourceLoader.javaClass.name = ${resourceLoader.javaClass.name}")
        (resourceLoader.getResource("s3://バケット名/test.txt") as WritableResource).outputStream.writer().use { 
            it.write("書き込みテスト")
        }
    }
}

動かしてみる

環境変数AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを設定して実行します。
EC2で実行した場合は、メタデータからリージョン情報が取得されるらしいです。

$JAVA_HOME/bin/java -Dcloud.aws.stack.auto=false -Dcloud.aws.credentials.useDefaultAwsCredentialsChain=true -jar hoge.jar

標準出力にはこれがでたので、ResourceLoaderの実装としてPathMatchingSimpleStorageResourcePatternResolverがインジェクとされているのがわかる。

resourceLoader.javaClass.name = org.springframework.cloud.aws.core.io.s3.PathMatchingSimpleStorageResourcePatternResolver

S3でファイルが作られていることも確認と。
f:id:sioiri:20180418081324p:plain

IntelliJ IDEA 2018.1 Public Previewでpostfix code completionが追加できるようになってた

IntelliJ IDEA 2018.1 Public Previewでpostfix code completionが追加できるようになってたのでお試ししてみた。

登録方法はこんな感じ。

Postfix Completionの設定画面から追加ダイアログを開く

流れ的にはこんな感じ。
ここにハマりポイントがあって、「+」を押した時に下の画像のようにJavaが複数表示されているとうまく登録されない…
原因は、Postfix Completionを登録するようなプラグインをインストールしているから。プラグインを消すと、Javaがひとつだけになってちゃんと登録されるようになります。
f:id:sioiri:20180301070908p:plain

ダイアログでPostfix Completionの内容を登録する

この例だと、primitive以外に対してクラス名を取ってくるみたいな感じです。

$EXPR$がPostfix Competionを実行した対象が入る部分になっていて、$END$がPostfix Completion後にカーソルを移動する場所になります。

f:id:sioiri:20180301073425p:plain

動かしてみると…

こんな感じにちゃんと使える!
f:id:sioiri:20180301074335g:plain

Gradle4.6-rc1からのBOMサポート

Gradle 5.0のfeature previewでGradle5.0からはデフォルトで有効になるかもしれないやつらしいです。
Gradle4.6 RC1で使う場合には、enableFeaturePreview('IMPROVED_POM_SUPPORT')をsettings.gradleに追加してこの機能を有効化する必要がある。

settings.gradle

enableFeaturePreview('IMPROVED_POM_SUPPORT')

build.gradle

dependencies {
  // bom
  compile 'com.nablarch.profile:nablarch-bom:5u12'
  // bomにバージョン番号が定義されているのでバージョン番号は不要
  compile 'com.nablarch.framework:nablarch-fw-web' 
}

Gradle4.6-rc1からのJUnit5サポートを試してみた

Gradle4.6からのJUnit5サポートをお試ししてみた。

これより古いバージョンはGradleからJUnit5のテストを実行する - しおしおのエントリのようにする必要があると。

build.gradleの内容

test.useJUnitPlatformでJUnit5を有効化してあげる。
これだけでよくて、昔のバージョンのようにJUnit Platform Gradle Pluginは不要になる。

buildscript {
  ext.junit_version = '5.0.3'
}

test {
  useJUnitPlatform()

  // ログを出力したい場合…
  testLogging {
    events "passed", "skipped", "failed", "standardOut", "standardError"
  }
}

dependencies {
  
  testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version"
 
  testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_version"
}

実行

./gradlew clean testで実行する。
ログを有効かしていると、こんな感じのものが出力される。

:test
sample.ParameterizedSampleTest > [1] 1 PASSED
sample.ParameterizedSampleTest > [2] 2 PASSED
sample.JUnit5Sample > test() PASSED
sample.ParamTest > [1] hoge, 4 PASSED
sample.ParamTest > [2] 1, 1 PASSED
sample.ParamTest > [1] (hoge, 4) PASSED
sample.ParamTest > [2] (abcdefg, 7) PASSED
BUILD SUCCESSFUL in 2s

テストのレポートはhtmlファイルでbuild/reports/testsに出力される。
JUnit Platform Gradle Pluginのようにxmlのテスト結果だけじゃないので良い感じ。

JaCoCoプラグイン

下を追加して、./gradlew clean test jacocoTestReportカバレッジが取れるようになる。

apply plugin: 'jacoco'

Gradle&JUnit5でJaCoCoを使う - しおしおみたいなことも要らなくなる。


おわり。

Gradle&JUnit5でJaCoCoを使う

Gradle&JUnit5の組み合わせでJaCoCoを使用した場合、デフォルトだとテスト実行時のカバレッジを取得することができない。*1
なので、この組み合わせでJaCoCoでカバレッジをとりたい場合は、JaCoCoプラグインの設定を変更する必要がある。

JaCoCoプラグインへの設定

  • JUnit5のテストを実行するjunitPlatformTestタスクをカバレッジ対象にする。
  • レポートを出力するタスクを追加して、junitPlatformTestの結果からレポートを出力できるようにする。
jacoco {
  applyTo junitPlatformTest
}

task junitPlatformJacocoReport(type: JacocoReport) {
  sourceSets sourceSets.main
  executionData junitPlatformTest
}

これで、gradle junitPlatformTest junitPlatformJacocoReportカバレッジ取得とhtmlレポートが生成できるようになると。

*1:GradleのJaCoCoプラグインのデフォルト動作だとjunitPlatformTestタスクはカバレッジ対象にならない。

JaCoCo0.8.0を試してみる

Release 0.8.0 · jacoco/jacoco · GitHubのtry-with-resources対応などなど良さげそうに見えたので試してみた。

try-with-resourcesを使った実装を作成

雑にこんな感じで…

public void test() throws IOException {

    try (InputStream stream = new ByteArrayInputStream(new byte[0])) {
        stream.read();
    }
}

0.7.9までの動きを確認と

build.gradleはこんな感じに

jacoco {
  toolVersion = "0.7.9"
}

JaCoCoのレポートを確認すると、分岐網羅されていないとなる。
f:id:sioiri:20180105210857p:plain

0.8.0にすると

build.gradleはこんな感じに

jacoco {
  toolVersion = "0.8.0"
}

分岐網羅されてていい感じ。
f:id:sioiri:20180105210958p:plain

他にもprivateコンストラクタの除外とかもしてくれたりするみたいなのがよい。

IntelliJ IDEA 2017.3 EAPからのeditor-based REST clientを試す

IntelliJ IDEA 2017.3(今はEAP)から追加されたeditor-based REST clientを試してみたよ。
詳しくは、What’s New in IntelliJ IDEA 2017.3 EAP? | IntelliJ IDEA BlogToolsに書かれてるよ。

試すために作ったサーバ側のコード

GETとPOSTを確認するためだけの簡単な実装で・・・

@RestController
@RequestMapping("/api")
class Api {

    data class Data(val value: String)

    @GetMapping
    fun get(@RequestHeader("X-Hoge") hoge: String): Data = Data("X-Hogeは $hoge でした")

    @PostMapping
    fun post(@RequestBody data: Data): ResponseEntity<Unit> {
        val httpHeaders = HttpHeaders()
        httpHeaders["x-hoge"] = listOf(data.toString())
        return ResponseEntity(httpHeaders, HttpStatus.OK)
    }
}

getを試す

拡張子がhttpだと、editor-based REST clientとして認識されるので、適当なところに拡張子がhttpのファイルを作ってあげる。
プロジェクト配下に置く必要がなければ、blogにあるようにScratch Fileとして作ってあげればよいのかなと。

ファイルの中身はこんな感じにする。

### get
# GETのあとにスペースを開けてURLを指定する。
# HTTP Headerは次の行から列挙する。
GET http://localhost:8080/api
X-Hoge: aaaa

こんな感じに補完もできるので割と良い感じ。
f:id:sioiri:20170916171909g:plain

実行はエディタの横に表示されている実行アイコンから行うと。
f:id:sioiri:20170916170331p:plain

実行結果は、Run Windowに表示されると。
レスポンスボディの内容は、プロジェクトの.idea/httpRequestsの下に自動的に保存されるから、あとから参照もできる。
繰り返し実行した場合、大量に保存されそうだから自分で消さないとダメなのかなー。。。
f:id:sioiri:20170916170603p:plain

postを試す

getと同じように拡張子がhttpなファイルを作る。

こんな感じにヘッダーの後に空行いれて送信するボディを定義すると

POST http://localhost:8080/api
Content-Type: application/json

{
  "value": "fuga"
}

こんな感じにファイルに定義した内容をボディを送るれるみたい。
指定するファイルのパスは相対パスの場合はプロジェクト直下から。

POST http://localhost:8080/api
Content-Type: application/json

< ./input/input.json

実行方法や、結果の参照はgetと同じ感じ。
GUIのREST Clientより繰り返し実行するのは便利かも?

おわり。