Ruby標準のLoggerでスレッドIDを出力する

  • このエントリーをはてなブックマークに追加

その1 / procを指定する

formatterにprocを直接指定する。
色々と制限があります。あまりオススメしません。


def main(logger)
logger.info("main"){ "こんにちは" }
begin
raise "エラー"
rescue => err
logger.error("main"){ err }
end
end

custom = Logger.new(STDOUT, formatter: proc { |severity, time, progname, msg|
# msgが例外の場合、originalは表示されるけど、これはされない
"%s, [%s#%d/#%d] %5s -- %s: %s\n" % [severity[0..0], time.strftime("%Y-%m-%dT%H:%M:%S.%6N "), Process.pid, Thread.current.object_id, severity, progname, msg]
})
main(custom)
I, [2021-07-11T10:36:43.688551 #4163]  INFO -- main: こんにちは
E, [2021-07-11T10:36:43.688635 #4163] ERROR -- main: エラー (RuntimeError)
app.rb:7:in `main'
app.rb:14:in `<main>'

その2 / Logger::Formatterを継承する

Logger::Formatterを継承して自分用のFormatterを作り、Loggerのfometterに指定します。
この方法は直接Procを指定するわけではないので、標準クラスが持っているメソッドであるformat_datetimemsg2strが使えます。


def main(logger)
logger.info("main"){ "こんにちは" }
begin
raise "エラー"
rescue => err
logger.error("main"){ err }
end
end

class CustomFormatter < Logger::Formatter
CustomFormat = "%s, [%s#%d/#%d] %5s -- %s: %s\n".freeze
def initialize
super
end
def call(severity, time, progname, msg)
CustomFormat % [severity[0..0], format_datetime(time), Process.pid, Thread.current.object_id, severity, progname, msg2str(msg)]
end
end
custom2 = Logger.new(STDOUT, formatter: CustomFormatter.new)
main(custom2)

I, [2021-07-11T10:36:43.688747 #4163/#70368626219440]  INFO -- main: こんにちは
E, [2021-07-11T10:36:43.688773 #4163/#70368626219440] ERROR -- main: エラー (RuntimeError)
app.rb:7:in `main'
app.rb:32:in `<main>'

参考

vueでscssを利用する

  • このエントリーをはてなブックマークに追加

vue-cliのバージョンは4.5.13を想定。
vue createした時に「Manually select features」を選択して「CSS Pre-processors」を選択すれば最初から入るが、「Default」を選択した場合は、babeleslintが有効になるだけである。

vue --version
@vue/cli 4.5.13

後から入れる場合は、sasssass-loaderをdevDependenciesに追加する。ただし、sass-loaderは現時点でバージョンが12.1.0であり、webpackの依存バージョンが競合してエラーになってしまう。
回避するためにはバージョンを指定してインストールする。それぞれvue-cliで最初に有効にした場合にインストールされるバージョンを指定する。
これらのバージョンは、ここで参照する事ができます。

npm install --save-dev sass@1.26.5
npm install --save-dev sass-loader@8.0.2

上記では8.0.2を指定していますが、vue-cliが4.5.13で作ったpackage.jsonに対しては、sass-loader@10.2.0まではインストール可能です。

sass-loaderのpeerDependenciesが、10.2.0では次の指定に対して、

10.2.0
"webpack": "^4.36.0 || ^5.0.0"

11.0.0からは、次のようになっているからです。

11.0.0
"webpack": "^5.0.0"

@vue/cli-plugin-babelのバージョンは4.5.13で、そのdependenciesに"webpack": "^4.0.0"とあり、4.46.0が実際にインストールされています。

書き方

vueファイルのstyleにlang="scss"と書く。

サンプル
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
}
body {
color: blue;
p {
font-weight: bold;
}
}
</style>

参考

Vue3で環境変数の設定をする

  • このエントリーをはてなブックマークに追加

Vue2とVue3では設定方法が異なります。この記事ではVue3に関する設定方法を。
npm run serve mode=mockとして起動することで、.env.mockのファイルを読み込みます。開発環境の時はNODE_ENVdevelopmentなので、.env.developmentが読み込まれます。

環境変数名はVUE_APP_で始まる必要があり、それ以外は無視されてしまう。

.env.development
VUE_APP_HOGEFUGA=true

process.env.VUE_APP_HOGEFUGAで参照可能。

.envは全てのケースにおいて読み込まれますが、優先順位があり、.env.developmentが先に読み込まれる。また、.env.local.env.development.localのように末尾に.localのファイルがあれば、それが優先的に読み込まれる。.localは各個人の環境でのみ利用することを想定しているファイルで.gitignoreの対象となっている。

例えば、--mode=developmentで起動した場合、.env.development.local -> .env.development -> .env.local -> .env の順番に読み込みされて、同じ環境変数名がある場合は先勝ちである。

これらの処理はdotenvdotenv-expandのモジュールがやってるのだと思うのですが、そんなコードは見つけられず、dotenv-flowにこのような処理があるけど、vue3からはリンクはされておらず。

どうやら自前で処理している様子。
vue-cliのcli-serviceのService.jsに処理がありました。
dotenvを利用しており、環境変数DEBUG=trueをつけて実行すると、dotenvのデバッグログが有効になって、そのあたりのログが出力されます。

参考

Vue3でWebページを表示しようとしたらInvalid Host Headerと表示される

  • このエントリーをはてなブックマークに追加

例えば、 example.local127.0.0.1にマッピングして、example.localでアクセスした時にInvalid Host Headerと表示される。

vue.config.jsで次の設定を入れる

module.exports = {
// options...
devServer: {
disableHostCheck: true
}
}

参考

rubyのhttpclientでhttpsからhttpにredirectするとエラーになる

  • このエントリーをはてなブックマークに追加

httpclientでredirectの自動追従は次のオプションで出来る。

client = HTTPClient.new()
client.get('https://nghttp2.org/httpbin/redirect/2', :follow_redirect => true)

httpbinのredirectが404になるので、代わりのサイトで検証。

しかし、httpsからhttpへのredirectはBadResponseErrorになります。

client = HTTPClient.new()
client.get('https://nghttp2.org/httpbin/redirect-to?url=http%3A%2F%2Fexample.com', :follow_redirect => true)

ライブラリのコードはこんな感じでif https?(uri) && !https?(newuri)このコードで弾かれています。

def default_redirect_uri_callback(uri, res)
newuri = urify(res.header['location'][0])
if !http?(newuri) && !https?(newuri)
warn("#{newuri}: a relative URI in location header which is not recommended")
warn("'The field value consists of a single absolute URI' in HTTP spec")
newuri = uri + newuri
end
if https?(uri) && !https?(newuri)
raise BadResponseError.new("redirecting to non-https resource")
end
puts "redirect to: #{newuri}" if $DEBUG
newuri
end
https://github.com/nahi/httpclient/blob/master/lib/httpclient.rb#L722-L734

HTTPClient::BadResponseError (redirecting to non-https resource)

これはこれで正しいのですが、クローラーを書くときは無視したいことが多いです。そんな時は、clientのredirect_uri_callbackを自前のロジックに変更します。

client = HTTPClient.new()
client.redirect_uri_callback = lambda {|uri, res|
newuri = HTTPClient::Util.urify(res.header['location'][0])
if (newuri.scheme && (newuri.scheme.downcase == "https" || newuri.scheme.downcase == "http"))
else
newuri = uri + newuri
end
newuri
}

参考情報

rubyのhttpclientでgzip対応

  • このエントリーをはてなブックマークに追加

httpclientでgzipのresponseを自動で処理するためのオプション。

client = HTTPClient.new()
client.transparent_gzip_decompression = true

参考情報

PlantUML-ServerをBasic認証付きで公開する

  • このエントリーをはてなブックマークに追加

plantuml-serverはdocker imageが既にあるので簡単に公開する事ができます。
外部サーバに立てると、誰でもアクセスできてしまうため、Basic認証を付けたいことがあります。WebのUIから使うだけならIDP連携でOAuth認証を入れてしまえば良いのですが、Visual Studio Codeのプラグインと連携させる場合は、OAuthは対応していないため、Basic認証にするしかありません。

docker-composeを利用して、nginxでbasic認証をかけてplantumlにproxyするのが簡単です。
そして、nginxのbasic認証に特化したイメージがあります ⇒ quay.io/dtan4/nginx-basic-auth-proxy

しかし、普通に設定すると、PlantUMLの画面でホスト名がplantuml:8080というホスト名になってしまいます。
これは、例えば、http://example.comにデプロイしたとして、Userhttp://example.comnginxhttp://plantuml:8080/PlantUMLのApplicationサーバ(Jetty or Tomcat) となり、PlantUML(Jetty)から見ると、plantuml:8080というホスト名でアクセスに来ているからです。

PlantUMLのコード

PlantUMLのコードでは、JSPのTagLibで次のように記述されています。

<c:set var="contextroot" value="${pageContext.request.contextPath}" />
<c:if test="${(pageContext.request.scheme == 'http' && pageContext.request.serverPort != 80) ||
(pageContext.request.scheme == 'https' && pageContext.request.serverPort != 443) }">
<c:set var="port" value=":${pageContext.request.serverPort}" />
</c:if>
<c:set var="scheme" value="${(not empty header['x-forwarded-proto']) ? header['x-forwarded-proto'] : pageContext.request.scheme}" />
<c:set var="hostpath" value="${scheme}://${pageContext.request.serverName}${port}${contextroot}" />
<c:if test="${!empty encoded}">
<c:set var="imgurl" value="${hostpath}/png/${encoded}" />
<c:set var="svgurl" value="${hostpath}/svg/${encoded}" />
<c:set var="txturl" value="${hostpath}/txt/${encoded}" />
<c:if test="${!empty mapneeded}">
<c:set var="mapurl" value="${hostpath}/map/${encoded}" />
</c:if>
</c:if>

<a href="${svgurl}">View as SVG</a>

pageContext.request.serverNameplantuml:8080になります。
一方、nginx-basic-auth-proxyでは、X-Forwarded-Hostを設定しています。(参考)

つまり、Jetty側でこのヘッダをHostとして扱えば良いわけです。
Jettyでは、X-Forwarded-xxの処理を良い感じに処理してくれるモジュールとしてhttp-forwardedがあります。

PlantUMLのJetty版の元のイメージはこちらを利用しており、
http-forwardedはデフォルトでは有効になっていませんが、/usr/local/jetty/etc/jetty-http-forwarded.xmlにあります。
そして、有効にするためには、--module=http-forwardedの引数を付ければ有効になります。

PlantUMLのDockerfileの定義は、Entrypointが/docker-entrypoint.sh。Commandがjava -jar /usr/local/jetty/start.jarです。
ここに引数を追加するには、command: java -jar /usr/local/jetty/start.jar --module=http-forwardedとすれば良いです。

docker-compose.yaml

こんな感じで。
ALLOW_PLANTUML_INCLUDEは、!includeで綺麗にするスタイルを外部ファイル化しており、毎回当てるので有効にしています。

version: "3.3"
services:
nginx-proxy:
image: quay.io/dtan4/nginx-basic-auth-proxy
ports:
- 80:80
environment:
BASIC_AUTH_USERNAME: test-user
BASIC_AUTH_PASSWORD: test-password
PROXY_PASS: http://plantuml:8080/
SERVER_NAME: proxy.internal
networks:
- container-link
plantuml:
image: plantuml/plantuml-server:jetty
command:
- "java"
- "-jar"
- "/usr/local/jetty/start.jar"
- "--module=http-forwarded"
environment:
- ALLOW_PLANTUML_INCLUDE=true
networks:
- container-link
networks:
container-link:

VS Codeのプラグインの設定

利用しているPlantUMLのPluginはこちら。

名前: PlantUML
ID: jebbs.plantuml
説明: Rich PlantUML support for Visual Studio Code.
バージョン: 2.14.5
パブリッシャー: jebbs
VS Marketplace リンク: https://marketplace.visualstudio.com/items?itemName=jebbs.plantuml

次のように、RenderをLocalからPlantUMLServerにします。
そして、Serverにdocker-composeで起動したURLを設定します。Basic認証の情報はURLに入れる事ができるので、http://test-user:test-password@example.com/のように設定します。

参考

Application Guardの設定をPowerShellで取得する

  • このエントリーをはてなブックマークに追加

Azureで管理されているポリシーが各端末に適用されるわけですが、そのポリシーはレジストリに格納されています。

  • キー: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager\current\device\NetworkIsolation
  • エントリ: EnterpriseCloudResources

もしくは、上記キーの EnterpriseCloudResources_WinningProviderの値 ⇒ ① として、以下のキーの場所。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager\Providers\①\default\Device\NetworkIsolation

プロビジョニングされた内容は、以下のキー配下に履歴として残っていきます。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning\NodeCache\CSP\Device\MS DM Server\Nodes\

取得方法

(Get-ItemProperty -LiteralPath HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device\NetworkIsolation).EnterpriseCloudResources | %{ $_ -replace '\|', "`n" }

|で区切られているので、改行に変換します。
PowerShellでは改行に変換する時、バッククォートなんですね。

参考

Safari Booksに日本語の本がたくさん追加されていた(計112冊)

  • このエントリーをはてなブックマークに追加

先月まで58冊だったのですが、今日見たら112冊になってました。
追加日を見ると、2021年5月19日~24日にかけて追加されたようです。

デザインの伝え方Javaパフォーマンス をはじめ、よさげな本がたくさんあります!

安く読む方法は、ACMの会員になるのが良いです。以下のリンクを参照。

ACM会員になってオライリーの本が読み放題

日本語書籍の一覧

カバー タイトル 出版日/追加日
入門 ソーシャルデータ 第2版 ―ソーシャルウェブのデータマイニング 2014/06/20
2021/05/24
Cクイックリファレンス 第2版 2016/11/04
2021/05/24
JavaScriptで学ぶ関数型プログラミング 2014/01/17
2021/05/20
マイクロインタラクション ―UI/UXデザインの神が宿る細部 2014/03/18
2021/05/19
AngularJSアプリケーション開発ガイド 2014/04/17
2021/05/19
実践 Vagrant 2014/02/20
2021/05/19
Effective Modern C++ ―C++11/14プログラムを進化させる42項目 2015/09/17
2021/05/19
Backbone.jsアプリケーション開発ガイド 2014/02/06
2021/05/19
統計クイックリファレンス 第2版 2015/01/23
2021/05/19
戦略的データサイエンス入門 ―ビジネスに活かすコンセプトとテクニック 2014/07/18
2021/05/19
Rクイックリファレンス 第2版 2014/01/24
2021/05/19
Bluetooth Low Energyをはじめよう 2015/02/24
2021/05/19
エンジニアのためのフィードバック制御入門 2014/07/25
2021/05/19
リーン顧客開発 ―「売れないリスク」を極小化する技術 2015/04/24
2021/05/19
Think Stats 第2版 ―プログラマのための統計入門 2015/08/18
2021/05/19
Rパッケージ開発入門 ―テスト、文書化、コード共有の手法を学ぶ 2016/02/04
2021/05/19
Think Bayes ―プログラマのためのベイズ統計入門 2014/09/05
2021/05/19
デザイニング・マルチデバイス・エクスペリエンス ―デバイスの枠を超えるUXデザインの探求 2014/12/24
2021/05/19
CSSシークレット ―47のテクニックでCSSを自在に操る 2016/07/22
2021/05/19
Sparkによる実践データ解析 ―大規模データのための機械学習事例集 2016/01/22
2021/05/19
Cython ―Cとの融合によるPythonの高速化 2015/06/18
2021/05/19
ユーザーストーリーマッピング 2015/07/24
2021/05/19
インタラクティブ・データビジュアライゼーション ― D3.jsによるデータの可視化 2014/02/18
2021/05/19
データ分析によるネットワークセキュリティ 2016/06/10
2021/05/19
リーンブランディング ―リーンスタートアップによるブランド構築 2016/08/25
2021/05/19
情報アーキテクチャ 第4版 ―見つけやすく理解しやすい情報設計 2016/11/17
2021/05/19
Docker 2016/08/12
2021/05/19
アルゴリズムクイックリファレンス 第2版 2016/12/22
2021/05/19
初めてのSpark 2015/08/21
2021/05/19
デザインスプリント ―プロダクトを成功に導く短期集中実践ガイド 2016/11/25
2021/05/19
初めてのAnsible 2016/04/15
2021/05/19
コマンドラインではじめるデータサイエンス ―分析プロセスを自在に進めるテクニック 2015/09/15
2021/05/19
実践 Android Developer Tools 2014/04/22
2021/05/19
アンダースタンディング コンピュテーション ―単純な機械から不可能なプログラムまで 2014/09/17
2021/05/19
データ匿名化手法 ―ヘルスデータ事例に学ぶ個人情報保護 2015/05/22
2021/05/19
詳説 イーサネット 第2版 2015/06/09
2021/05/19
アジャイルデータサイエンス ―スケーラブルに構築するビッグデータアプリケーション 2014/04/24
2021/05/19
ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化 2014/05/15
2021/05/19
ハイパフォーマンスPython 2015/11/19
2021/05/19
詳解 iOS SDK 第4版 ―ワンランク上のiPhone/iPadプログラミング 2014/12/18
2021/05/19
Javaパフォーマンス 2015/04/10
2021/05/19
パフォーマンス向上のためのデザイン設計 2016/06/24
2021/05/19
モバイルデザインパターン 第2版 ―ユーザーインタフェースのためのパターン集 2015/02/10
2021/05/19
データサイエンス講義 2014/10/24
2021/05/19
RStudioではじめるRプログラミング入門 2015/03/24
2021/05/19
Lean Analytics ―スタートアップのためのデータ解析と活用法 2015/01/23
2021/05/19
デザインの伝え方 ―組織の合意を得るコミュニケーション術 2016/09/15
2021/05/19
入門 iOS SDK ―初めてのiPhone/iPadプログラミング 2014/06/20
2021/05/19
グラフデータベース ―Neo4jによるグラフデータモデルとグラフデータベース入門 2015/03/24
2021/05/19
リーンエンタープライズ ―イノベーションを実現する創発的な組織づくり 2016/10/14
2021/05/19
Haskellによる並列・並行プログラミング 2014/08/20
2021/05/19
UX戦略 ―ユーザー体験から考えるプロダクト作り 2016/05/24
2021/05/19
マイクロサービスアーキテクチャ 2016/02/25
2021/05/19
ZooKeeperによる分散システム管理 2014/10/07
2021/05/19
エレガントなSciPy ―Pythonによる科学技術計算 2018/11/09
2020/12/14
デザイニング・ボイスユーザーインターフェース ―音声で対話するサービスのためのデザイン原則 2018/11/30
2020/12/14
Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス 2017/03/17
2020/12/14
初めてのPerl 第7版 2018/01/19
2020/12/14
Rによるテキストマイニング ―tidytextを活用したデータ分析と可視化の基礎 2018/05/17
2020/12/14
PythonとJavaScriptではじめるデータビジュアライゼーション 2017/08/24
2020/12/14
Rグラフィックスクックブック 第2版 ―ggplot2によるグラフ作成のレシピ集 2019/11/19
2020/12/14
ゼロトラストネットワーク ―境界防御の限界を超えるためのセキュアなシステム設計 2019/10/25
2020/12/14
Pythonデータサイエンスハンドブック ―Jupyter、NumPy、pandas、Matplotlib、scikit-learnを使ったデータ分析、機械学習 2018/05/25
2020/12/14
プログラミングRust 2018/08/09
2020/12/14
初めてのPHP 2017/03/17
2020/12/14
Rではじめるデータサイエンス 2017/10/24
2020/12/14
Lean UX 第2版 ―アジャイルなチームによるプロダクト開発 2017/07/03
2020/12/14
実践 CSIRTプレイブック ―セキュリティ監視とインシデント対応の基本計画 2018/05/18
2020/12/14
Head First Python 第2版 ―頭とからだで覚えるPythonの基本 2018/03/23
2020/12/14
Pythonによるデータ分析入門 第2版 ―NumPy、pandasを使ったデータ処理 2018/07/25
2020/12/14
GitHubツールビルディング ―GitHub APIを活用したワークフローの拡張とカスタマイズ 2017/05/09
2020/12/14
バイオビルダー ―合成生物学をはじめよう 2018/11/20
2020/12/14
Optimized C++ ―最適化、高速化のためのプログラミングテクニック 2017/02/21
2020/12/10
入門 監視 ―モダンなモニタリングのためのデザインパターン 2019/01/16
2020/11/19
Go言語による並行処理 2018/10/25
2020/11/19
Fluent Python ―Pythonicな思考とコーディング手法 2017/10/06
2020/11/19
アイソモーフィックJavaScript 2017/07/03
2020/11/19
ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック 2017/12/14
2020/11/19
入門 Kubernetes 2018/03/20
2020/11/19
Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎 2017/05/24
2020/11/19
機械学習のための特徴量エンジニアリング ―その原理とPythonによる実践 2019/02/21
2020/11/19
エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド 2018/09/25
2020/11/19
SVGエッセンシャルズ 第2版 2017/05/16
2020/11/19
実践 Deep Learning ―PythonとTensorFlowで学ぶ次世代の機械学習アルゴリズム 2018/04/25
2020/11/19
進化的アーキテクチャ ―絶え間ない変化を支える 2018/08/17
2020/11/19
Reactビギナーズガイド ―コンポーネントベースのフロントエンド開発入門 2017/03/10
2020/11/19
初めてのJavaScript 第3版 ―ES2015以降の最新ウェブ開発 2017/01/19
2020/11/19
プロダクションレディマイクロサービス ―運用に強い本番対応システムの実装と標準化 2017/09/12
2020/11/19
Effective DevOps ―4本柱による持続可能な組織文化の育て方 2018/03/23
2020/11/19
PythonによるWebスクレイピング 第2版 2019/03/25
2020/11/19
分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計 2019/04/19
2020/11/19
データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理 2019/07/17
2020/11/19
詳説 Deep Learning ―実務者のためのアプローチ 2019/08/08
2020/11/19
入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング 2019/05/17
2020/11/19
初めてのGraphQL ―Webサービスを作って学ぶ新世代API 2019/11/11
2020/11/19
SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム 2017/08/10
2020/11/19
プログラミングROS ―Pythonによるロボットアプリケーション開発 2017/12/12
2020/11/19
詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識 2018/05/25
2020/11/19
Unityによるモバイルゲーム開発 ―作りながら学ぶ2D/3Dゲームプログラミング入門 2018/08/23
2020/11/19
マスタリング・イーサリアム ―スマートコントラクトとDAppの構築 2019/11/28
2020/11/16
インテリジェンス駆動型インシデントレスポンス ―攻撃者を出し抜くサイバー脅威インテリジェンスの実践的活用法 2018/12/25
2020/11/16
Python機械学習クックブック 2018/12/14
2020/11/16
ITIL Service Design (Japanese Translation) 2013/06/01
2020/10/29
ITIL Service Operation (Japanese Translation) 2013/06/01
2020/10/29
ITIL Service Strategy (Japanese Translation) 2013/06/01
2020/10/29
ITIL Service Transition (Japanese Translation) 2013/06/01
2020/10/29
ITIL Practitioner Guidance (Japanese Translation) 2017/03/01
2020/10/29
ITIL Continual Service Improvement (Japanese Translation) 2013/06/01
2020/10/29
Feedback That Works: How to Build and Deliver Your Message (Japanese) 2008/08/01
2020/10/26
Developmental Assignments: Creating Learning Experiences Without Changing Jobs (Japanese) 2008/07/31
2020/10/26
ITIL Foundation Handbook (Japanese Translation) 2015/06/01
2020/10/23
ITIL Foundation, ITIL 4 edition (Japanese Translation) 2019/11/01
2020/10/23

Jacksonである階層の属性を別の階層のObjectにマッピングする

  • このエントリーをはてなブックマークに追加

以下のJsonがあるとして、cursorhas_nextはPaginationに関するものだから、別のObjectにマッピングしたい。

{
"id": "abc",
"cursor": "next-cursor",
"has_next": true
}

普通にMappingするとこういうクラスを用意するわけだけど、

@Data
public static class MyRoot {
private String id;
private String cursor;
@JsonProperty("has_next") private boolean hasNext;
}

こういう感じの構造にマッピングしたい。

@Data
public static class MyRoot {
private String id;
private Paging paging;
}
@Data
public static class Paging {
@JsonProperty("cursor") private String cursor;
@JsonProperty("has_next") private boolean hasNext;
}

方法: @JsonUnwrappedを使う

@Data
public static class MyRoot {
private String id;
@JsonUnwrapped
private Paging paging;
}
@Data
public static class Paging {
@JsonProperty("cursor")
private String cursor;
@JsonProperty("has_next")
private boolean hasNext;
}

@Test
public static void main(String[] args) throws Exception {
String jsonString = """
{
"id": "abc",
"cursor": "next-cursor",
"has_next": true
}
""".indent(0);

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MyRoot root = mapper.readValue(jsonString, MyRoot.class);
System.out.println(root);
JacksonTest.MyRoot(id=abc, paging=JacksonTest.Paging(cursor=next-cursor, hasNext=true))

もし、MyRootクラスと@JsonUnwrappedされたPagingクラスに同じ属性名が存在する場合、MyRoot側に値が設定されます。