Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【NW】SMTP

SMTP

SMTPとは、メール転送のための通信プロトコルです。
主にメールを管理するメールサーバーが他のメールサーバーにメールを転送するためにこのプロトコル用います。

メールサーバーとメール転送

SMTPの通信内容について説明する前に、そもそもメールがどのように配送され、送り先に届くのか、簡単に見てみましょう。

私たちは普段、PCやスマートフォン上でメールを書き、それを送りたい相手へと送信します。PCであればOutlookGmailスマートフォンであればGmailやキャリアの用意したメールアプリなどを使いますね。このような、メールを作成したり送信したりするプログラムをメーラー(メールクライアント)と呼びます。

メーラーを使って私たちがメールを送信すると、メールはメールサーバーと呼ばれるサーバーに一旦送られます。メールサーバーはユーザーのメールボックスを保持しており、メーラーはこのメールボックスを参照することで相手からのメールを受信することができます。このようなメーラー、もといメールクライアントは、メールの配送や転送のサービスを享受する側としてMail User Agent(MUA)と呼ばれます。

例えば、Aさんがメーラーとしてデスクトップ版Gmailを使ってメールを送る場合、下図のようになります。

f:id:rennnosukesann:20180704081137p:plain:w300

メールサーバーはメールを受け取ると、その宛先によって取るべきアクションを変えます。

① メールの宛先が自分が管理するユーザの場合、ユーザのメールボックスに配送する
② メールの宛先が自分が管理するユーザでない場合、他のメールサーバーに転送する

① メールの配送

メールサーバーは受け取ったメールの宛先を確認し、もし自分が管理するユーザー宛であれば、そのユーザのメールボックスにメールを配送します。

例えば、メールサーバーαがAさんとBさんの情報、そして彼らのメールボックスを管理しているとします。このときAさんがBさん宛にメールを送信すると、メールサーバーはメールの宛先を確認し、Bさんのメールボックスにメールを配送します。

f:id:rennnosukesann:20180704082612p:plain:w600

Bさんのメーラーは適宜メールサーバー上のBさんのメールボックスを参照します(この参照はIMAP/POP3などのプロトコルを用いて行われます)

② メールの転送

メールサーバーの受け取ったメールの宛先が、メールサーバーの管理するユーザー宛でなければ、そのユーザを管理する他のメールサーバーへと転送します。

今度はAさんがCさん宛にメールを送信したとしましょう。メールサーバーはメールの宛先を確認し、Cさんが自分の管理下にいないとわかると、Cさんを管理する別のメールサーバーへと転送しようとします。

f:id:rennnosukesann:20180704083658p:plain

このとき、メールサーバーαから、Cさんを管理下に置くメールサーバーβへメールの転送を行いますが、この転送時に用いられる通信プロトコルSMTPになります。またメールサーバーはメールネットワークのなかでメール転送する役割を担うことから、Mail Transfer Agent(MTA)とも呼ばれます。

ちなみにどうやってCさんを管理するメールサーバーを見つけるのか?と疑問に思うかもしれませんが、これはあて先のメールアドレスを使って解決します。

f:id:rennnosukesann:20180704084303p:plain:w300

メールアドレスは{ユーザ名}@{ドメイン名orメールサーバー名}という、左側にメールサーバーで一意なユーザ名、右側にドメイン名またはメールサーバー名が書かれている構成になっています。このうち、右側のメールサーバー名とドメイン名は、DNSとよばれる仕組み(とプロトコル)を使って、サーバーの居場所(IPアドレス)を突き止めることができます。IPアドレスがわかれば、あとはそのIPアドレス先のホストに対してSMTPでメールを転送するだけです。

SMTPの通信フロー

SMTPの通信フローは以下の5段階からなります。

① Greeting
② 送信元メールアドレスの送信
③ 宛先メールアドレスの送信
④ メールコンテンツの送信
⑤ 通信終了

f:id:rennnosukesann:20180704212954p:plain

① Greeting

