<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Kotlin | みんたく</title>
	<atom:link href="https://mintaku-blog.net/category/develop/kotlin/feed/" rel="self" type="application/rss+xml" />
	<link>https://mintaku-blog.net</link>
	<description>みんたくの技術ブログ</description>
	<lastBuildDate>Sat, 16 Jul 2022 02:03:24 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.11</generator>

<image>
	<url>https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2018/06/cropped-ipad-820272_640.jpg?fit=32%2C32&#038;ssl=1</url>
	<title>Kotlin | みんたく</title>
	<link>https://mintaku-blog.net</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">144480658</site>	<item>
		<title>Kotlinにおけるclassとdata classの違い</title>
		<link>https://mintaku-blog.net/kotlin-data-class/</link>
					<comments>https://mintaku-blog.net/kotlin-data-class/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Sat, 16 Jul 2022 02:03:23 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2222</guid>

					<description><![CDATA[<p>Kotlinにおけるclassとdata classの違いについてまとめました。 data classとは data classはKotlin特有の仕様で、 …</p>
The post <a href="https://mintaku-blog.net/kotlin-data-class/">Kotlinにおけるclassとdata classの違い</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>Kotlinにおけるclassとdata classの違いについてまとめました。</p>
<h2>data classとは</h2>
<p>data classはKotlin特有の仕様で、データを保持するだけのクラスはdataマークをつけることで定義されます。</p>
<p>data classとは特に何かしらの処理を行うわけではないが、データだけ持っているクラスを作ることができます。つまり、データだけを持ったクラスが生成できます。</p>
<p>data classとして成り立たせるには、最低1つのプライマリコンストラクタ引数を持たせる必要があります。</p><pre class="crayon-plain-tag">data class hoge()

// Data class must have at least one primary constructor parameter</pre><p>また、valやvarでイミュータブルかどうかを明示すること、抽象クラスやopenクラス、sealedクラスやinnerクラスでないことが必要です。</p>
<p>&nbsp;</p>
<h2>data classの実装</h2>
<p>data classは、dataという修飾子をclassの前につけるだけでdata classとして扱われます。</p><pre class="crayon-plain-tag">data class User(val userId: number, val name: String)</pre><p>&nbsp;</p>
<h2>data classとclassの違い</h2>
<p>data classとclassの違いは、data classの方はデータを扱うのに便利なメソッドが自動で実装されます。</p>
<p>元々全クラスの継承元、Anyクラスが持つ</p>
<ul>
<li>toString: 型名とプロパティ名、値を文字列として返す</li>
<li>hashCode: プロパティの値に基づくハッシュ値を返す</li>
<li>equals: オブジェクトの同値性を調べ、Booleanを返す</li>
</ul>
<p>data classは上記に加え、以下が実装されています。</p>
<ul>
<li>copy: オブジェクトのコピーを返す</li>
<li>componentN: N番目のプロパティの値を返す</li>
</ul>
<p>&nbsp;</p>
<h2>data classで使えるcopyメソッドとcomponentNメソッド</h2>
<h3>copyメソッド</h3>
<p>copyメソッドを使うことで同値の別インスタンスを生成できます。その際プロパティの値を変更することができます。</p>
<p>「プロパティの一部だけ値を変更して、新たなオブジェクトを作る」といった場合はcopyを使うと、全てのプロパティを入力せずに済みます。</p>
<p>例としてcopyメソッドを使って、nameプロパティのみ変更したインスタンスを作成します。</p><pre class="crayon-plain-tag">data class Department(val name: String, val address: String, val phoneNumber: String)

val department = Department("品質管理", ”東京都”, “090-1111-2222”)
val changedDepartment = department.copy(name = "生産管理")

println(changedDepartment.name)
// 生産管理

println(changedDepartment.address)
// 東京都</pre><p>&nbsp;</p>
<h3>componentNメソッド</h3>
<p>クラスに宣言したプロパティにcomponent1、component2&#8230;でアクセスすることができます。</p><pre class="crayon-plain-tag">data class Department(val name: String, val address: String, val phoneNumber: String)

val department = Department("品質管理", ”東京都”, “090-1111-2222”)

val first = department.component1()
val second = department.component2()

println(first)
// 品質管理

println(second)
// 東京都</pre><p></p>The post <a href="https://mintaku-blog.net/kotlin-data-class/">Kotlinにおけるclassとdata classの違い</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-data-class/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2222</post-id>	</item>
		<item>
		<title>KotlinにおけるFactoryメソッドの実装方法と使う理由</title>
		<link>https://mintaku-blog.net/kotlin-factory-method/</link>
					<comments>https://mintaku-blog.net/kotlin-factory-method/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Sun, 10 Jul 2022 15:01:14 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2220</guid>

					<description><![CDATA[<p>KotlinにおけるFactoryメソッドの実装方法と使う理由についてまとめました。 Factoryメソッドとは Factoryメソッドとはデザインパターン …</p>
The post <a href="https://mintaku-blog.net/kotlin-factory-method/">KotlinにおけるFactoryメソッドの実装方法と使う理由</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>KotlinにおけるFactoryメソッドの実装方法と使う理由についてまとめました。</p>
<h2>Factoryメソッドとは</h2>
<p>Factoryメソッドとはデザインパターンの1つで、より柔軟にオブジェクトを生成することを目的とするものです。</p>
<p>インスタンスの作り方をスーパークラスで定め、具体的な処理をサブクラスで行います。</p>
<p>&nbsp;</p>
<h2>KotlinでFactoryメソッドを実装する方法</h2>
<p>Factoryメソッドを実装する方法はいくつかありますが、以下のcompanion objectを使用した方法が推奨されています。</p>
<p>メソッド名としては以下が慣例的によく使われるため、以下のメソッド名を使うのが良さそうです。</p>
<ul>
<li>from: 返り値がその型そのものの場合</li>
<li>of: 複数引数を受け取りそれらを集約するものを返す場合</li>
</ul>
<p></p><pre class="crayon-plain-tag">data class User(val id: Int, val Name: String) {
  companion object {
    fun from(userId: number, name: String): User {
      return User(userId, name)
    }
  }
}</pre><p>&nbsp;</p>
<p>使うときは以下のようにFactoryメソッドを呼び出してインスタンスを生成します。</p><pre class="crayon-plain-tag">val userId = 1
val name = “hoge”
val user = User.from(userId, name)</pre><p></p>
<h3>companion objectとは</h3>
<p>ちょっと寄り道ですが、companion objectについて説明します。</p>
<p>companion objectはクラス内に作成されるSingletonのことです。Singletonとは、生成するインスタンスの数を1つに制限するデザインパターンです。</p>
<p>Kotlinでは、classの代わりに objectキーワードを使用するだけでSingletonが作成でき、objectキーワードの前にcompanion修飾子を付与することでクラスに属するSingletonが作成できます。</p>
<p>これをcompanion objectと呼び、companion objectは1クラス内に1つだけ宣言可能です。</p>
<p>Kotlinにはstatic修飾子がないので、companion objectはstaticなフィールドやメソッドが必要なときの代替手段として利用されることがあります。</p>
<p>&nbsp;</p>
<h2>なぜコンストラクタよりFactoryメソッドの方が良いのか</h2>
<p>オブジェクトを生成するのになぜコンストラクタよりFactoryメソッドが良いのか、いくつかその理由を挙げていきます。</p>
<h3>Factoryメソッドにすることでメソッド名がつけられる</h3>
<p>先ほど紹介したように、Factoryメソッドならメソッド名をつけられるため、生成方法ごとにわかりやすい名前をつけられます。</p><pre class="crayon-plain-tag">data class User(val id: Int, val Name: String) {
  companion object {
    fun from(userId: number, name: String): User {
      return User(userId, name)
    }
  }
}</pre><p></p>
<h3>返り値にサブタイプを指定できる</h3>
<p>以下の例のように、listOfメソッドの返り値はList型になっており、Listはinterfaceであるため、Listのサブタイプを返すことができます。</p><pre class="crayon-plain-tag">val hogeList: List&lt;int&gt; = listOf(1, 2, 3)</pre><p></p>
<h3>コンストラクタと異なる引数を渡すことができる</h3>
<p>Factoryメソッドならコンストラクタと異なる引数を渡すことができます。</p><pre class="crayon-plain-tag">data class User(val id: Int, val Name: String) {
  companion object {
    fun of(userId: number, config: Config): User {
      return User(userId, config.defaultName)
    }
  }
}</pre><p>&nbsp;</p>
<h2>参考</h2>
<p><iframe loading="lazy" title="KotlinによるFactoryメソッド実装パターン" id="talk_frame_574528" class="speakerdeck-iframe" src="//speakerdeck.com/player/f200fbfc2f374c91ada3b7bfb35b0183" width="800" height="600" style="aspect-ratio:800/600; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe></p>
<p><a href="https://qiita.com/doyaaaaaken/items/0c99da9efa7d724a0d80" target="_blank" rel="noopener">https://qiita.com/doyaaaaaken/items/0c99da9efa7d724a0d80</a></p>
<p><a href="https://qiita.com/tkhs0604/items/261e94a42b7097dfd204" target="_blank" rel="noopener">https://qiita.com/tkhs0604/items/261e94a42b7097dfd204</a></p>
<p>&nbsp;</p>The post <a href="https://mintaku-blog.net/kotlin-factory-method/">KotlinにおけるFactoryメソッドの実装方法と使う理由</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-factory-method/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2220</post-id>	</item>
		<item>
		<title>Kotlin + Spring Boot + Spring JPA + MySQLでCRUD操作する</title>
		<link>https://mintaku-blog.net/kotlin-spring-jpa/</link>
					<comments>https://mintaku-blog.net/kotlin-spring-jpa/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Fri, 03 Jun 2022 06:56:27 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2207</guid>

					<description><![CDATA[<p>https://mintaku-blog.net/kotlin-spring-boot/ 前回スタブで取得していたデータをちゃんとセットアップしてDBから取 …</p>
The post <a href="https://mintaku-blog.net/kotlin-spring-jpa/">Kotlin + Spring Boot + Spring JPA + MySQLでCRUD操作する</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<div class="ys-blog-card">
	<div class="ys-blog-card__container">
					<figure class="ys-blog-card__image">
				<img width="560" height="315" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2022/03/0123e5de95cd96b6ad406d1934472974.png?fit=560%2C315&amp;ssl=1" class="attachment-large size-large wp-post-image" alt="" loading="lazy" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2022/03/0123e5de95cd96b6ad406d1934472974.png?w=560&amp;ssl=1 560w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2022/03/0123e5de95cd96b6ad406d1934472974.png?resize=300%2C169&amp;ssl=1 300w" sizes="(max-width: 560px) 100vw, 560px" data-attachment-id="2195" data-permalink="https://mintaku-blog.net/kotlin-spring-boot/help-raise-heart-disease-awareness%e3%81%ae%e3%82%b3%e3%83%92%e3%82%9a%e3%83%bc%e3%81%ae%e3%82%b3%e3%83%92%e3%82%9a%e3%83%bc%e3%81%ae%e3%82%b3%e3%83%92%e3%82%9a%e3%83%bc-10-3/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2022/03/0123e5de95cd96b6ad406d1934472974.png?fit=560%2C315&amp;ssl=1" data-orig-size="560,315" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Help raise Heart Disease Awarenessのコピーのコピーのコピー (10)" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2022/03/0123e5de95cd96b6ad406d1934472974.png?fit=300%2C169&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2022/03/0123e5de95cd96b6ad406d1934472974.png?fit=560%2C315&amp;ssl=1" />			</figure>
				<div class="ys-blog-card__text">
			<p class="ys-blog-card__title">
				<a class="ys-blog-card__link" href="https://mintaku-blog.net/kotlin-spring-boot/">Kotlin+Spring Bootで簡単なAPIをClean Architectureで実装してみた</a>
			</p>
							<div class="ys-blog-card__dscr">
					Kotlin + Spring Bootを触ってみたので、Clean Archi&hellip;				</div>
										<div class="ys-blog-card__domain">mintaku-blog.net</div>
					</div>
	</div>
</div>

<p>前回スタブで取得していたデータをちゃんとセットアップしてDBから取得できるようにします。またTODOアプリっぽいAPIを実装し、CRUD操作できるようにします。</p>
<h2>DockerでMySQL導入し、Spring BootからDB接続できるようにする</h2>
<p>まずは既存のAPIにMySQLを導入します。今回はDockerでMySQLを選択しました。</p>
<p>M1 Macで起動するためにplatform: linux/x86_64を追加しています。volumesでコンテナ起動時のデータセットアップとMySQLの設定ファイルを読み込んでいます。</p>
<p>・docker-compose.yml</p><pre class="crayon-plain-tag">version: '3'
services:
  mysql:
    platform: linux/x86_64
    image: mysql:5.7
    container_name: mysql_sample
    environment:
      MYSQL_ROOT_PASSWORD: mysql
      MYSQL_DATABASE: sample
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
    volumes:
      - ./initdb.d:/docker-entrypoint-initdb.d
      - ./my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - 3306:3306</pre><p>&nbsp;</p>
<p>my.cnfでMySQLの設定を行います。my.cnfにcharacter-setを追加しているのはMySQLに日本語のデータを追加した際に文字化けになったのでその対応です。</p>
<p>参考：https://qiita.com/Asaiii12/items/69e4420d06d91374428a</p>
<p>・my.cnf</p><pre class="crayon-plain-tag">[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
explicit-defaults-for-timestamp=1
general-log=1
general-log-file=/var/log/mysql/mysqld.log

[client]
default-character-set=utf8mb4</pre><p>&nbsp;</p>
<p>init.sqlではコンテナ作成時にテーブルの作成とデータ投入をしています。volumsで./initdb.d:/docker-entrypoint-initdb.dを指定すると、指定ディレクトリ配下のSQLが実行されるようになっています。</p>
<p>・initdb.d/init.sql</p><pre class="crayon-plain-tag">USE sample;
DROP TABLE IF EXISTS tasks;
CREATE TABLE tasks
(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(100) NULL,
  `content` varchar(500) NULL,
  PRIMARY KEY (id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

INSERT INTO tasks (id, title, content) VALUES (1, "タイトル1", "内容1"), (2, "タイトル2", "内容2");</pre><p>&nbsp;</p>
<p>全て完了したらDockerを立ち上げます。</p><pre class="crayon-plain-tag">$ docker compose up</pre><p>以下のコマンドで立ち上げたMySQLに接続し、実際にDBやテーブルが作成できるかを確認します。</p><pre class="crayon-plain-tag">$ mysql -h 0.0.0.0 -u docker -p</pre><p>&nbsp;</p>
<p>アプリケーションからDB接続できるようにするためにapplication.propertiesにDB接続情報を追加します。</p>
<p>・src/main/resources/application.properties</p><pre class="crayon-plain-tag">spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://0.0.0.0:3306/sample
spring.datasource.username=docker
spring.datasource.password=docker</pre><p>&nbsp;</p>
<h2>Spring JPAの導入</h2>
<p>Spring JPAを導入するためbuild.gradle.ktsのdependenciesに以下を追加し、Gradleをリビルドします。</p>
<p>・build.gradle.kts</p><pre class="crayon-plain-tag">dependencies {
  ...

  implementation("org.springframework.boot:spring-boot-starter-data-jpa")
}
</pre><p>&nbsp;</p>
<h2>Entityの作成</h2>
<p>Entityで定義されたテーブル情報が、自動インサートの対象になります。今回はTODOリストを意識しているのでidとtitle、contentのカラムを定義しています。</p>
<p>・entity/Task.kt</p><pre class="crayon-plain-tag">package com.example.entity

import javax.persistence.*

@Entity
@Table(name = "tasks")
data class Task (
  @Id
  @GeneratedValue
  val id: Long = 0,

  @Column(name = "title", length = 100, nullable = false)
  val title: String = "",

  @Column(name = "content", length = 500)
  val content: String? = null,
)</pre><p>&nbsp;</p>
<h2>Repositoryの作成</h2>
<p>JPA用のインターフェースを定義します。今回はそれぞれSQLを書いて定義しています。</p>
<p>・repository/TaskRepository.kt</p><pre class="crayon-plain-tag">package com.example.repository

import com.example.entity.Task
import org.apache.ibatis.annotations.*
import org.springframework.stereotype.Repository

@Mapper
@Repository
interface TaskRepository {
  @Select("SELECT * FROM tasks;")
  fun findAll(): List&lt;Task&gt;

  @Select("SELECT * FROM tasks where id = #{id};")
  fun findById(id: Long): Task

  @Insert("INSERT INTO tasks(title, content) values(#{title}, #{content});")
  fun insertTask(title: String, content: String?): Int

  @Update("UPDATE tasks SET title=#{title}, content=#{content} WHERE id=#{id}")
  fun updateTask(id: Long, title: String, content: String?): Int

  @Delete("DELETE FROM tasks WHERE id=#{id}")
  fun deleteTask(@Param("id") id: Long): Int
}</pre><p>&nbsp;</p>
<h2>DriverでRepositoryで定義したメソッドを呼び出す</h2>
<p>DriverでRepositoryで定義したメソッドを呼び出し、実際にDB操作します。curlなどで確認しCRUDできていることが確認できれば完了です。</p>
<p>・driver/TaskDriver.kt</p><pre class="crayon-plain-tag">package com.example.driver

import com.example.repository.TaskRepository
import com.fasterxml.jackson.annotation.JsonCreator
import org.springframework.stereotype.Component

@Component
class TaskDriver(private val taskRepository: TaskRepository) {
  fun getTasks(): TasksJson {
    return taskRepository.findAll().map {
      TaskJson(it.id, it.title, it.content)
    }.let(::TasksJson)
  }

  fun getTask(taskId: Long): TaskJson {
    return taskRepository.findById(taskId)?.let {
      TaskJson(it.id, it.title, it.content)
    }
  }

  fun createTask(title: String, content: String?): Int {
    return taskRepository.insertTask(title, content)
  }

  fun updateTask(taskJson: TaskJson): Int {
    return taskRepository.updateTask(taskJson.id, taskJson.title, taskJson.content)
  }

  fun deleteTask(taskId: Long): Int {
    return taskRepository.deleteTask(taskId)
  }
}

data class TasksJson @JsonCreator constructor(
  val list: List&lt;TaskJson&gt;
)

data class TaskJson @JsonCreator constructor(
  val id: Long,
  val title: String,
  val content: String?
)</pre><p></p>The post <a href="https://mintaku-blog.net/kotlin-spring-jpa/">Kotlin + Spring Boot + Spring JPA + MySQLでCRUD操作する</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-spring-jpa/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2207</post-id>	</item>
		<item>
		<title>Kotlin + Spring Boot + JUnit5 + MockKでUnitテストを書く</title>
		<link>https://mintaku-blog.net/kotlin-junit/</link>
					<comments>https://mintaku-blog.net/kotlin-junit/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Tue, 10 May 2022 13:56:00 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2197</guid>

					<description><![CDATA[<p>前回実装したClean Architecture APIのUnitテストを書いていきます。 JUnit JUnitとはJavaで開発されたプログラムにおいて …</p>
The post <a href="https://mintaku-blog.net/kotlin-junit/">Kotlin + Spring Boot + JUnit5 + MockKでUnitテストを書く</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>前回実装したClean Architecture APIのUnitテストを書いていきます。</p>
<h2>JUnit</h2>
<p>JUnitとはJavaで開発されたプログラムにおいてユニットテストの自動化を行うためのフレームワークです。</p>
<h3>よく使いそうなアノテーション</h3>
<h4>@Test</h4>
<p>メソッドに付与することでJUnitにテストメソッドであることを認識します。</p>
<h4>@DisplayName</h4>
<p>テストの表示名を設定できます。</p>
<h4>@BeforeEach</h4>
<p>付与されたメソッドは、各テストメソッド実行前に@BeforeEachアノテーションがついたメソッドが実行されます。JUnit 4の@Beforeと同じです。</p>
<h4>@Disabled</h4>
<p>@Disabled はクラスまたはメソッドに付与してテストを実行させないようにすることができます。JUnit4における@Ignoreに相当します</p>
<p>JUnit5のアノテーション一覧は以下の公式で見ることができます。</p>

<div class="ys-blog-card">
	<div class="ys-blog-card__container">
				<div class="ys-blog-card__text">
			<p class="ys-blog-card__title">
				<a class="ys-blog-card__link" href="https://oohira.github.io/junit5-doc-jp/user-guide/">JUnit 5 ユーザーガイド</a>
			</p>
										<div class="ys-blog-card__domain">oohira.github.io</div>
					</div>
	</div>
</div>

<p>&nbsp;</p>
<h2>MockK</h2>
<p>MockKとは Kotlin用のモックライブラリです。</p>

<div class="ys-blog-card">
	<div class="ys-blog-card__container">
					<figure class="ys-blog-card__image">
				<img src="https://i0.wp.com/mockk.io/doc/stats-shared.png?w=800&#038;ssl=1" alt="" data-recalc-dims="1">			</figure>
				<div class="ys-blog-card__text">
			<p class="ys-blog-card__title">
				<a class="ys-blog-card__link" href="https://mockk.io/">MockK | mocking library for Kotlin</a>
			</p>
							<div class="ys-blog-card__dscr">
					Provides DSL to mock behavior. Built fro&hellip;				</div>
										<div class="ys-blog-card__domain">mockk.io</div>
					</div>
	</div>
</div>

<h3>every</h3>
<p>everyを使うと特定のモックインスタンスが呼ばれた時に指定した値を返却します。</p>
<h3>verify</h3>
<p>verifyを使うとメソッドが指定した引数で呼び出されたかを確認できます。</p>
<h3>よく使いそうなアノテーション</h3>
<h4>@MockK</h4>
<p>モックインスタンスとしてインジェクションしたい場合に使用します。</p>
<h4>@SpyK</h4>
<p>Spy用のインスタンスとしてインジェクションしたい場合に使用します。</p>
<p>Spyはオブジェクトを実際のコードで動かしつつ、メソッドの引数や呼び出し回数、戻り値などを検証するために使用します。</p>
<p>注意点としては、アノテーションを利用して初期化する際には@Spyk var hoge = Hoge()のようにvarかつインスタンス生成する必要があります。</p>
<h4>@InjectMockKs</h4>
<p>該当オブジェクトのもつ属性に対してインジェクトしたい場合に使用します。</p>
<p>&nbsp;</p>
<h2>ControllerのUnitテスト</h2>
<p>@ExtendWith(SpringExtension::class)でSpring拡張機能をインクルードしていましたが、調べたら@SpringBootTestアノテーションを使用している場合は@ExtendWith(SpringExtension::class)を付与する必要はなくなったようです。</p>
<p>参考：https://github.com/spring-projects/spring-boot/issues/13739</p>
<p>・TaskControllerTest.kt</p><pre class="crayon-plain-tag">package com.example.controller

import com.example.domain.*
import com.example.usecase.TaskUseCase
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.test.web.servlet.setup.MockMvcBuilders

@SpringBootTest
class TaskControllerTest {
  @InjectMockKs
  private lateinit var taskController: TaskController

  @MockK
  private lateinit var taskUseCase: TaskUseCase

  private lateinit var mockTaskController: MockMvc

  @BeforeEach
  fun setup() {
    mockTaskController = MockMvcBuilders.standaloneSetup(taskController).build()
  }

  @Test
  @DisplayName("TasksをTasksJsonに変換する")
  fun convertTasksJsonTest() {
    val target = Tasks(listOf(Task(Title("title"), Content("content")), Task(Title("title2"), Content("content2"))))
    val expected = TasksJson(listOf(TaskJson("title", "content"), TaskJson("title2", "content2")))

    assertEquals(expected, target.toJson())
  }

  @Test
  @DisplayName("TaskをTaskJsonに変換する")
  fun convertTaskJsonTest() {
    val target = Task(Title("title"), Content("content"))
    val expected = TaskJson("title", "content")

    assertEquals(expected, target.toJson())
  }

  @Test
  @DisplayName("task一覧を取得する")
  fun getTasksTest() {
    val tasks = Tasks(listOf(Task(Title("title"), Content("content")), Task(Title("title2"), Content("content2"))))
    every { taskUseCase.getTasks() } returns tasks

    mockTaskController.get("/api/tasks").andExpect {
      status { isOk() }
      content {
        contentType(MediaType.APPLICATION_JSON)
        json("""{"tasks":[{"title":"title","content":"content"},{"title":"title2","content":"content2"}]}""")
      }
    }

    verify { taskUseCase.getTasks() }
  }

  @Test
  @DisplayName("taskを1つ取得する")
  fun getTaskTest() {
    val taskId = TaskId(1)
    val task = Task(Title("title"), Content("content"))
    every { taskUseCase.getTask(taskId) } returns task

    mockTaskController.get("/api/tasks/1").andExpect {
      status { isOk() }
      content {
        contentType(MediaType.APPLICATION_JSON)
        json("""{"title":"title","content":"content"}""")
      }
    }

    verify { taskUseCase.getTask(taskId) }
  }
}</pre><p>&nbsp;</p>
<h3>HTTPメソッドへのテスト</h3>
<p>MockMvcBuilders.standaloneSetup()でControllerの動作を再現するための準備をします。</p>
<p>参考：https://terasolunaorg.github.io/guideline/5.4.1.RELEASE/ja/UnitTest/ImplementsOfUnitTest/UsageOfLibraryForTest.html#mockmvc</p>
<p>@BeforeEachアノテーションを付けて、全ての@Testの前に実行させます。以降、このmockMvcインスタンスを利用して、仮想のリクエストを発生させテストを実行します。</p>
<p>今回はテスト対象のTaskControllerを指定して、mockMvcを生成しています。</p><pre class="crayon-plain-tag">@InjectMockKs

private lateinit var taskController: TaskController

@MockK
private lateinit var taskUseCase: TaskUseCase

…

@BeforeEach
fun setup() {
  mockTaskController = MockMvcBuilders.standaloneSetup(taskController).build()
}</pre><p>&nbsp;</p>
<p>テストしたいPath(今回の場合はGET /api/tasks)を指定し、andExceptメソッドでレスポンスのテストを行います。</p>
<p>今回はHTTPステータスコードのテストなのでstatus()を使います。ステータスコード200はstatus().isOkでテストできます。代表的なステータスコードは以下の通りです。</p>
<ul>
<li>200: status().isOk()</li>
<li>308: status().isPermanentRedirect()</li>
<li>404: status().isNotFound()</li>
<li>403: status().isForbidden()</li>
<li>503: status().isServiceUnavailable()</li>
</ul>
<p>あとはcontent()でレスポンスの形と中身を見ています。今回はREST APIなのでJSON形式であることJSONの中身が正しいことをアサートしています。</p>
<p>また、Controllerないのメソッドにおいて、該当のuseCaseメソッドが呼ばれたこともテストしています。</p><pre class="crayon-plain-tag">fun getTasksTest() {
  val tasks = Tasks(listOf(Task(Title("title"), Content("content")), Task(Title("title2"), Content("content2"))))
  every { taskUseCase.getTasks() } returns tasks

  mockTaskController.get("/api/tasks").andExpect {
    status { isOk() }
    content {
      contentType(MediaType.APPLICATION_JSON)
      json("""{"tasks":[{"title":"title","content":"content"},{"title":"title2","content":"content2"}]}""")
    }
  }

  verify { taskUseCase.getTasks() }
}</pre><p>&nbsp;</p>
<h3>ドメインからJSONへの変換テスト</h3>
<p>ControllerではUseCaseから返ってきたドメインをレスポンスの形であるJSONに変換しているため、そのテストも行っています。</p>
<p>今回は各ドメインにtoJson()というメソッドを生やしているので、そのメソッドを実行してちゃんとドメインからJSONに変換されているかをアサートしています。</p>
<p>assertEquals()で値が等しいかを確認しています。左が期待値で右が実測値を入れます。</p><pre class="crayon-plain-tag">fun convertTasksJsonTest() {
  val target = Tasks(listOf(Task(Title("title"), Content("content")), Task(Title("title2"), Content("content2"))))
  val expected = TasksJson(listOf(TaskJson("title", "content"), TaskJson("title2", "content2")))

  assertEquals(expected, target.toJson())
}</pre><p>&nbsp;</p>
<h2>UseCaseのUnitテスト</h2>
<p>UseCaseのテストではPortのメソッドを呼び出して、その返り値が正しいかをアサートしています。今回は簡素なAPIなので特にUseCaseでロジック挟んでおらず、シンプルなUnitテストになっています。</p>
<p>・TaskUseCaseTest.kt</p><pre class="crayon-plain-tag">package com.example.usecase

import com.example.domain.Task
import com.example.domain.TaskId
import com.example.domain.Tasks
import com.example.port.TaskPort
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.springframework.boot.test.context.SpringBootTest

@SpringBootTest
class TaskUseCaseTest {
  @InjectMockKs
  private lateinit var target: TaskUseCase

  @MockK
  lateinit var taskPort: TaskPort

  @Test
  @DisplayName("task一覧を取得する")
  fun getTasksTest() {
    val expected = mockk&lt;Tasks&gt;()

    every { taskPort.getTasks() } returns expected

    assertEquals(expected, target.getTasks())

    verify { taskPort.getTasks() }
  }

  @Test
  @DisplayName("taskを1つ取得する")
  fun getTaskTest() {
    val taskId = mockk&lt;TaskId&gt;()
    val expected = mockk&lt;Task&gt;()

    every { taskPort.getTask(taskId) } returns expected

    assertEquals(expected, target.getTask(taskId))

    verify { taskPort.getTask(taskId) }
  }
}</pre><p>&nbsp;</p>
<h2>GatewayのUnitテスト</h2>
<p>GatewayではDriverメソッドを呼び出し、その返り値をアサートしています。またGatewayではDriverで受け取ったプリミティブなJSONオブジェクトをドメインに変換する処理をしているため、変換メソッドのテストも追加しています。</p>
<p>・TaskGatewayTest.kt</p><pre class="crayon-plain-tag">package com.example.gateway

import com.example.domain.*
import com.example.driver.TaskDriver
import com.example.driver.TaskJson
import com.example.driver.TasksJson
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest

@SpringBootTest
class TaskGatewayTest {
  @InjectMockKs
  private lateinit var target: TaskGateway

  @MockK
  lateinit var taskDriver: TaskDriver

  @Test
  @DisplayName("task一覧を取得する")
  fun getTasksTest() {
    val tasksJson = TasksJson(listOf(TaskJson("title", "content"), TaskJson("title2", "content2")))
    val expected = Tasks(listOf(Task(Title("title"), Content("content")), Task(Title("title2"), Content("content2"))))

    every { taskDriver.getTasks() } returns tasksJson

    assertEquals(expected, target.getTasks())

    verify { taskDriver.getTasks() }
  }

  @Test
  @DisplayName("TasksJsonをTasksに変換する")
  fun convertToTasks() {
    val target = TasksJson(listOf(TaskJson("title", "content"), TaskJson("title2", "content2")))
    val expected = Tasks(listOf(Task(Title("title"), Content("content")), Task(Title("title2"), Content("content2"))))

    assertEquals(expected, target.toTasks())
  }

  @Test
  @DisplayName("taskを1つ取得する")
  fun getTaskTest() {
    val taskJson = TaskJson("title", "content")
    val taskId = TaskId(1)
    val expected = Task(Title("title"), Content("content"))

    every { taskDriver.getTask(taskId.value) } returns taskJson

    assertEquals(expected, target.getTask(taskId))

    verify { taskDriver.getTask(taskId.value) }
  }

  @Test
  @DisplayName("TaskJsonをTaskに変換する")
  fun convertToTask() {
    val target = TaskJson("title", "content")
    val expected = Task(Title("title"), Content("content"))

    assertEquals(expected, target.toTask())
  }
}

</pre><p>&nbsp;</p>
<h2>MockKでlateinitプロパティが初期化されない問題</h2>
<p>springのMockKだとうまくいくのにMockKだと以下のエラーが出る問題がありました。</p><pre class="crayon-plain-tag">kotlin.UninitializedPropertyAccessException: lateinit property hoge has not been initialized</pre><p>調べてみるとinitメソッドで解決できそうでしたので、実際やってみたらうまくいきました。</p>
<p>参考：https://github.com/mockk/mockk/issues/546</p>
<p>以下のように@BeforeEachを追加するだけです。テスト実行前にMockKAnnotations.initでモックインスタンスをインジェクションすることで解決できます。</p><pre class="crayon-plain-tag">@BeforeEach
  fun init() {
  MockKAnnotations.init(this)
}</pre><p></p>The post <a href="https://mintaku-blog.net/kotlin-junit/">Kotlin + Spring Boot + JUnit5 + MockKでUnitテストを書く</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-junit/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2197</post-id>	</item>
		<item>
		<title>Kotlin+Spring Bootで簡単なAPIをClean Architectureで実装してみた</title>
		<link>https://mintaku-blog.net/kotlin-spring-boot/</link>
					<comments>https://mintaku-blog.net/kotlin-spring-boot/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Sun, 03 Apr 2022 02:50:22 +0000</pubDate>
				<category><![CDATA[アーキテクチャ]]></category>
		<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2182</guid>

					<description><![CDATA[<p>Kotlin + Spring Bootを触ってみたので、Clean ArchitectureでちょっとしたAPIを作ってみました。 Kotlin: 1.6 …</p>
The post <a href="https://mintaku-blog.net/kotlin-spring-boot/">Kotlin+Spring Bootで簡単なAPIをClean Architectureで実装してみた</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>Kotlin + Spring Bootを触ってみたので、Clean ArchitectureでちょっとしたAPIを作ってみました。</p>
<ul>
<li>Kotlin: 1.6.10</li>
<li>SpringBoot: 2.4.4</li>
</ul>
<h2>Spring BootでのDI</h2>
<p>そもそもDIとはDependeny Injectionの略で依存性の注入という意味です。DIはオブジェクト間に生じる依存関係をオブジェクト内のコードに直接記述せず、外部から何らかの形で与えるようにする手法です。</p>
<h3>@Component</h3>
<p>クラスにComponentアノテーションを付与するとDIの対象であることを表します。<br />
そのクラスをDIコンテナが管理してくれるようになります。</p>
<p>他にも@Controllerや@Serviceがありますが、以下の使い分けをします。</p>
<ul>
<li>@Controller： MVCでコントローラー層のクラスに付与</li>
<li>@Service： MVCでサービス層のクラスに付与</li>
<li>@Repository： MVCでデータ層のクラスに付与</li>
<li>@Component： MVCに限らず、DIで利用したいクラスへ付与する</li>
</ul>
<h3>@Bean</h3>
<p>付与した関数で返却したインスタンスがDIコンテナに登録され、そのインスタンスをDIで使用できるようになります。</p>
<p>@Componentと@Beanの使い分けは以下の記事が参考になりました。</p>

<div class="ys-blog-card">
	<div class="ys-blog-card__container">
					<figure class="ys-blog-card__image">
				<img src="https://i0.wp.com/www.greptips.com/images/ogp/1318.png?w=800&#038;ssl=1" alt="" data-recalc-dims="1">			</figure>
				<div class="ys-blog-card__text">
			<p class="ys-blog-card__title">
				<a class="ys-blog-card__link" href="https://www.greptips.com/posts/1318/">Spring Bootの@Componentと@Beanの違い - grep Tips *</a>
			</p>
							<div class="ys-blog-card__dscr">
					まずは結論から SpringのDIコンテナに管理してもらいたいクラスが、自分で作&hellip;				</div>
										<div class="ys-blog-card__domain">www.greptips.com</div>
					</div>
	</div>
</div>

<h3>@Autowired</h3>
<p>注入されるフィールドに付けます。</p>
<p>DIコンテナはAutowiredアノテーションを付けたフィールドに対して、合致するオブジェクトを探してインジェクションします。</p>
<h4>lateinit var</h4>
<p>このフィールドへのインジェクションは変数の読み込みと同時に初期化されるのではなく、後からインジェクションされるためvar定義しておく必要があります。</p>
<p>&nbsp;</p>
<h2>Clean ArchitectureでTODOアプリを意識したAPIを実装してみる</h2>
<p>Clean ArchitectureでTODOアプリを意識したAPIを実装してみました。といってもDBも用意せずスタブみたいな感じにしています。メソッドもgetTasks()とgetTask()だけでちょっとしたAPIとなっています。</p>
<h3>Enterprise Business Rules</h3>
<p>Enterprise Business Rulesではアプリケーション全体の最重要ビジネスルールをカプセル化したドメインを格納しています。</p>
<p>今回はTODOアプリを意識しているので、タスクIDとタイトル、コンテンツを含むTaskドメインとListとで持つTasksドメインを作っています。</p>
<p>・Task.kt</p><pre class="crayon-plain-tag">package com.example.domain

data class TaskId(val value: Int)

data class Title(val value: String)

data class Content(val value: String)

data class Task(val title: Title, val content: Content)

data class Tasks(val list: List&lt;Task&gt;)</pre><p>&nbsp;</p>
<h3>Application Business Rules</h3>
<p>Application Business Rulesではアプリケーション固有のビジネスルールが含まれ、入出力するデータの流れを調整します。</p>
<p>TaskPortにインターフェイスを定義し、TaskGatewayで具象クラスを実装するようにしています。TaskUseCaseではTaskPortを呼び出すように実装しています。</p>
<p>・TaskPort.kt</p><pre class="crayon-plain-tag">package com.example.port

import com.example.domain.Task
import com.example.domain.TaskId
import com.example.domain.Tasks

interface TaskPort {
  fun getTasks(): Tasks
  fun getTask(taskId: TaskId): Task
}</pre><p>&nbsp;</p>
<p>・TaskUseCase.kt</p><pre class="crayon-plain-tag">package com.example.usecase

import com.example.domain.Task
import com.example.domain.TaskId
import com.example.port.TaskPort
import com.example.domain.Tasks
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component
class TaskUseCase() {
  @Autowired
  lateinit var taskPort: TaskPort

  fun getTasks(): Tasks {
    return taskPort.getTasks()
  }

  fun getTask(taskId: TaskId): Task {
    return taskPort.getTask(taskId)
  }

}</pre><p>&nbsp;</p>
<h3>Interface &amp; Adapter</h3>
<p>Interface &amp; Adapterではドメインやユースケースに便利な形式からDBに便利な形式にデータを変換します。</p>
<p>TaskGatewayはTaskPortで定義したinterfaceを実装しています。またTaskDriverで取得したJSONをドメインに変換する処理をしています。</p>
<p>TaskControllerでは逆にドメインをレスポンスの形に変換する処理をしています。</p>
<p>・TaskGateway.kt</p><pre class="crayon-plain-tag">package com.example.gateway

import com.example.domain.*
import com.example.driver.TaskDriver
import com.example.driver.TaskJson
import com.example.driver.TasksJson
import com.example.port.TaskPort
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component
class TaskGateway: TaskPort {
  @Autowired
  lateinit var taskDriver: TaskDriver

  override fun getTasks(): Tasks {
    val tasksJson: TasksJson = taskDriver.getTasks()
    return tasksJson.toTasks()
  }

  override fun getTask(taskId: TaskId): Task {
    val taskJson: TaskJson = taskDriver.getTask(taskId.value)
    return taskJson.toTask()
  }
}

fun TasksJson.toTasks(): Tasks {
  return this.list.map {
    Task(Title(it.title), Content(it.content))
  }.let(::Tasks)
}

fun TaskJson.toTask(): Task {
  return Task(Title(this.title), Content(this.content))
}</pre><p>&nbsp;</p>
<p>・TaskController.kt</p><pre class="crayon-plain-tag">package com.example.controller

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RestController
import com.example.usecase.TaskUseCase
import com.example.domain.Tasks
import com.example.domain.Task
import com.example.domain.TaskId
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable

@RestController
class TaskController {
  @Autowired
  lateinit var taskUseCase: TaskUseCase

  @GetMapping(value = ["/api/tasks"])
    fun getTasks(): ResponseEntity&lt;TasksJson&gt; {
    return ResponseEntity.ok(taskUseCase.getTasks().toJson())
  }

  @GetMapping(value = ["/api/tasks/{taskId}"])
  fun getTask(
    @PathVariable(value = "taskId", required = true) taskId: Int
  ): ResponseEntity&lt;TaskJson&gt; {
    return ResponseEntity.ok(taskUseCase.getTask(TaskId(taskId)).toJson())
  }
}

data class TaskJson(val title: String, val content: String)
data class TasksJson(val tasks: List&lt;TaskJson&gt;)

fun Tasks.toJson() = this.list.map { it.toJson() }.let(::TasksJson)
fun Task.toJson() = TaskJson(this.title.value, this.content.value)</pre><p>&nbsp;</p>
<h3>Framework &amp; Driver</h3>
<p>Framework &amp; Driverはフレームワークやツールで構成されています。</p>
<p>今回はスタブでJSON形式の値を返すようにしていますが、本来ならDB操作やAPIリクエストを行う想定です。</p>
<p>・TaskDriver.kt</p><pre class="crayon-plain-tag">package com.example.driver

import com.fasterxml.jackson.annotation.JsonCreator
import org.springframework.stereotype.Component

@Component
class TaskDriver() {
  fun getTasks(): TasksJson {
    return TasksJson(listOf(TaskJson("title", "content"), TaskJson("title2", "content2")))
  }

  fun getTask(taskId: Int): TaskJson {
    return TaskJson("title", "content")
  }
}

data class TasksJson @JsonCreator constructor(
  val list: List&lt;TaskJson&gt;
)

data class TaskJson @JsonCreator constructor(
  val title: String,
  val content: String
)</pre><p></p>The post <a href="https://mintaku-blog.net/kotlin-spring-boot/">Kotlin+Spring Bootで簡単なAPIをClean Architectureで実装してみた</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-spring-boot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2182</post-id>	</item>
		<item>
		<title>Kotlinのコレクションとコンストラクタを整理する</title>
		<link>https://mintaku-blog.net/kotlin-collenction/</link>
					<comments>https://mintaku-blog.net/kotlin-collenction/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Sat, 02 Apr 2022 03:20:27 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2174</guid>

					<description><![CDATA[<p>Kotlinハンズオンを読んで、Kotlinのコレクションとコンストラクタを整理します。 コレクション コレクションはたくさんの値をまとめて管理するための仕 …</p>
The post <a href="https://mintaku-blog.net/kotlin-collenction/">Kotlinのコレクションとコンストラクタを整理する</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>Kotlinハンズオンを読んで、Kotlinのコレクションとコンストラクタを整理します。</p>
<h2>コレクション</h2>
<p>コレクションはたくさんの値をまとめて管理するための仕組みで、いくつかの専用の値が用意されています。</p>
<p>&nbsp;</p>
<h2>配列</h2>
<p></p><pre class="crayon-plain-tag">arrayOf(value1, value2, …)</pre><p>配列は多数の値を保管する場所が用意されており、そこに1つ1つ値が保管されます。</p>
<p>保管されている場所にはインデックスと呼ばれる番号が付与され、これは0から順に割り振られます。また、配列の変数の後に.sizeをつけると要素数が取得できます。</p>
<h3>配列の問題点</h3>
<p>配列の欠点として型の異なる値を保管できないことが挙げられます。</p>
<p>また、配列は基本的に最初に用意した要素しか使えないようになっています。以下の例のように配列に新しい要素を追加することは基本的にできません。</p><pre class="crayon-plain-tag">ex)
var sampleArray = arrayOf(1, 2, 3, 4, 5)
sampleArray[5] = 6 // エラー</pre><p>&nbsp;</p>
<h2>リスト</h2>
<p>異なる値をひとまとめたり、要素を追加や削除をするにはリストを使います。</p>
<p>リストは配列と同じように多数の値を1つにまとめ、インデックスで整理します。このリストには「List」と「MutableList」の2種類があります。</p>
<p>ListとMutableListの違いは、リストの書き換えが可能かどうかの違いです。</p>
<p>Mutableとは「可変な」という意味で、MutableListは要素の追加や削除、入れ替えなどができます。一方、Listは読み取り専用で要素を変更することができません。</p>
<p><strong>Listの作成</strong></p><pre class="crayon-plain-tag">listOf(value1, value2, …)</pre><p><strong>MutableListの作成</strong></p><pre class="crayon-plain-tag">mutableListOf(value1, value2, …)</pre><p>&nbsp;</p>
<h2>マップ</h2>
<p>マップは保管する値にキーというラベルをつけて保管します。このマップもリストと同様、値の変更ができない定数扱いの「Map」と変更できる「MutableMap」が用意されています。</p>
<p>マップにはインデックスがないため、リストのように作成した順番に値を取り出すということができません。</p>
<p><strong>Mapの作成</strong></p><pre class="crayon-plain-tag">mapOf(key1 to valu1, key1 to value2, …)</pre><p><strong>MutableMapの作成</strong></p><pre class="crayon-plain-tag">mutableMapOf(key1 to valu1, key1 to value2, …)</pre><p>&nbsp;</p>
<h2>セット</h2>
<p>セットは集合を扱う値で、集合のため同じ値は複数存在できません。また、値に順番などもありません。</p>
<p>これも変更できない定数としての「Set」と変更可能な「MutableSet」が用意されています。</p>
<p><strong>Setの作成</strong></p><pre class="crayon-plain-tag">setOf(valu1, value2, …)</pre><p><strong>MutableSetの作成</strong></p><pre class="crayon-plain-tag">mutableSetOf(value1, value2, …)</pre><p>&nbsp;</p>
<h2>ジェネリック(総称型)</h2>
<p>コレクション関係の値を用意する際に、この方の値だけ入れられるということを設定できる仕組みがジェネリックと呼ばれるものです。</p>
<p>これは、値を作成する際に&lt;&gt;記号を使って型を指定します。以下のように&lt;型&gt;とつけることで、そのコレクション内に指定された型の値しか保管できなくなります。</p><pre class="crayon-plain-tag">変数 = listOf&lt;型&gt;()</pre><p>&nbsp;</p>
<h2>クラスのコンストラクタ</h2>
<h3>プライマリコンストラクタ</h3>
<p>インスタンスを作成する際に使用する引数は、クラス定義に引数を用意しておくことで利用できるようになります。この引数はプライマリコンストラクタと呼ばれ、その名の通りインスタンスをコンストラクタするためのものです。</p><pre class="crayon-plain-tag">class 名前 (arg1, arg2, …)</pre><p>&nbsp;</p>
<h3>initメソッド</h3>
<p>initメソッドでクラスに初期化処理を用意して処理させることができます。このinit内で、クラスの引数に用意された値などを元に初期化の処理をします。</p><pre class="crayon-plain-tag">init { 初期化処理 }</pre><p></p><pre class="crayon-plain-tag">ex)

class Person(name: String=”no name”, address: String=”no address”) {
  var name: String
  var address: String

  init {
    this.name = name
    this.address = address
  }

  fun say() = “Name: ” + name + “, Address: “ + address
}</pre><p>プライマリコンストラクタの引数をプロパティに代入するだけならinitメソッドを使わなくとも行うことができます。値をプロパティに代入するだけで他に何も処理を行わないなら以下のように直接代入した方が簡単にできます。</p><pre class="crayon-plain-tag">ex)

class Person(name: String=”no name”, address: String=”no address”) {
  var name = name
  var address = address

  fun say() = “Name: ” + name + “, Address: “ + address
}</pre><p>&nbsp;</p>
<h3>constructorメソッド(セカンダリコンストラクタ)</h3>
<p>プライマリコンストラクタよりもっと柔軟に引数を用意できる仕組みがconstructorメソッドです。このconstructorはセカンダリコンストラクタと呼ばれ、使用するにはプライマリコンストラクタ(クラス宣言の引数とinit)は使えません。</p><pre class="crayon-plain-tag">constructor(args) { … }</pre><p></p><pre class="crayon-plain-tag">ex)
class Person {
  var name: String
  var address: String

  constructor(name: String=”no name”, address: String=”no address”) {
    this.name = name
    this.address = address
  }

  constructor(arr: Map&lt;String, String&gt;) {
    this.name = arr[“name”] ?: “no name”
    this.address = arr[“address”] ?: “no address”
  }

  fun say() = “Name: ” + name + “, Address: “ + address
}
</pre><p></p>The post <a href="https://mintaku-blog.net/kotlin-collenction/">Kotlinのコレクションとコンストラクタを整理する</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-collenction/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2174</post-id>	</item>
		<item>
		<title>Kotlin + Spring BootをVSCodeで環境構築する</title>
		<link>https://mintaku-blog.net/kotlin-vscode/</link>
					<comments>https://mintaku-blog.net/kotlin-vscode/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Mon, 09 Aug 2021 03:06:30 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2034</guid>

					<description><![CDATA[<p>VSCodeでKotlin + Spring Bootの環境構築をしたので、メモとして残しておきます。 事前準備 VSCodeのインストール JDKのインス …</p>
The post <a href="https://mintaku-blog.net/kotlin-vscode/">Kotlin + Spring BootをVSCodeで環境構築する</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>VSCodeでKotlin + Spring Bootの環境構築をしたので、メモとして残しておきます。</p>
<h2>事前準備</h2>
<ul>
<li>VSCodeのインストール</li>
<li>JDKのインストール</li>
</ul>
<p>&nbsp;</p>
<h2>Kotlinとは</h2>
<p>Kotlinは、Javaの統合開発環境であるIntelliJ IDEAで有名なJetBrainsが開発したオブジェクト指向プログラミング言語です。言語構文自体はJavaとは互換性がない独自方式ですが、コンパイルされたコードはJava VM（仮想マシン）上で動作します。</p>
<p>2017年にAndroid公式開発言語に追加されたことで、知名度が上がりました。</p>
<p>&nbsp;</p>
<h2>Kotlinの特徴</h2>
<h3>Javaと互換性がある</h3>
<p>KotlinとはJavaと互換性があり、KotlinからJavaを呼び出すことも、JavaからKotlinを呼び出すこともできます。</p>
<h3>汎用性</h3>
<p>Kotlinは、Javaをより安全に記述できることを目的として改良されており、高い汎用性をがある言語です。</p>
<p>またJavaを簡潔に記述できるようにコードがシンプルになっているため、短いコードで記述でき、開発時の負担が軽減されています。</p>
<h3>安全性</h3>
<p>もともと産業利用を目的とした汎用言語として開発された言語なので、コードが簡潔でバグを発生させにくい構造になっています。</p>
<p>また、KotlinにはNull Safetyがあり、Javaの場合に発生しがちなNull参照を原因とする実行時エラーを防ぐことができるため、安全なシステム開発ができます。</p>
<p>&nbsp;</p>
<h2>Spring Bootとは</h2>
<p>Spring BootはJavaによるWebアプリ開発を迅速かつ効率的にする仕組みを備えたフレームワークのことです。</p>
<h3>Spring Frameworkとの関係</h3>
<p>Spring Frameworkは現在に至るまで様々な機能拡張がされており、豊富な機能が充実する一方で、組み合わせて使うには煩雑な設定とノウハウが必要という課題も指摘されるようになりました。</p>
<p>この課題に取り組み、最小限の設定とより少ないコード量でアプリケーションを作成して、すぐに実行できる仕組みを実装したのがSpring Bootです。</p>
<p>そのため、Spring BootもSpring Frameworkをベースとするフレームワークの1つです。</p>
<p>&nbsp;</p>
<h2>JVMとは</h2>
<p>KotlinはJVM言語ですが、そもそもJVMについて何なのか整理します。</p>
<p>JVMとは「Java Virtual Machine」の略でJavaで作成されたアプリケーションを各OSで動かすために必要となるアプリケーションです。Java仮想マシンなどとも呼ばれます。</p>
<p>Javaで作成したプログラムをコンパイルすると中間コードと呼ばれるJavaクラスファイルを出力します。JavaクラスファイルはどのOS上でコンパイルしても同じものが生成され、実行したいOSにインストールされているJVM上で実行されます。</p>
<p>JavaクラスファイルがOSに関わらず共通なのに、それぞれのOSで問題なく動さするのはそれぞれのOS用のJVMがJavaクラスファイルを対象のOSで動作するように変換して実行してくれるからです。</p>
<p>&nbsp;</p>
<h2>JDKとは</h2>
<p>JDKとははJVM・Javaコンパイラ・ライブラリ等のJavaの開発に必要な物のセットです。Java開発環境などと呼ばれます。</p>
<p>Kotlinのコードだけを実行するだけなら、KotlinのコンパイラとJVMがあれば動きますが、Javaのライブラリを使ったりすることがあるため、JDKを入れておくと良いでしょう。</p>
<p>&nbsp;</p>
<h2>jarファイルとは</h2>
<p>jarとはJava Archiveの略です。その名の通りJavaのファイルがひとつにまとめられ、アプリケーションとして使えるようになったファイルのことです。</p>
<p>コンパイルされた複数のclassファイルやプログラムが使用する画像などはすべてjarファイルの中に入っています。複数のjavaファイルが圧縮されてひとまとめになったものをjarファイルといいます。</p>
<p>&nbsp;</p>
<h2>Gradleとは</h2>
<p>javaのビルドツールで jarファイルへのビルドをしてくれます。mavenと違い設定ファイルはgrovyという言語で書きます。</p>
<p>&nbsp;</p>
<h2>Spring Bootのプロジェクト作成</h2>
<p>以下の2つの方法でSpring Bootのプロジェクトテンプレートを作成できます。</p>
<ol>
<li>https://start.spring.io/</li>
<li>VSCodeの拡張機能を使う</li>
</ol>
<p>今回はspring initializerを使って作成しました。以下のように設定し「GENERATE」を押すことでテンプレートを生成できます。</p>
<p>Dependenciesは以下の2つを選択しました。</p>
<ol>
<li>Spring Web: Webアプリ作成に必要な依存関係定義のセット</li>
<li>Thymleaf: テンプレートエンジン</li>
</ol>
<p><img data-attachment-id="2036" data-permalink="https://mintaku-blog.net/kotlin-vscode/image2-9/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?fit=1999%2C1394&amp;ssl=1" data-orig-size="1999,1394" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image2" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?fit=300%2C209&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?fit=800%2C558&amp;ssl=1" loading="lazy" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?resize=800%2C558&#038;ssl=1" alt="" width="800" height="558" class="aligncenter size-large wp-image-2036" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?resize=1024%2C714&amp;ssl=1 1024w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?resize=300%2C209&amp;ssl=1 300w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?resize=768%2C536&amp;ssl=1 768w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?resize=1536%2C1071&amp;ssl=1 1536w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?w=1999&amp;ssl=1 1999w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image2.png?w=1600&amp;ssl=1 1600w" sizes="(max-width: 800px) 100vw, 800px" data-recalc-dims="1" /></p>
<p>&nbsp;</p>
<p>VSCodeで生成したテンプレートを開きます。</p>
<p>タスクの実行をするため、.vscode/tasks.jsonを生成し、以下を貼り付けます。</p>
<p>・tasks.json</p>
<div class="hcb_wrap">
<pre class="crayon-plain-tag">&lt;code&gt;{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  &quot;version&quot;: &quot;2.0.0&quot;,
  &quot;tasks&quot;: [
    {
      &quot;label&quot;: &quot;build&quot;,
      &quot;type&quot;: &quot;shell&quot;,
      &quot;command&quot;: &quot;./gradlew build&quot;
    },
    {
      &quot;label&quot;: &quot;run&quot;,
      &quot;type&quot;: &quot;shell&quot;,
      &quot;command&quot;: &quot;./gradlew bootRun&quot;,
    },
    {
      &quot;label&quot;: &quot;clean&quot;,
      &quot;type&quot;: &quot;shell&quot;,
      &quot;command&quot;: &quot;./gradlew clean&quot;
    },
    {
      &quot;label&quot;: &quot;check&quot;,
      &quot;type&quot;: &quot;shell&quot;,
      &quot;command&quot;: &quot;./gradlew check&quot;
    }
  ]
}&lt;/code&gt;</pre>
</div>
<p>「ターミナル」→「タスクの実行」から「Run」を選択します。以下のように正常に起動すれば完了です。</p>
<div class="hcb_wrap">
<pre class="crayon-plain-tag">&lt;code&gt;&amp;gt; Executing task: ./gradlew bootRun &amp;lt;

&amp;gt; Task :bootRun

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)&lt;/code&gt;</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>build.gradleがある階層でこのコマンドを実行するとbuildが実行され、build/libs/の下にjarファイルが生成されます。</p><pre class="crayon-plain-tag">$ gradlew build</pre><p>生成されたファイルを以下のコマンドで実行すると、localhost:8080でページにアクセスすることができます。</p><pre class="crayon-plain-tag">$ java -jar build/libs/hoge-0.0.1-SNAPSHOT.jar</pre><p>&nbsp;</p>
<h2>Hello Worldしてみる</h2>
<p>HelloWorld.ktを作成し、localhost:8080にきたら「Hello World」と表示するようにします。「GetMapping」や「RestController」を使うにはSpring WebをDependenciesで選択しておく必要があります。</p>
<p>・HelloWorld.kt</p>
<div class="hcb_wrap">
<pre class="crayon-plain-tag">import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
  class HelloController {
  @GetMapping(&quot;/&quot;)
  fun helloWorld(): String {
    return &quot;Hello World&quot;
  }
}
</pre>
</div>
<p>&nbsp;</p>
<p>サーバを起動させてlocalhost:8080にアクセスし、「Hello World」と表示されれば成功です。</p>
<p><img data-attachment-id="2035" data-permalink="https://mintaku-blog.net/kotlin-vscode/image1-11/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image1.png?fit=500%2C192&amp;ssl=1" data-orig-size="500,192" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image1.png?fit=300%2C115&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image1.png?fit=500%2C192&amp;ssl=1" loading="lazy" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image1.png?resize=500%2C192&#038;ssl=1" alt="" width="500" height="192" class="aligncenter size-full wp-image-2035" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image1.png?w=500&amp;ssl=1 500w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/07/image1.png?resize=300%2C115&amp;ssl=1 300w" sizes="(max-width: 500px) 100vw, 500px" data-recalc-dims="1" /></p>The post <a href="https://mintaku-blog.net/kotlin-vscode/">Kotlin + Spring BootをVSCodeで環境構築する</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/kotlin-vscode/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2034</post-id>	</item>
	</channel>
</rss>
