かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

共有ライブラリを管理するために Sonatype の Nexus Repository Manager OSS を使用する ( その12 )( 他のライブラリに依存するライブラリを作成する )

概要

共有ライブラリを管理するために Sonatype の Nexus Repository Manager OSS を使用する ( その11 )( Nexus を 3.0.0-03 → 3.0.1-01 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • 他のライブラリに依存するライブラリを作成してみます。
    • 他のライブラリは org.apache.commons:commons-lang3 を使用します。

参照したサイト・書籍

  1. 金勘定のためのBigDecimalそしてMoney and Currency API
    http://www.slideshare.net/miyakawataku/bigdecimal-for-money-counting

    • BigDecimal と Money and Currency API を調べた時に参照しました。
  2. org.apache.commons.lang3.builder - Interface Builder
    https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/builder/Builder.html

  3. Groovyで円周率を求めてみた
    http://d.hatena.ne.jp/masanobuimai/20081118/1227014122

  4. Groovy Language Documentation - Decimal literals
    http://docs.groovy-lang.org/latest/html/documentation/#_decimal_literals

    • 小数点が付いている数字は groovy では標準で BigDecimal で処理するそうです。
  5. Apache Maven Project - POM Reference
    https://maven.apache.org/pom.html

目次

  1. ライブラリの仕様を決める
  2. feature/2-issue ブランチを作成する
  3. ksbysample-library-depend-nospring プロジェクトを作成する
  4. Order クラス、OrderBuilder クラスを作成する
  5. テストを作成して動作確認する
  6. Nexus に登録する
  7. ksbysample-webapp-demo プロジェクトから ksbysample-library-depend-nospring ライブラリを利用する
  8. ksbysample-webapp-demo プロジェクトで build.gradle に記述していない org.apache.commons:commons-lang3:3.4 が参照される仕組みとは?
  9. pom ファイルとは何か?

手順

ライブラリの仕様を決める

今回は以下の仕様でライブラリを作成します。

  • Gradle プロジェクトとして作成します。
  • GroupId は ksbysample.library、ArtifactId は ksbysample-library-depend-nospring にします。
  • 依存するライブラリは JDK と org.apache.commons:commons-lang3 とします。
  • org.apache.commons:commons-lang3 の Builder クラスを継承した OrderBuilder クラスを作成します。number, price をフィールドに持つ Order クラスを Builder パターンで生成するクラスです。
  • テストは Spock で実装します。

feature/2-issue ブランチを作成する

  1. GitHub に Issue 2 を作成した後、feature/2-issue ブランチを作成します。

ksbysample-library-depend-nospring プロジェクトを作成する

  1. IntelliJ IDEA の「Welcome to IntelliJ IDEA」ダイアログから「Create New Project」メニューをクリックします。

    f:id:ksby:20160810225409p:plain

  2. 「New Project」ダイアログが表示されます。画面左側の一覧から「Gradle」を選択してから以下の画像の内容を入力後、「Next」ボタンをクリックします。

    f:id:ksby:20160810225536p:plain

  3. GroupId、ArtifactId を入力する画面が表示されます。以下の画像の内容を入力後、「Next」ボタンをクリックします。

    f:id:ksby:20160810225755p:plain

  4. 以下の画像の画面が表示されます。「Create directories for empty content roots automatically」をチェックした後、「Next」ボタンをクリックします。

    f:id:ksby:20160810230019p:plain

  5. Project name と Project location を入力する画面が表示されます。Project location を C:\project-springboot\ksbysample-nexus-repomng\ksbysample-library-depend-nospring に変更した後、「Finish」ボタンをクリックします。

    f:id:ksby:20160810230246p:plain

  6. build.gradle を リンク先の内容 に変更します。変更後、Gradle projects View の左上にある「Refresh all Gradle projects」ボタンをクリックして反映します。

  7. 以下のディレクトリに .gitkeep ファイルを作成します。

    • src/main/groovy
    • src/main/java
    • src/main/resources
    • src/test/groovy
    • src/test/java
    • src/test/resources
  8. commit します。

Order クラス、OrderBuilder クラスを作成する

  1. src/main/java の下に ksbysample.library.dependnospring パッケージを作成します。

  2. src/main/java/ksbysample/library/dependnospring の下に Order.java を作成し、リンク先の内容 に変更します。

  3. src/main/java/ksbysample/library/dependnospring の下に OrderBuilder.java を作成し、リンク先の内容 に変更します。

テストを作成して動作確認する

Spock でテストを作成して動作確認します。

  1. OrderBuilder クラスのソース上で Ctrl+Shift+T を押してコンテキストメニューを表示した後、「Create New Test...」を選択します。

    f:id:ksby:20160811032853p:plain

  2. 「Create Test」ダイアログが表示されます。「Testing library」を「Spock」に変更した後、「OK」ボタンをクリックします。

    f:id:ksby:20160811033050p:plain

  3. 「Choose Destination Directory」ダイアログが表示されます。groovy のディレクトリを選択して「OK」ボタンをクリックします。

    f:id:ksby:20160811033200p:plain

  4. src/test/groovy/ksbysample/library/dependnospring の下に OrderBuilderTest.groovy が作成されますので、リンク先の内容 に変更します。

  5. テストを実行します。def "OrderBuilder(#number, #price) --> #total"() メソッド名の左側の矢印アイコンをクリックしてメニューを表示した後、「Run 'OrderBuilder(#numb...()'」メニューを選択します。

    f:id:ksby:20160811041233p:plain

  6. テストが実行され、全て成功することが確認できました。

    f:id:ksby:20160811041407p:plain

Nexus に登録する

  1. Gradle projects View の uploadArchives タスクをダブルクリックして実行します。Run View に実行結果が表示され、BUILD SUCCESSFUL が表示されました。

    f:id:ksby:20160811042606p:plain

  2. Nexus の管理画面を見ると maven-releases repository に登録されていることが確認できます。

    f:id:ksby:20160811042838p:plain

ksbysample-webapp-demo プロジェクトから ksbysample-library-depend-nospring ライブラリを利用する

  1. ksbysample-library-depend-nospring プロジェクトを閉じて、ksbysample-webapp-demo プロジェクトを開きます。

  2. build.gradle を リンク先の内容 に変更します。変更後、Gradle projects View の左上にある「Refresh all Gradle projects」ボタンをクリックして反映します。

  3. Project View の External Libraries を見ると build.gradle に記述した ksbysample.library:ksbysample-library-depend-nospring:1.0-RELEASE 以外に ksbysample-library-depend-nospring ライブラリが依存している org.apache.commons:commons-lang3:3.4 も表示されていることが確認できます。

    f:id:ksby:20160813055812p:plain

  4. src/main/java/ksbysample/webapp/demo の下に OrderController.java を作成し、リンク先の内容 に変更します。

  5. Gradle projects View から bootRun タスクを実行して Tomcat を起動します。

  6. ブラウザから http://localhost:8080/order/ にアクセスすると、"数量 = 5, 単価 = 2000, 総額 = 10000" の文字列が表示されました。

    f:id:ksby:20160813061602p:plain

  7. Ctrl+F2 を押して Tomcat を停止します。

  8. commmit します。

ksbysample-webapp-demo プロジェクトで build.gradle に記述していない org.apache.commons:commons-lang3:3.4 が参照される仕組みとは?

ksbysample-library-depend-nospring-1.0-RELEASE.jar の中に情報が入っているのかと思い解凍してみると、以下の構造でした。

ksbysample-library-depend-nospring-1.0-RELEASE
├ generated
├ ksbysample
│ └ library
│    └ dependnospring
│       ├ Order.class
│       └ OrderBuilder.class
└ META-INF
   └ MANIFEST.MF

META-INF/MANIFEST.MF かなと思い、中を見てみましたが以下の内容しか書かれていませんでした。jar ファイルの中には依存関係を解決するような情報はないようです。

Manifest-Version: 1.0

Nexus にアップロードされているファイルを見てみます。

f:id:ksby:20160813064124p:plain f:id:ksby:20160813064308p:plain

maven-releases repository の中の ksbysample-library-depend-nospring ライブラリの中を見ると jar 以外に ksbysample-library-depend-nospring-1.0-RELEASE.pom というファイルだけアイコンが異なっていました。このファイルの中を確認してみます。

f:id:ksby:20160813064711p:plain f:id:ksby:20160813064837p:plain f:id:ksby:20160813065038p:plain

ksbysample-library-depend-nospring-1.0-RELEASE.pom ファイルの中に org.apache.commons:commons-lang3:3.4 の記述がありました。おそらく jar ファイル以外にこのファイルもダウンロードされて依存関係が解決されているものと思われます。

pom ファイルとは何か?

  • 以下の URL に POM について説明がありました。プロジェクトの情報や依存するライブラリ等の情報を記載しておくファイルのようです。

ソースコード

ksbysample-library-depend-nospring/build.gradle

group 'ksbysample.library'
version '1.0-RELEASE'

apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'maven'

sourceCompatibility = 1.8
targetCompatibility = 1.8

compileJava.options.compilerArgs = ['-Xlint:all']
compileTestGroovy.options.compilerArgs = ['-Xlint:all']
compileTestJava.options.compilerArgs = ['-Xlint:all']

repositories {
    jcenter()
}

dependencies {
    compile("org.apache.commons:commons-lang3:3.4")
    testCompile("org.spockframework:spock-core:1.0-groovy-2.4")
}

uploadArchives {
    def nexusUrl = "http://localhost:8081"
    def nexusUsername = "admin"
    def nexusPassword = "admin123"

    repositories {
        mavenDeployer {
            repository(url: "${nexusUrl}/repository/maven-releases") {
                authentication(userName: nexusUsername, password: nexusPassword)
            }
            snapshotRepository(url: "${nexusUrl}/repository/maven-snapshots") {
                authentication(userName: nexusUsername, password: nexusPassword)
            }
        }
    }
}
  • 今回は最初から version '1.0-RELEASE' にします。
  • dependencies に compile("org.apache.commons:commons-lang3:3.4") を記述します。

Order.java

package ksbysample.library.dependnospring;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Order {

    private BigDecimal number;

    private BigDecimal price;

    public BigDecimal getNumber() {
        return number;
    }

    public void setNumber(BigDecimal number) {
        this.number = number;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public BigDecimal getTotal() {
        return number.multiply(price)
                .setScale(0, RoundingMode.FLOOR);
    }

}
  • number, price の型を BigDecimal にしているのは Spock でテストを書く時に BigDecimal の場合どうなるのか試すためです。

OrderBuilder.java

package ksbysample.library.dependnospring;

import org.apache.commons.lang3.builder.Builder;

import java.math.BigDecimal;

public class OrderBuilder implements Builder<Order> {

    private Order order;

    public OrderBuilder() {
        this.order = new Order();
    }

    public OrderBuilder number(int number) {
        this.order.setNumber(new BigDecimal(Integer.toString(number)));
        return this;
    }

    public OrderBuilder price(int price) {
        this.order.setPrice(new BigDecimal(Integer.toString(price)));
        return this;
    }

    @Override
    public Order build() {
        return this.order;
    }

}

OrderBuilderTest.groovy

package ksbysample.library.dependnospring

import spock.lang.Specification
import spock.lang.Unroll

class OrderBuilderTest extends Specification {

    @Unroll
    def "OrderBuilder(#number, #price) --> #total"() {
        given:
        Order order = new OrderBuilder()
                .number(number)
                .price(price)
                .build()

        expect:
        order.number == number
        order.price == price
        order.total == total

        where:
        number            | price             || total
        0                 | 1                 || 0
        1                 | 0                 || 0
        1                 | 1                 || 1
        Integer.MAX_VALUE | 1                 || Integer.MAX_VALUE
        1                 | Integer.MAX_VALUE || Integer.MAX_VALUE
        Integer.MAX_VALUE | Integer.MAX_VALUE || 4611686014132420609
    }

}
  • order.price 等は BigDecimal 型を返しますが、groovy だと上の書き方で動作しており BigDecimal を特に意識しなくてよいので楽でした。

ksbysample-webapp-demo/build.gradle

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')

    compile('ksbysample.library:ksbysample-library-simpleutils:1.0-RELEASE')
    compile('ksbysample.library:ksbysample-library-depend-nospring:1.0-RELEASE')
}
  • dependencies に compile('ksbysample.library:ksbysample-library-depend-nospring:1.0-RELEASE') を追加します。

OrderController.java

package ksbysample.webapp.demo;

import ksbysample.library.dependnospring.Order;
import ksbysample.library.dependnospring.OrderBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/order")
public class OrderController {

    @RequestMapping
    @ResponseBody
    public String index() {
        Order order = new OrderBuilder()
                .number(5)
                .price(2000)
                .build();
        return String.format("数量 = %d, 単価 = %d, 総額 = %d"
                , order.getNumber().intValue()
                , order.getPrice().intValue()
                , order.getTotal().intValue());
    }

}

履歴

2016/08/13
初版発行。