メールを転送したいサーバーαがSMTPによる通信を開始するとき、送信先のメールサーバーβに対して通信開始の合図として「HELO」文字列を送ります(設定によっては「EHLO」を送ることもあります)。この挨拶に対して、メールサーバーβが250番応答を返したとき、Greetingは成功とし、SMTP通信が開始されます。

② 送信元メールアドレスの送信

Greetingが完了すると、メールサーバーαはメールサーバーβに対してメールの送信元アドレスを送信します。この送信に対してメールサーバーβが250番応答を返すと送信成功となります。

③ 宛先メールアドレスの送信

次に、メールサーバーαはメールサーバーβに対してメールの宛先アドレスを送信します。この送信に対してメールサーバーβが250番応答を返すと送信成功となります。

④ メールコンテンツの送信

送信元・宛先メールアドレスを送信し終わると、メールサーバーαはメールの内容を送る準備を開始します。その合図としてメールサーバーαは「DATA」の文字列をメールサーバーβに送信し、それに対してメールサーバーβは354番応答を返します。ここからメール内容の送信が開始されます。

送信されるメール内容は

  • 日付
  • 送信元メールアドレス
  • 宛先メールアドレス
  • メールの主題
  • メーラーのバージョン情報
  • メールの内容 ...

となります。

このメール内容送信に対してメールサーバーが250番応答を返すことで、メール内容送信は成功となります。

⑤ 通信終了

最後にメールサーバーαが「QUIT」メッセージをメールサーバーβに送信し、メールサーバーβが221番応答を返すことでSMTP通信が終了となります。

参考

Simple Mail Transfer Protocol - Wikipedia

SMTP(Simple Mail Transfer Protocol)〜前編:インターネット・プロトコル詳説(5) - @IT

e-words.jp

ascii.jp

(素材をお借りしました。ありがとうございました!) flat-icon-design.com

【python】numpy配列の特定の条件を満たす要素のインデックスを取得する

メモ。

numpy.arrayオブジェクトの要素のうち、指定した条件を満たす要素は下記のように取得できる。

import numpy as np

arr = np.array([[1,2,3],[4,5,6]]) # array([[1, 2, 3],
                                  #       [4, 5, 6]])

# 特定の条件を満たす要素を取得
arr[arr > 3] # array([4, 5, 6])

# 特定の条件を満たす要素を取得
arr[arr > 3] # array([4, 5, 6])

ただし、指定した条件を満たす要素の「添字」を取得したいときは、numpy.argwhereを使うと良い。

np.argwhere(arr > 3) # array([[1, 0],
                     #            [1, 1],
                     #            [1, 2]])

numpy配列のshapeに合わせた添字を返してくれるので、便利。

【Watson/python】IBM Watson Visual Recognitionを使って、pythonスクリプト上で画像分類を行う

IBM Watson Visual Recognition

IBM Watson Visual Recognitionは、IBMが提供するDeep Learningを利用した画像認識サービスです。

www.ibm.com

IBM Cloud上で利用することができ、APISDK経由で画像データの分類を行うことができます。

今回はpython用Watson Visual Recognitionモジュールを用いて画像分類をやってみます。

Usage

IBM Cloudアカウントの取得

まずはIBM Cloudのアカウントを取得しましょう。
下記記事に取得方法を記載してあります。

rennnosukesann.hatenablog.com

Visual Recognition サービスを作成する

次にIBM Cloud上でVisual Recognitionのサービスを作成します。

IBM Cloudダッシュボード画面にて、画面右上の「リソースの作成」ボタンを押します。

f:id:rennnosukesann:20180701184946p:plain

すると利用できるリソース一覧が表示されるので、一番下の「Watson」の項目一覧にある「Visual Recognition」をクリック。

f:id:rennnosukesann:20180701185216p:plain

遷移先画面の右下にある「作成」ボタンをクリック。

f:id:rennnosukesann:20180701185401p:plain

