
kintone Java Client を使ってみました
サイボウズ株式会社 開発本部 People Experience チーム内 コネクト支援チームの貴島(@jnkykn) です。サイボウズは、U-22プログラムコンテスト 2023 のダイヤモンドスポンサーです。U-22プログラミングコンテストへの参加に興味を持っていただくことを目的に、kintone を使ったワークショップをお申込みをいただいた各地の学校で開催しています。ワークショップでは、kintone の REST APIを使ったハンズオンに取り組んでいただくのですが、私は Javaでkintone REST APIにアクセスするための kintone Java Client を使ったことがなかったので自分でも試してみました。
kintoneのREST APIを使ってみよう
サイボウズの kintone は REST API を使って、データを扱うことができます。Node.js や Pythonからのアクセスは、GitHub Codespacesでサクッと試してみたのですが、Javaで試そうと思ったら少々苦戦したので、その顛末をレポートします。今回は、kintone 開発者ライセンスを利用して、cybozu.com の kintone 開発者環境に漫画データベースアプリを作成して、アクセスします。
kintone Java Client
kintone Java Client は、kintone REST API を Java プログラムから使う際に必要な処理をまとめたライブラリです。kintone Java Client に用意されたメソッドを呼び出すだけで kintone REST API を実行できるので、コードの記述量を減らすことができます。
kintone Java Client の導入説明には、Gradleプロジェクトの場合と、Maven プロジェクトの場合が紹介されています。私はどちらも使ったことがなかったのですが、ワークショップ講師のウィルさんに「Maven を使ったことがありますか?」と聞かれたので、Maven プロジェクトで試すことにしました。

こんにちは、Maven
Mavenは、Java のコンパイル環境です。公式サイトの説明に従って、Mavenをインストールしました。ドキュメントにあるとおり、バージョン確認をしようとしたら、JAVA_HOMEを環境変数に設定していなかったことがわかりました。

そもそもJDKをインストールしていなかったので、Java Downloads から、ぴかぴかの最新バージョン JDK 20をインストールしました。
これで無事に、Maven のバージョン確認もできたので、サンプルプロジェクトを参考に Maven プロジェクトを作ってみました。mvn install でビルドができると思ったのですが、エラーがたくさん…

Eclipseと一緒に使ってみよう
Maven でプログラムを作るにあたって、解説ブログをいろいろ見てみたのですが、素の Maven プロジェクトを使っている例は Maven 公式ドキュメントくらいで、他は Eclipse にMaven 用の拡張を追加しているものばかりでした。Eclipse なら 前職の Java 開発案件で使っていたので、馴染みがあります。最初からこうすればよかった…。
今更ですが、Eclipse Version: 2023-06 (4.28.0)をインストールしました。
さらに、Eclipse に Maven 統合環境拡張を追加して、準備はOKです。

Eclipse の File メニューから、New >Maven Project を選択して、Maven 公式のサンプル「Hello, Maven Project」をもとにプロジェクトを作成、pom.xmlを設定しました。

App.java (標準出力にHello Maven World! と出力するだけのプログラム)
package main;
/**
* Hello Maven World!
*/
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello Maven World!");
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>maven.hello</groupId>
<artifactId>hello-world</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<!-- プラグインには Maven コンパイラを指定 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
</plugin>
</plugins>
</build>
</project>
Eclipse の場合、確か、Runでビルドと実行ができたはず~と思ったのですが、Maven プロジェクトの場合は、Run As > Maven install を選択すると、mvn install が実行されます。

コマンドプロンプトを開いて、対象プロジェクトの target ディレクトリに出力されたjarファイルを実行すると、Hello Maven World! が出力されました。やったー!

Hello, kintone Java Client
さて、ここから、kintone Java Client を使ってみようと思ったのですが、10年以上ぶりの Java で、システム開発をしていたときの記憶は忘却の彼方。kintone Java Client をプロジェクトにパッケージとして取り込めば良いのかなと思いながら、GitHubのコードをダウンロードしてプロジェクトに import してしまったのです。
これが、躓きの始まりでした。

pom.xml に kintone Java Client のための設定を追加したのに、ソースまで一緒に import するとは…
pom.xml にdependency を追加して、kintone Java Client の情報を追記
<dependencies>
<dependency>
<groupId>com.kintone</groupId>
<artifactId>kintone-java-client</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
App.java (kintoneのアプリの指定レコードを取得するプログラム)
package com.cybozu.devnet;
import java.util.List;
import com.kintone.client.KintoneClient;
import com.kintone.client.KintoneClientBuilder;
import com.kintone.client.RecordClient;
import com.kintone.client.api.record.AddRecordRequest;
import com.kintone.client.api.record.AddRecordResponseBody;
import com.kintone.client.api.record.GetRecordsByCursorResponseBody;
import com.kintone.client.model.record.CheckBoxFieldValue;
import com.kintone.client.model.record.Record;
import com.kintone.client.model.record.SingleLineTextFieldValue;
public class App {
public static void main(String[] args) throws Exception {
String baseUrl = "https://■■■■■■■■■■■.cybozu.com/"; // ドメイン名
String apiToken = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■"; // API トークン
long appId = 1L; // アクセス対象のアプリ ID
long recordId = 1L; // 取得対象のレコード ID
System.out.println("Hello, kintone Java Client");
// API トークン認証を行う
try (KintoneClient client = KintoneClientBuilder.create(baseUrl).authByApiToken(apiToken).build()) {
// レコード操作用クライアントを取得
RecordClient recordClient = client.record();
// kintone からレコードを取得する
Record record = recordClient.getRecord(appId, recordId);
// レコードID を出力する
System.out.println(record.getId());
}
}
}
ここから、ビルドが通らないという状態にハマってしまいました。


