jimble

ユーティリティ#

jimble-util には移送元から持ってきた道具が 約 28,000 行入っています。 ここは地図です。網羅ではなく「よく使うもの」と「引っかかるところ」を並べます。

補足

公開 API としての整理は Phase 2 です。 パッケージの切り方も名前も、移送元のままのところが残っています。

Data#

io.jimble.util.data.DataLinkedHashMap<String, Object> の派生です。 リクエストも SELECT の結果も JSON もこれで扱います(リクエストとレスポンス)。

Data data = new Data();
data.putData(SITE_ID, 1L);
data.putData(SITE_NAME, "俺的まとめ");

Data site = data.getData("site");

assertEquals(1L, site.getLong("id"));
assertEquals("俺的まとめ", site.getString("name"));

DB の値は列(Column)で読み書きします。列版はテーブル名のネストを辿ります。

putData(Column, 値) 必ずネストを作る
putDataTakeCare(Column, 値) 既存の形に合わせる(ネストが無ければ平ら)
flattenTable(Table) / extractTableData(Table) 平らにする / 取り出す。無ければ null

落とし穴

getStringOptional などの Optional 版は Data を書き換えます。 無ければ空文字を put してから返すので、読んだだけでキーが増えます。 JSON にして返す直前やループの中で呼ぶと、出力が変わります。

落とし穴

「無い」と「0」が区別できません。getStringnullgetInt0getBooleanfalse を返します。 区別したいときは getIntObject など Object 版isNull(key) を使ってください。

補足

toString() は要約です(キーと型だけ)。 ログに1行出しただけで中身が全部流れる/Async が読み込まれる、を防ぐためです。 JSON が要るときは getJsonString() を呼んでください。

JSON#

自前実装です(Jackson も Gson も使っていません)。

Data nested = new Data();
nested.put("title", "記事タイトル");

Data data = new Data();
data.put("name", "俺的まとめ");
data.put("count", 3);
data.put("feed", nested);
data.put("tags", List.of("あ", "い"));

String json = data.getJsonString();
Data restored = Data.fromJsonString(json);

assertEquals("俺的まとめ", restored.getString("name"));
assertEquals(3, restored.getInt("count"));
assertEquals("記事タイトル", restored.getData("feed").getString("title"));
assertEquals(List.of("あ", "い"), restored.getStringList("tags"));
やること 書き方
Data → 文字列 data.getJsonString() / getJsonString(true)(整形)
文字列 → Data Data.fromJsonString(json)
任意のオブジェクト Dson.encodes(obj) / Dson.decodes(json, Xxx.class)
ストリームに直接 data.outputJsonString(outputStream)
組み立てずに逐次書く JsonHashWriter / JsonArrayWriter

注意

Dson.encodes / decodes(static 版)は失敗しても null を返すだけです。 理由が要るなら new Dson() を作り、decode(...) のあとに isError() / getErrorException() を見てください。

型変換#

Convertor.convert(conf, src, 変換先.class) が入口です。 Bean ↔ Data ↔ Map ↔ List ↔ プリミティブが同じ1本を通ります。 data.convert(new MyBean()) も中身は同じものです。

落とし穴

**Configration は使い回さないでください。**変換の途中で階層カウンタと 循環参照の記録が書き換わります。1回の変換に1つ作ります。

HTTP クライアント#

JDK の HttpClient の薄いラッパで、メソッドごとにクラスがあります。

HttpGetExecutor res = new HttpGetExecutor()
	.setUrl("https://example.com/api")
	.addHeader("Accept", "application/json")
	.setTimeout(5000)
	.execute();

if (res.isError) {
	Log.error(res.errorException, "取得に失敗しました");
	return;
}

Data json = res.getContentJson();
  • POST は HttpPostExecutoraddBodyForm(name, value) / setBodyJson(data)
  • ファイルを1つでも足すと multipart になりますaddBodyForm(name, file, contentType)
  • プロキシは setProxy(new HttpProxy(host, port, id, pass))
  • 例外を投げません。isError を見てください(DB と同じ流儀)

注意

タイムアウトの既定は 30 秒で、接続と応答の両方に同じ値が入ります。個別には指定できません。

落とし穴

setIgnoreSslError(true) は JVM 全体に効きます。 証明書の検証を止めるシステムプロパティを立てるので、 同じプロセスの他の通信も検証しなくなり、元に戻りません。

CSV#

try (CsvReader reader = new CsvReader(new File("in.csv"))) {
	while (reader.next()) {
		String name = reader.getString("name");
	}
}

1行ずつ読みます(全部メモリに載せません)。書くほうは CsvWriter#writeLine(Object...)

注意

文字コードを省略すると、判定に失敗したときは Shift_JIS になります。 UTF-8 と分かっているなら new CsvReader(file, "UTF-8") と書いてください。

XML#

XmlParser.parse(file)XmlData の木にします(全部メモリに載ります)。 組み立ては XmlBuilder.build(xmlData)

ハッシュと暗号#

やること 使うもの
パスワード PasswordUtil.createHash / checkセッションと安全側の既定
署名(改ざん検知) Signer.sign / unsign(HMAC-SHA256)
暗号化 Aead.encrypt / decrypt(AES-256-GCM)
短い ID Hashids
ハッシュ値 Hash.md5 / sha256 / sipHash / xxHash64

注意

CipherUtil(AES/CBC)は IV が設定で固定です。同じ平文が必ず同じ暗号文になり、 改ざんも検知できません。移送元との互換のために残しています。 新しく書くところは Aead を使ってください。

落とし穴

**Hashids の既定インスタンスは salt が空です。**並びが推測できるので、 **見せたくない ID の隠蔽には使えません。**必要なら salt を指定して自分で作ってください。

DB に置く key-value#

DBValue.set(db, "last_imported_at", "2026-09-07");
String value = DBValue.getString(db, "last_imported_at", "");

落とし穴

get は値が無いと既定値を書き込みます(読むだけのつもりで INSERT が飛びます)。 値は 250 文字まで、消す API はありません。 キャッシュはプロセスごとなので、他の台の set は伝わりません。

そのほか#

分野 クラス
文字列 StringUtil(置換・全半角・Base62・パスワード生成)/ IcuUtil(かな・全半角)
日時 DateUtiljava.util.Date ベース。getFrom / getTo は「その日の 00:00:00 / 23:59:59」)
URL UrlUtil / UrlBuilder(ドメイン抽出・punycode・エンコード)
数値・パース Parse.parseInt など(失敗しても例外を投げません
正規表現 Patterns(メール・URL・ドメイン・電話)
ファイル FileUtil / IOUtil / FileCharDetecter(文字コード判定)
スレッド VirtualThreadManager / ThreadManager実行モデル
計測 StopWatch

補足

Patterns の TLD 一覧は書き切りの文字列です。新しい TLD は通りません。