するとVisual Recognitionサービス詳細画面に移動します。
ここで表示されるAPIキーは後ほどpythonスクリプト上で利用します。

f:id:rennnosukesann:20180701185641p:plain

Watson Visual Recognitinoモジュールをインストール

pipを使い、python用Visual Recognitionモジュールをインストールします。

$ pip install --upgrade "watson-developer-cloud>=1.4.0"

これで準備完了です。

Source

以下にVisual Recognitionを利用した画像分類のスクリプト例を示します。
このスクリプトは、一枚の画像をVisual Recognitionに送信し、
その分類結果をJSON形式で標準出力する簡単なものです。

{API_KEY}にはVisual Recognition サービス作成時に取得したAPIキーを入力してください。

from watson_developer_cloud import VisualRecognitionV3, WatsonApiException


def recognize():
    WVR_VERSION = '2016-05-20'
    WVR_API_KEY = '{API_KEY}'
    FILE_PATH = 'cat.jpg' # 分類対象画像ファイル

    try:
        visual_recognition = VisualRecognitionV3(WVR_VERSION, iam_api_key=WVR_API_KEY)
        with open( FILE_PATH , 'rb') as image:
            # クラス分類:今回はすでに用意された分類器を使用
            results = visual_recognition.classify(images_file=image, classifier_ids=['default'])
        print(results)
    except WatsonApiException as ex:
        print(ex.message)


if __name__ == '__main__':
    recognize()

Demo

試しに、以下の画像を分類してみます。

f:id:rennnosukesann:20180701190447j:plain:w200

すると、以下ようなJSON形式で結果が返されます。
今回は猫の画像を上げたので、「猫」クラスのスコアや「動物」クラスのスコアが高いのがわかります。

{'images': [{'classifiers': [{'classifier_id': 'default', 'name': 'default', 'classes': [{'class': 'cat', 'score': 0.893, 'type_hierarchy': '/animal/mammal/carnivore/feline/cat'}, {'class': 'feline', 'score': 0.905}, {'class': 'carnivore', 'score': 0.905}, {'class': 'mammal', 'score': 0.906}, {'class': 'animal', 'score': 0.953}, {'class': 'tabby cat', 'score': 0.548, 'type_hierarchy': '/animal/mammal/carnivore/feline/cat/domestic cat/tabby cat'}, {'class': 'domestic cat', 'score': 0.713}, {'class': 'kitten', 'score': 0.5, 'type_hierarchy': '/animal/young/kitten'}, {'class': 'young', 'score': 0.508}, {'class': 'ash grey color', 'score': 0.849}, {'class': 'gray color', 'score': 0.571}]}], 'image': '../res/cat.jpg'}], 'images_processed': 1, 'custom_classes': 0}

参考

www.ibm.com

Visual Recognition - API reference | IBM Watson

【python】pipでファイル内に記述した複数モジュールを一括インストールする

メモ。

pip install -rで、ファイルに記述したモジュールを一括してインストールできる。

# インストールしたいモジュールを記述したファイル
$ cat hoge.txt 
asn1crypto==0.23.0
bleach==1.5.0
certifi==2017.11.5
cffi==1.11.2
chardet==3.0.4
cryptography==2.1.3
cycler==0.10.0
...

# 一括インストール
$ pip install -r hoge.txt
Collecting asn1crypto==0.23.0 (from -r hoge.txt (line 1))
 ...

入れたいモジュールを一気に入れられるのは便利だし、スクリプトを共有するときに依存モジュールを外部にまとめて書いておいてスクリプト内で自動一括インストール...みたいなことができるのも便利。

【Watson】Watson Studio でMNIST手書き文字認識を行う②【モデル学習・推論】

前回までのあらすじ

rennnosukesann.hatenablog.com

前回の記事では、Watson Studioのセットアップを行いました。 今回の記事では、実際にMNISTデータセットを使って手書き文字の学習とクラス分類を行います。

MNISTとは

MNISTとは、パターン認識機械学習の研究で頻繁に用いられる手書き文字画像データです。