関連するパッケージ情報をせっせと pom.xml に追加してエラーは減らせたのですが、ハタと、「import しちゃいけないものをimportしているのでは?」と気がついて、import していた kintone Java Client のソースコードをサクッと削除するとエラーがきれいになくなりました。そうなんです。pom.xml に依存関係が書いてあるので、わざわざソースコードを import しなくても良かったのです。これなら、ビルドできそうです。意気揚々と、Run As > Maven install を実行したのですが、ビルドエラーが発生しました。
pom.xml で指定した Java コンパイラのバージョンが古かったようです。

pom.xml のJava コンパイラバージョンの指定を修正して 1.8 に
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
これで、ビルドが成功しました!ばんざい!🎊

コマンドプロンプトで実行すると、途中までは実行が成功したようでした。
例外メッセージを読むと、URI の '/' が重複しているようです。

baseUrl には不要な '/' は無かったので、 末尾の '/' を除いてみました。
String baseUrl = "https://■■■■■■■■■■■.cybozu.com"; // ドメイン名
これで Run As > Maven clean、Run As > Maven install で再ビルドしました。

『漫画データベース』へのレコードの追加
これで気を良くした私は、練習用の開発環境に作った「漫画データベース」にレコードを追加して、追加した結果の情報を取得するように修正してみようと思いました。
修正したコード(mainのみ)
/**
* kintoneの漫画データベースの1レコード目の取得後、1件追加して
* 追加したレコードのタイトルを確認する
**/
public class App {
public static void main(String[] args) throws Exception {
String baseUrl = "https://■■■■■■■■■■■.cybozu.com"; // ドメイン名
String apiToken = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■"; // API トークン
long appId = 1L; // アクセス対象のアプリ ID
long recordId = 1L; // 取得対象のレコード ID
System.out.println("Hello, kintone Java Client");
// API トークン認証を行う
try (KintoneClient client = KintoneClientBuilder.create(baseUrl).authByApiToken(apiToken).build()) {
// レコード操作用クライアントを取得
RecordClient recordClient = client.record();
// kintone からレコードを取得する
Record record = recordClient.getRecord(appId, recordId);
// レコードID を出力する
System.out.println("取得したレコードのID " + record.getId());
// 追加用レコードオブジェクトを作成(本当はやりたくないけど、便宜上直接文字列を設定)
Record addrecord = new Record();
addrecord.putField("manga_title", new SingleLineTextFieldValue("ちいかわ"));
addrecord.putField("manga_artist", new SingleLineTextFieldValue("ナガノ"));
addrecord.putField("manga_genre", new CheckBoxFieldValue("ファンタジー"));
// Add Record API 用リクエストを作成
AddRecordRequest req = new AddRecordRequest();
req.setApp(40L);
req.setRecord(addrecord);
// Add Record API 呼び出し(戻り値は、追加されたレコード番号)
long addedId = client.record().addRecord(appId, addrecord);
// 追加されたレコード番号 を出力する
System.out.println("追加されたレコードのID=" + addedId);
// 条件に一致するレコードの取得
// カーソルの定義
String cursorId = client.record().createCursor(appId, null, "レコード番号=" + addedId);
while (true) {
// カーソルを元にレコード一覧取得
GetRecordsByCursorResponseBody resp = client.record().getRecordsByCursor(cursorId);
List<Record> results = resp.getRecords();
for( int i=0; i<results.size(); i++){
System.out.println("追加されたレコードのタイトル=" + results.get(i).getSingleLineTextFieldValue("manga_title"));
}
// 次のデータが無ければループを終了
if (!resp.hasNext()) {
break;
}
}
}
}
}
実行してみたところ、うまくいきました。(実は、ここに至るまでに少々デバッグが必要だったのですが、割愛します)

kintone の漫画データベースにも、ちゃんとレコードが追加されていました。

まとめ
久しぶりの Java プログラミングということもありましたが、初めての Maven プロジェクト環境構築に苦戦しました。最初はわけもわからず「なぜ、こんなエラーが!?」と考え込んでしまいましたが、Maven の仕組みを理解するにつれて、自分の環境設定の間違いが理解できるようになりました。Mavenプロジェクトは、pom.xml に依存関係を記述しておけば、必要なパッケージを管理しつつビルドしてくれるので、他のPCに移行する際など、パッケージのインストール漏れもなく安心だなと思いました。python やNode.js のサンプルプログラムと比べて、環境構築で手間取りましたが、こういうところもプログラミングの面白さだな~と再認識できました。kintone Java Client の readme を読むと、Gradleで開発されているそうなので、次は Gradle も試してみたいと思いました。