f:id:rennnosukesann:20180620081207p:plain

手書き文字といってもアルファベットやひらがながすべて網羅されている・・・というわけではなく、0から9までの10種類の手書き文字のみから構成されています。データセットとしてシンプルでありながら十分な数のデータ数があるため、少し前はアルゴリズム・手法の性能を図るためのスタンダードなデータセットとして、現在は機械学習のHello,World的データセットとして用いられています。

それでは、早速Watson StudioでMNISTを学習してみましょう!

Usage

データセットを取得する

まずはデータがなければ始まらないので、MNIST手書き文字データセットをダウンロードします。

今回はWatson Studioに読み込ませるMNISTがほしいので、こちらからダウンロードします。

遷移先のページ右上にダウンロードボタンがあるので、クリックしてMNISTのpklファイルをダウンロードしましょう。

f:id:rennnosukesann:20180620082507p:plain

MNIST-pkl.zipがダウンロードできるので、解凍して

  • mnist-keras-test.pkl
  • mnist-keras-train.pkl
  • mnist-keras-valid.pkl
  • mnist-keras-test-payload.json

があることを確認します。

Watson Studioプロジェクトを作成する

前回の記事で作成したWatson Studioサービスのページに遷移し、「Get Started」をクリックします。

f:id:rennnosukesann:20180630002352p:plain

するとWatson Studioのトップページに遷移するので「Get started with key tasks」メニューの「New project」ボタンをクリックしてください。

f:id:rennnosukesann:20180630002551p:plain

するとプロジェクトの種類を選択するダイアログが出現します。
今回は深層学習を行うので、「Deep Learning」を洗濯して「OK」を押してください。

f:id:rennnosukesann:20180630002751p:plain

画面遷移時にMachine Learning・Object Storageサービスの作成が行われます(未作成の場合)。インストールしたいスペースを聞かれるので、Watson Studioと同じスペースを選択してください。

次にプロジェクト詳細を定義します。
先程作成したMachine Learning・Object Storageサービスが右側に表示されているか確認してください。設定されていなければ「Reload」ボタンを押してみてください。

問題がなければ「create」を押します。

f:id:rennnosukesann:20180630003359p:plain

データセットをWatson Studioに読み込ませる

ストレージが用意できたので、ダウンロードしたデータセットをWatson Studioにアップロードします。

Watson Studio画面トップのメニューバーのプルダウン「Service」をクリックし、次いで「Data Services」をクリックします。

f:id:rennnosukesann:20180630003839p:plain

「Cloud Object Storage」メニュー中にある、先ほど作成したObject Storageサービスをクリック。

f:id:rennnosukesann:20180630004026p:plain

バケットの作成」をクリック。

f:id:rennnosukesann:20180630004130p:plain

バケット作成ダイアログが出現するので、名前を入力してください。
念の為、ロケーションをus-geoにします。その後「作成」をクリック。

f:id:rennnosukesann:20180630004334p:plain

するとデータをアップロードする画面が表示されます。
右上の「アップロード」ボタンをクリックしてファイルダイアログを開き、ダウンロードしたpklファイルをすべてアップロードしてください。ドラッグ&ドロップでもアップロード可能です。

f:id:rennnosukesann:20180630004728p:plain

f:id:rennnosukesann:20180630004840p:plain

f:id:rennnosukesann:20180630005033p:plain

f:id:rennnosukesann:20180630004859p:plain

このような感じでアップロードできたらOK。

f:id:rennnosukesann:20180630005122p:plain

その後、同じように学習結果出力用のバケットも作成します。
先ほどとは別名のバケットをもう一つ作成してください。
データセットのアップロードは不要です。

f:id:rennnosukesann:20180630012301p:plain

モデルの作成

次に学習・クラス分類のためのモデルを作成します。

Watson Studioトップページに戻り、「Get started with key tasks」メニューの「New Modeler Flow」をクリック。

f:id:rennnosukesann:20180630005416p:plain

遷移先の画面の「From example」タブをクリック。
今回はすでに用意されているDeep Learningのモデルを使います。

f:id:rennnosukesann:20180630005611p:plain

遷移したら、「Single Convolution layer on MNIST」のカードメニューをクリックし、「Project」が冒頭で作成したプロジェクト担っていることを確認して「Create」をくりっくしてください。

f:id:rennnosukesann:20180630005824p:plain

すると何やら数珠つなぎになった図が表示されます。
これはDeep Learningで用いられる「ニューラルネットワーク」と呼ばれる学習モデル(と最適化アルゴリズム等のオプション)の構成を表しており、これらの構成自体や、各パーツのパラメータを調整することでモデルの推論精度を高めたりすることができます。

一旦モデルの構造には変更を加えず、モデルの学習・テストに使うデータを設定します。

「Image Data」をダブルクリックすると下記サイドメニューが表示されるので、「Create a Connection」をクリックしてください。 Object Storageに接続します。

f:id:rennnosukesann:20180630010244p:plain

接続がうまく行った場合、「Data Connection」プルダウンが表示されるので、「Connect to project COS」を選択してください。すると続けて「Buckets」プルダウンが表示されるので、先程アップロードしたデータを含むバケットの名称を選択します。
その後「Train data file」「Test data file」「Validation data file」の所在を聞かれるのでそれぞれアップロード舌ファイルを選択し、「Close」をクリック。

f:id:rennnosukesann:20180630010835p:plain

最後にモデルを公開します。
画面右上のアップロードボタンをクリック。

f:id:rennnosukesann:20180630010954p:plain

ダイアログが出てくるので、名前が先ほど作成したモデル名であり、WML Instance の名前が冒頭で作成したサービスのものと一致するかチェックして「Publish」をクリック。

f:id:rennnosukesann:20180630011150p:plain

緑色の通知が出てきたら成功です!
さらにモデルの学習をすべく「or Train it in an experiment」をクリックしましょう。

f:id:rennnosukesann:20180630011339p:plain

モデルを学習する

先程のリンクをクリックすると、Experiment作成画面に遷移します。
Experimentはモデルの学習やテスト、精度推移の可視化などができる実験環境の単位を指します。

名前を入力し、作成したMachine Learning Serviceを選択してください。

f:id:rennnosukesann:20180630012858p:plain

その後下段の「Cloud Object Storage bucket for...」の「Select」ボタンをクリック。

f:id:rennnosukesann:20180630011832p:plain

「Cloud Object Storage connection」から「Connection to project COS」を選択し、 「Bucket containing training data」にはデータセットをアップロードしたバケットを、「Bucket for storing training results」には学習結果出力用のバケットを指定します。 指定したら「Select」をクリック。

f:id:rennnosukesann:20180630011955p:plain

新規experiment作成画面に戻り、「Add training definition」をクリックします。

f:id:rennnosukesann:20180630012910p:plain

先程作成したモデルを指定するため、「Existing training definition」タブ → 作成したモデル名を選択します。

f:id:rennnosukesann:20180630013223p:plain

すると「Training definition attributes」メニューが表示されます。 「Compute plan」はモデルの学習・テストに使う計算機リソースの構成のうち、どのGPUをどれだけ利用するかを選択します(台数や一台の性能が良いほどメモリや並列性が増し、学習やテストが高速になる)。「Hyperparameter optimization method」はモデルを学習する上でハイパパラメタ、つまり学習の際に予め設定しておくパラメータ初期値をどのように決定するかを指定します。今回は前者を「1 x NVIDIA® Tesla® K80 (2 GPU)」とし、校舎を「None」としました。選択したら「Select」をクリック。

f:id:rennnosukesann:20180630013722p:plain

「Create and Run」を押しましょう。

f:id:rennnosukesann:20180630013921p:plain


学習が開始されました!

遷移先の画面ではモデルの学習中の様子を見ることができます。 学習中のモデルの状態は「Queued」「In progress」「Completed」の順に遷移していき、「Completed」になると学習が終了したことを表します。

f:id:rennnosukesann:20180630014148p:plain

終了したら、詳細を見てみましょう。

f:id:rennnosukesann:20180630014516p:plain

学習が完了していることがわかります。

f:id:rennnosukesann:20180630014543p:plain

Logsには学習時のコンソールログも残されており、学習回数や、学習時点での学習データに対する分類精度等を見ることができます。

f:id:rennnosukesann:20180630014722p:plain

学習したモデルを保存する

学習したモデルは、保存して利用できるようになります。

先程の「Completed」状態にあるモデルの右端のメニュープルダウンから「Save model」を選択します。

f:id:rennnosukesann:20180630015326p:plain

保存用ページに遷移するので、名前を入力し、「Save」ボタンを押しましょう。

f:id:rennnosukesann:20180630015624p:plain

成功すると、緑色の通知が出ます。

f:id:rennnosukesann:20180630015712p:plain

「here」をクリックすることで、保存したモデルの詳細を見ることができます。 (またはメニューバー「Project」から作成したプロジェクトの「Assets」タブに遷移し、「Experiments」の項目で「Add Experiment」をクリックします)

保存したモデルをデプロイする

次に、保存したモデルをデプロイします。
デプロイすると、テストデータを使った検証や、API経由で分類器を提供することが可能になります。

今回はWeb Service としてデプロイしてみましょう。

先程のモデル詳細画面の「Deployments」タブをクリックします。

f:id:rennnosukesann:20180630020023p:plain

「Add Deployment」をクリック。

f:id:rennnosukesann:20180630020050p:plain

遷移先の画面

f:id:rennnosukesann:20180630020144p:plain

今回はテストデータセットを使った性能評価を行うので「Deployment type」の「Web Service」を選択します。 あとは名前を入力して「Save」をクリックします。

これだけでデプロイ完了です! 早速テストしてみましょう!

デプロイしたモデルをテストする

デプロイした結果作成されたDeployをクリックし、「Test」タブをクリックします。

f:id:rennnosukesann:20180630021900p:plain

f:id:rennnosukesann:20180630164518p:plain

冒頭でダウンロードしたmnist-keras-test-payload.jsonの拡張子を.htmlに変更します。 変更したあと、ブラウザでHTMLファイルを開きます。

f:id:rennnosukesann:20180630164744p:plain

開いたページのJSONファイルをコピーし、先程のDeploy画面のTestタブ内にあるフォームにペーストしてください。

f:id:rennnosukesann:20180630164850p:plain

「Predict」をクリックすると、クラス分類が開始されます。
元のJSONデータは数字の「7」を記した画像の濃淡値データを表しているので、帰ってきたクラス分類結果が「7」であれば分類成功です。

f:id:rennnosukesann:20180630165045p:plain

結果が帰ってきました!
レスポンスJSONvalues内配列の8番目の数値が1の場合、これは数字の7であるという分類結果になります。 上記画像では分類に成功していることがわかります。

まとめ

いかがだったでしょうか。

今回はMNIST分類の簡単な学習とテストを行いましたが、より複雑なモデルの構築、学習、テストももちろん可能です。
pythonスクリプトへのエクスポートなどもできるので、これからどんどん試していこうと思います。

参考

www.ibm.com

Neural network modeler - IBM Watson

qiita.com

【Java】Jacksonで任意形式のJSONをパースする

Jackson

Jacksonについては以下の記事を参照。

rennnosukesann.hatenablog.com

多様なJSONの構造

前回の記事で、JSONをMapオブジェクトにする記事を書きました。

rennnosukesann.hatenablog.com

JacksonではJSONファイルやStringオブジェクトとしてのJSONJavaクラスのオブジェクトに簡単にマッピングしてくれます。
この記事のように、JSONをMapオブジェクトに変換することも可能です。

しかし、各プロパティの値が階層的にオブジェクトになっている場合は、Map<String, Object>でごまかすか、 Map<String,Object>Map<String, Map<String, Object>>>のようにわかる範囲までジェネリクス型を明示してあげる必要があります。
更に後者の場合、各プロパティの階層レベルがすべて等しくなければパースに失敗します。

コンテナとなるJavaクラスを定義することでもパースが可能ですが、JSONのパターンの数だけJavaクラスを定義しなければならなくなり、面倒です (新しいパターンが増えたらまたクラスを定義する必要もあります)。

任意の構造を持つJSONを読み込む

Jacksonでは、ObjectMapperクラスのメソッドreadTree()を用いることでこの問題を解決できます。

String json = "{ ... }"; // JSON形式文字列
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);

readTree()JsonNodeオブジェクトを返します。
JsonNodeJSON木構造に見立てたときのノード(枝)として振る舞い、ノードに格納された値を参照したり、小ノードを参照することができます。

Source

JSON
{
  "hoge": {
    "fuga": 1,
    "piyo": 2
  },
  "foo": ["bar", "bow"]
}
Source
package com.company;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jdk.nashorn.internal.runtime.regexp.JoniRegExp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.spec.ECParameterSpec;

public class Main {

    public static void main(String[] args) {

        String json = readJsonAsString("res/hoge.json");

        if (json != null) {
            try {
                readJsonNode(json);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *
     * readTree()でJsonNodeインスタンスを作成
     *
     */
    private static void readJsonNode(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        // JSON文字列を読み込み、JsonNodeオブジェクトに変換(Fileやbyte[]も引数に取れる)
        JsonNode root = mapper.readTree(json);

        // get()で指定したキーに対応するJsonNodeを取得できる
        System.out.println(root.get("hoge")); // {"fuga":1,"piyo":2}

        // 階層的にアクセス可能
        System.out.println(root.get("hoge").get("fuga")); // 1

        // 配列にアクセスするときは添字をわたす
        System.out.println(root.get("foo").get(0)); // "bar"

        // 値を特定の基本型に変換して取得可能
        System.out.println(root.get("hoge").get("piyo").asInt()); // 2
        System.out.println(root.get("hoge").get("piyo").asDouble()); // 2.0
        System.out.println(root.get("hoge").get("piyo").asBoolean()); // true

        // toString()でJSON全体を文字列として取得
        System.out.println(root.toString()); // {"hoge":{"fuga":1,"piyo":2},"foo":["bar","bow"]}

    }


    /**
     *
     * JSONファイルを一つの文字列オブジェクトとして読み込み
     *
     */
    private static String readJsonAsString(String filename) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(new File(filename)));
            String line = null;
            StringBuilder builder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

参考

github.com

【Java】JacksonでJson文字列をMapオブジェクトに変換する

Jackson

Jacksonについてはこちら。

rennnosukesann.hatenablog.com

JacksonはJavaのライブラリで、JavaオブジェクトをJSON形式にしたり、その逆のこともできます。もちろんJSONファイルへの読み書きも可能です。

JSONをMapオブジェクトに変換する

Jacksonでは、JSON文字列をJavaオブジェクトに変換することができますが、 変換の方法の一つに、JSONのプロパティと同じ名称のプロパティを持つJavaクラスを用意するやり方があります。

public class JSONResponse {
    private String name;
    private String age;
}
// JSON文字列であるjsonをJSONResponse型オブジェクトに変換
JSONResponse response = mapper.readValue(json, JSONResponse.class);

JSONのプロパティがいつも同じであれば問題はないのですが、
例えば異なるAPIのレスポンスを処理する場合などに、レスポンスごとの個別のコンテナクラスを作成する必要があります。

そんなときは、JSONをMapオブジェクトに変換してしまいましょう。
JacksonのTypeReferenceオブジェクトを利用することでJSONからMap型オブジェクトを生成することができます。

TypeReference<HashMap<String, String>> reference = new TypeReference<HashMap<String, String>>() {};
Map<String, String> map = mapper.readValue(json, reference);