10分で出来る!初めてのTwitter4J & Twitterアプリ作り方メモ in 2015-10-18
最近はJava EE系でもJAX-RS研修の担当が多くなっている関係上、OAuthやRESTクライアントにも興味が出てきました。ということで、初めてTwitter4Jでプログラムを作ってみました。参考にしたのは、@kikutaro_さんのこちらのブログです。
Twitter4Jを使ったら10分でつぶやきJavaプログラムが作れました! ~NetBeans編~ - Challenge Java EE !
分かりやすくまとまっていて、基本的な手順は今も変わっていないのですが、管理画面のUIが変わっていたので、本日時点での画面キャプチャ付きで解説します。
目標
Twitter4Jを使って、Javaのmain()メソッドからつぶやきを送信する!
Twitter Developer登録
プログラムを作る前に、Twitter Developer登録を行って、アプリ開発に必要なアクセストークンなどの情報を取得します。この手順は、JavaやTwitter4Jによらないはずです。
まず、下記のTwitterのDeveloperサイトにアクセスします。
すると、トップ画面が表示されます。画面右上のリンクから、ご自分のTwitterアカウントでサインインしてください。このアカウントは、普段のつぶやきなどで使っているアカウントでOKです。
トップ画面で下の方にスクロールして、[TOOLS]-[Managing Your App]をクリックします。
すると、アプリケーションの管理画面に移ります。まだ何もアプリケーションを作っていないので、[Create New App]ボタンだけが表示されます。
では、[Create New App]ボタンをクリックします。すると、アプリケーションの作成画面に移ります。適当なアプリケーション名、アプリの説明、自分のブログなどのURLを入力します。[Callback URL]は必須項目ではないので、今回は空欄のままにします。
上記の画面で下の方にスクロールすると、[Developer Agreement]が記載されているので、内容を確認した上で[Yes, I agree]にチェックを入れて、[Create your Twitter app]ボタンをクリックします。
そうすると、下記のような画面が表示されます。[Consumer Key]の部分は、後で使います。実際には英数字&記号の羅列が表示されていますが、秘密の情報のため画像を加工して伏せています。
次に、この画面の[Keys and Access Tokens]タブをクリックします。表示されている[Consumer Key (API Key)]と[Consumer Secret (API Secret)]という2つの文字列は、後で使います。
この画面で下の方にスクロールして、[Create my access token]ボタンをクリックします。
画面が遷移するので、また下の方にスクロールすると、[Access Token]と[Access Token Secret]が表示されています。この2つの文字列も、後で使います。
以上で、準備は完了です。
Twitter4JでJavaプログラムを作る
さて、後は簡単です。IDEはEclipseでもNetBeansでもIntelliJ IDEAでも何でも構いません。ビルドツールは、MavenまたはGradleを使います。
まず、Twitter4Jを依存性に含めます。
Gradleならこうです。
compile 'org.twitter4j:twitter4j-core:4.0.4'
<dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>4.0.4</version> </dependency>
次に、src/main/resourcesに「twitter4j.properties」というプロパティファイルを作ります。そして、下記のように記述します。
debug=true #右辺にConsumer Key (API Key)をコピーして貼り付ける oauth.consumerKey=XXXXXXXXXXXXXXXX #右辺にConsumer Secret (API Secret))をコピーして貼り付ける oauth.consumerSecret=XXXXXXXXXXXXXXXXXX #右辺にAccess Tokenをコピーして貼り付ける oauth.accessToken=XXXXXXXXXXXXXXXX #右辺にAccess Token Secretをコピーして貼り付ける oauth.accessTokenSecret=XXXXXXXXXXXXXXXX
src/main/javaにクラスを作ります。菊田さんのブログのプログラムそのままです(^^;
import twitter4j.*; public class UserInfoMain { public static void main(String[] args) throws TwitterException { Twitter twitter = TwitterFactory.getSingleton(); User user = twitter.verifyCredentials(); System.out.println(user.getName()); System.out.println(user.getScreenName()); System.out.println(user.getFriendsCount()); System.out.println(user.getFollowersCount()); Status status = twitter.updateStatus("Twitter4Jから初めてのツイート! #twitter4j"); } }
これだけです。いざ、実行します。すると・・・
多田真敏 suke_masa 63 199 . . . (他にもデバッグログがいっぱい表示されます)
おおお、自分のユーザー情報が表示されて、つぶやきが投稿されてる!
まとめ
- Developer登録をして、アクセストークンなどの情報を取得する
- アクセストークンなどは、コピーしてtwitter4j.propertiesに貼り付ける
- Twitter4J使えば、REST APIやらJSONやら認証やらのコードは書かなくてOK!
感想
あまりに簡単すぎて感動すら覚えました・・・。
Twitter4Jのソースも、これから読んでみたいと思います!
Payara(GlassFish)でMariaDBのJDBC接続プールが作成できない
表題の通りです。
環境
- MacBook Air (OS X El Capitan)
- MariaDB 10.1.x
- Payara Web 4.1.153
- JDK 1.8.0_60
試していませんが、おそらくWindowsやGlassFishでも同じ現象が起こると思います。
現象
- MariaDBのJDBCドライバのJARを「<PAYARA_HOME>/glassfish/lib」や「<PAYARA_HOME>/glassfish/domains/domain1/lib」に置く
- Payaraを起動してlocalhost:4848にアクセスし、管理コンソールからURL/USER/PASSWORDを設定する
という一般的な手順で作成しても、MariaDBへのpingが通りません。
ping時のPayara管理コンソール(ブラウザ上)でのエラーメッセージは、こんなのが出ます。
Access denied for user ‘’@’localhost’ (using password: NO)
どうやら、ユーザー名やパスワード設定が間違っている時に出てくるMariaDBのエラーメッセージのようなのですが、全く同じURL/USER/PASSWORDでメインメソッドから普通にJDBC接続したら出来ました。 (URL/USER/PASSWORDはPayara管理コンソールからコピペしたので間違いないはずです)
Payaraのプロパティ名も間違えていません。
しかも、ごくたまにpingが通ります。しかし、またすぐにpingが通らなくなります。
対策
今回は、MariaDBをPayaraで使うこと自体が目的ではないので、MySQL 5.6に変更しました。そうすると無事にJDBC接続プールが作成できました。
原因は分かりませんが、Payara管理コンソールで選択するときのDBの種類にはMariaDBは入っていないし、Payara(というか恐らくGlassFish)はMariaDBに対応していないのかもしれません。 (完全に僕の憶測です)
注意
この問題は、あくまでPayara+MariaDBの組み合わせによるものです。
【注意事項あり】Doma 2だけどCDI/EJB使ってJTAでトランザクション管理したい!そしてJAX-RSでREST作りたい!
Doma 2とは?基本的な使い方は?
Doma 2は、SQLを外部ファイルに書くことができるORマッパーです。ネイティブSQLが書けること、依存ライブラリが無い事、国産 OSSで日本語ドキュメントが充実している事などが魅力です。
下記の記事もご参考になさってください。2014年のJavaアドベントカレンダー向けに書いたものです。
美しき青きDoma!~SQLとIDEが奏でる美しきORマッピング~ - Java EE 事始め!
Domaでは、プログラマが作るのはHogeDaoインターフェイスだけで、その実装クラスHogeDaoImplはGradleでビルド時にAnnotation Processorで自動生成されます。
CDI/EJB使ってHogeDao型のフィールドにHogeDaoImplのインスタンスをインジェクションしたり、JTAでトランザクション管理するには、実装クラス側(HogeDaoImpl)に@RequestScoped
(CDI)や@Stateless
(EJB)などのアノテーションを付加する必要があります。
しかし、実装クラスはビルド時に生成されるし、生成後に手作業でアノテーションを付けても、再ビルド時に上書きされて消えてしまいます。
アノテーションをつける方法がずっと分からなかったのですが、遂にやり方が分かったのでご紹介します。
ソースはGitHubに公開しています。
MasatoshiTada/doma-jaxrs · GitHub
APサーバーはPayara Web 4.1.153ですが、Jerseyには依存しないように書いたので、WildFlyでもそのまま動作します(9.0.1.Finalで確認済み)。DBはMySQL 5.6、IDEはIntelliJ IDEA 14.1.5です。
CDI/EJBとJTAについて
これ以降の内容は、CDI/EJBとJTAの知識が前提となります。下記の資料が参考になります。
JavaDayTokyo2015での寺田さんの発表資料です。CDIについて詳しくまとまっています。
http://www.oracle.co.jp/jdt2015/pdf/2-2.pdf
@opengl-8080さんのJTAの解説ブログです。いつもながら勉強になります。
アノテーションをつける答えは@AnnnotateWith
ツイッターである方々のやり取りを見ていたら、Doma 2の公式ドキュメントの一部が目に入りました。
http://doma.readthedocs.org/ja/stable/config/#id22
@AnnnotateWith
というアノテーションを使っていますね。これがポイントです。
1.アノテーションの自作
まず、こんなアノテーションを自作します。自作するアノテーション名は任意ですが、公式ドキュメントに従って@InjectConfig
という名前にしておきます。
CDIの場合
package com.example.dao.config; import org.seasar.doma.AnnotateWith; import org.seasar.doma.Annotation; import org.seasar.doma.AnnotationTarget; import javax.enterprise.context.Dependent; import javax.inject.Inject; @AnnotateWith(annotations = { @Annotation(target = AnnotationTarget.CLASS, type = Dependent.class) , @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Inject.class) }) public @interface InjectConfig { }
EJBの場合
package com.example.dao.config; import org.seasar.doma.AnnotateWith; import org.seasar.doma.Annotation; import org.seasar.doma.AnnotationTarget; import javax.ejb.Stateless; import javax.inject.Inject; @AnnotateWith(annotations = { @Annotation(target = AnnotationTarget.CLASS, type = Stateless.class) , @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Inject.class) }) public @interface InjectConfig { }
注意!! Payara 4.1.1.154までのAPサーバーでは、CDI+JPA以外のORマッパー(というよりJDBC)では、JTAが正しく動作しない可能性があることが判明しました。なので、現段階ではEJBを使ってください。このことについては、PayaraのGitHubにIssueとして報告済みです。次バージョンでの改善を期待しています。WildFlyでは、CDIでもEJBでも正しく動作します。 参考URL @OpenGL_8080さんのブログ(コメント欄をご確認ください) JavaEE使い方メモ(JTA) - Qiita PayaraのGitHub Payara does NOT rollback when RuntimeException occurs in CDI @Transactional method using JDBC · Issue #505 · payara/Payara · GitHub
@Annotation
のtype属性はアノテーション名.class、target属性はtypeで指定したアノテーションを付加する対象を表します。
この例だと、クラスに@Dependent
、コンストラクタに@Inject
を付けるということになります。
2. 自作アノテーションをDaoインターフェイスに付加
次に、自作した@InjectConfing
アノテーションを、自作Daoインターフェイスに付加します。
package com.example.dao; import com.example.dao.config.InjectConfig; import com.example.entity.Employee; import org.seasar.doma.Dao; import org.seasar.doma.Script; import org.seasar.doma.Select; import java.util.List; import java.util.Optional; @Dao @InjectConfig public interface EmployeeDao { @Script void create(); @Select Optional<Employee> selectById(Integer empId); @Select List<Employee> selectLikeName(String name); }
3.Gradleでビルド
Gradleでビルドすると、EmployeeDao
インターフェイスの実装クラスが生成されます。
CDIの場合
package com.example.dao; /** */ @javax.enterprise.context.Dependent() @javax.annotation.Generated(value = { "Doma", "2.5.0" }, date = "2015-10-15T20:48:55.929+0900") public class EmployeeDaoImpl extends org.seasar.doma.internal.jdbc.dao.AbstractDao implements com.example.dao.EmployeeDao { /** * @param config the config */ @javax.inject.Inject() public EmployeeDaoImpl(org.seasar.doma.jdbc.Config config) { super(config); }
EJBの場合
package com.example.dao; /** */ @javax.ejb.Stateless() @javax.annotation.Generated(value = { "Doma", "2.5.0" }, date = "2015-10-15T20:48:55.929+0900") public class EmployeeDaoImpl extends org.seasar.doma.internal.jdbc.dao.AbstractDao implements com.example.dao.EmployeeDao { /** * @param config the config */ @javax.inject.Inject() public EmployeeDaoImpl(org.seasar.doma.jdbc.Config config) { super(config); }
@AnnnotateWith
で指定した通り、クラスに@Dependent
または@Stateless
、コンストラクタに@Inject
が付加されています。これで、このEmployeeDaoImpl
を他のクラスにCDIでインジェクトできるようになります。
また、コンストラクタには@Inject
が付加されています。
引数のConfig
インターフェイスは、データソースなどを保持するもので、後ほど実装クラスを作成します。
Config
実装クラスを作成して@ApplicationScoped
などを付加しておけば、この実装クラスのインスタンスが、コンストラクタインジェクションされます。
4. Config
実装クラスの作成
package com.example.dao.config; import org.seasar.doma.jdbc.Config; import org.seasar.doma.jdbc.dialect.Dialect; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.sql.DataSource; @ApplicationScoped public class AppConfig implements Config { @Inject private DataSource dataSource; @Inject private Dialect dialect; @Override public DataSource getDataSource() { return dataSource; } @Override public Dialect getDialect() { return dialect; } }
@ApplicationScoped
を付加してCDI管理ビーン(このクラスはEJBでなくでOKです)にします。アプリケーションに関する設定情報を保持するクラスなので、スコープはアプリケーションスコープが適切と思われます。
DataSource
とDialect
については、別途プロデューサークラスを作成して、@Inject
で取得できるようにしています。
package com.example.dao.config; import org.seasar.doma.jdbc.dialect.Dialect; import org.seasar.doma.jdbc.dialect.MysqlDialect; import javax.annotation.Resource; import javax.enterprise.context.Dependent; import javax.enterprise.inject.Produces; import javax.sql.DataSource; import java.io.Serializable; @Dependent public class DataSourceProducer implements Serializable { @Resource(lookup = "jdbc/sandbox") private DataSource dataSource; private Dialect dialect = new MysqlDialect(); @Produces public DataSource getDataSource() { return dataSource; } @Produces public Dialect getDialect() { return dialect; } }
このクラスもEJBでなくてOKです。
訂正とお詫び:@Resource
でJDBCリソースを取得する際、name
属性を使っていたのですが、正しくはlookup
属性でした。訂正してお詫びします。
Config
実装クラスが複数ある場合は?
データソースが複数ある場合など、Config
実装クラスが複数になる可能性があると思います。その場合はQualifierを自作して、それをConfig
実装クラスと@AnnotatedWith
に追加すれば良いはずです。
@AnnotateWith(annotations = { @Annotation(target = AnnotationTarget.CLASS, type = Dependent.class) , @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Inject.class) , @Annotation(target = AnnotationTarget.CONSTRUCTOR_PARAMETER, type = 自作Qualifier1.class }) public @interface InjectConfig1 { }
@ApplicationScoped @自作Qualifier1 public class AppConfig1 implements Config { // 省略 }
@AnnotateWith(annotations = { @Annotation(target = AnnotationTarget.CLASS, type = Dependent.class) , @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Inject.class) , @Annotation(target = AnnotationTarget.CONSTRUCTOR_PARAMETER, type = 自作Qualifier2.class }) public @interface InjectConfig2 { }
@ApplicationScoped @自作Qualifier2 public class AppConfig2 implements Config { // 省略 }
JTAでトランザクション管理する
DataSource
は@Resource
で取ってきているし、DaoImplクラスはCDI管理にできたので、後は簡単です。
CDIの場合
package com.example.service; import com.example.dao.EmployeeDao; import com.example.entity.Employee; import com.example.resource.dto.EmployeeDto; import javax.enterprise.context.Dependent; import javax.inject.Inject; import javax.transaction.Transactional; import java.io.Serializable; import java.util.Optional; @Dependent public class EmployeeService implements Serializable { @Inject private EmployeeDao employeeDao; @Transactional(Transactional.TxType.REQUIRED) public Optional<EmployeeDto> selectById(Integer empId) { Optional<Employee> employeeOptional = employeeDao.selectById(empId); return employeeOptional.map(this::convertToDto); }
EJBの場合
package com.example.service; import com.example.dao.EmployeeDao; import com.example.entity.Employee; import com.example.resource.dto.EmployeeDto; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.inject.Inject; import java.io.Serializable; import java.util.Optional; @Stateless public class EmployeeService implements Serializable { @Inject private EmployeeDao employeeDao; @TransactionAttribute(TransactionAttributeType.REQUIRED) public Optional<EmployeeDto> selectById(Integer empId) { Optional<Employee> employeeOptional = employeeDao.selectById(empId); return employeeOptional.map(this::convertToDto); }
@Inject
でインジェクトすると、EmployeeDaoImpl
のインスタンスが注入されます。で、メソッドに@Transactional
を付加すればOK!
JAX-RSでRESTを作る
package com.example.resource; import com.example.resource.dto.EmployeeDto; import com.example.service.EmployeeService; import org.hibernate.validator.constraints.NotBlank; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.validation.constraints.Pattern; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path("employees") @RequestScoped public class EmployeeResource { @Inject private EmployeeService employeeService; @GET @Path("{empId}") @Produces(MediaType.APPLICATION_JSON) public Response selectById(@PathParam("empId") @Pattern(regexp = "[1-9][0-9]*") String empIdStr) { Integer empId = Integer.valueOf(empIdStr); EmployeeDto employeeDto = employeeService.selectById(empId) .orElseThrow(() -> new NotFoundException("該当する社員が見つかりませんでした")); return Response.ok(employeeDto).build(); } }
感想
これで去年からの疑問点が解決しました。ようやっとスッキリです。
あとはDomaの使い方さえ知れれば、怖いものなし・・・のはず!
併せて読みたい
うらがみさんのブログ。Doma+JAX-RS連携について書かれています。
Thymeleaf + JAX-RS + DomaをGlassFishで試してみる - 裏紙
今回利用した、@siosioさん作のIntelliJ IDEA Doma Support Plugin
IntelliJ IDEA用のDomaプラグイン作ってみた - しおしお
Doma公式ドキュメント
Welcome to Doma — Doma 2.0 ドキュメント
Domaにこの機能が入った経緯のブログ記事です。
MVC 1.0 EDR2リリース&変更点解説!
公式資料
MVC 1.0のアーリードラフト第2版がリリースされました!
JSR 371はこちら
JSR-000371 Model-View-Controller Early Draft Review 2
Ozark(MVC 1.0の参照実装)のソースコードはこちら
僕の解説資料
スライド資料
それに伴って、先月のGlassFish勉強会で発表した資料も更新しました。
www.slideshare.net
サンプルコード
GitHubのサンプルコードも修正しましたので、git cloneしてお使いください。
GlassFish勉強会の時は、mvc-specとozark)をgit cloneしてローカルでMavenでビルドして使ってたんですが、MavenにEDR2版がアップされているので、pom.xmlを編集しました。
EDR1->EDR2の大きな変更点
セキュリティ機能
ValidtionResult->BindingResult
バリデーション結果を保持するインターフェイスが、BindingResultに変更になりました。
MvcContextの追加
アプリケーションのパスなどを取得できるメソッドが用意されています。EL式からは${mvc}で参照できます。
リダイレクト
コントローラーで返すビューへのパスに接頭辞「redirect:」をつけることで、リダイレクトが可能になりました。また、@RedirectScoped
というCDIスコープアノテーションも追加され、リダイレクト先にも値を渡せるようになりました。
次のリリースは?
来年の3月31日の予定です。
CDI/JTAを使うなら読んでおきたいリンクまとめ
日本語書籍
「わかりやすいJava EE」「Java EE 7徹底入門」です。
金魚本およびEE 5本には記載がありません。
まず概要を掴む
CDIに関しては、まずは下記の上妻さんの記事をご確認ください。バージョンが上がるごとに注意点をまとめていらっしゃいます。順番に読んでいただければOKです。
CDI 1.0 (Java EE 6)
CDI 1.1 (Java EE 7)
Java EE環境におけるCDIのデフォルト化 - 見習いプログラミング日記
CDI 1.2 (Java EE 7)
CDI1.2によるbean-discovery-modeの見直し - 見習いプログラミング日記
CDI 1.0から2.0 + αまで (Java EE 6, 7, 8)
CDI2.0アップデート&クックブック #JavaDayTokyo #jdt2016_4c
寺田さんの資料
Java Day Tokyo 2015の寺田さんの資料を見ていただくと、CDIのその他の機能が一通り学習できます。
PDF(直リンク)
http://www.oracle.co.jp/jdt2015/pdf/2-2.pdf
動画
【Java Day Tokyo 2015】 [2-2] Java EE 7エッセンシャル・レシピ - YouTube
羽生田さんの資料
2016年2月のJJUGナイトセミナーでの資料です。
BeanManagerなど、上記の資料では載っていないことまで解説されています。
各機能の詳細な使い方
こちらの記事が、きれいにまとまっています。openglさんのブログは本当に凄い・・・。
JTA(トランザクション管理)
多分どこよりも早いJSON-B解説(Java EE 8・Java API for JSON Binding)
JSON-Bって何?
Java EE 8で追加される予定の、JavaオブジェクトとJSONの相互変換を行う機能です。例えば、下記のようなJAX-RSコードがあるとします。
public class Employee { private int id; private String name; private java.time.LocalDate joinedDate; // コンストラクタ、setter、getterは省略 } @Path("employee") public class EmployeeResource { @GET @Produces("application/json") public Response getEmployee() { Employee emp = new Employee(100, "Hoge", LocalDate.of(2015, 4, 1)); return Response.ok(emp).build(); } }
で、http://localhost:8080/sample/api/employee
のようなURLにGETリクエストを送ると、下記のようなJSONが返ってきます。
{ "id" : 100, "name" : "Hoge", "joinedDate" : "2015-04-01" }
実は今まで、JAX-RS(およびJava EE)自体にはJavaオブジェクトをJSONに変換する機能を持っていませんでした。このJSON変換の部分は、APサーバーが内包している「JSONパーサー」と呼ばれる別ライブラリ(EclipseLink MOXy、Jackson、Jettisonなど)が行っています。Java EE 7で「JSON Processing (JSON-P)」という機能が追加されましたが、これはJSONを動的に読み書きするもので、前述のJSONパーサーのような、オブジェクトを一括でJSONに変換するものではありません。
そこで、JSONパーサーをJava EE標準に取り入れようということで、Java EE 8に追加される予定の機能が「JSON-B」です。2015年8月に、JSR 367のEarly Draft第1版が公開されました。下記のURLからダウンロード可能です。ダウンロードできるZIPには、クラスファイル・ソース・JavadocのJARが1つずつ、およびJSR文書のPDFが含まれています。
JSR-000367 Java API for JSON Binding Early Draft Review
ただし、JSRで決まっているのはほとんどインターフェイス・アノテーション・例外なので、プログラムとして動かすためには「実装」が必要になります。しかしJSON-Bの参照実装(公式の実装)であるEclipseLink MOXyには、探した限りではまだJSON-B実装が含まれていないようです。そこで今回は、JSRやJavadocから分かる範囲で、JSON-Bの仕様を解説したいと思います。プログラムとしての作成・実行を確認できていないので、その点はご了承くださいm( )m
JavaオブジェクトとJSONの相互変換
変換の中心となるのは、javax.json.bind.Jsonb
インターフェイスです。ただし、Jsonbインターフェイスについては、まだJSRには記載されていませんので、Javadocに載っていたサンプルコードからご紹介します。
Javaオブジェクト→JSONへの変換(マーシャリング)
JsonbインターフェイスのtoJson()メソッドを使います。
Employee emp = new Employee(100, "Hoge", LocalDate.of(2015, 4, 1)); // Jsonbオブジェクトの取得 Jsonb jsonb = JsonbBuilder.create(); // JavaオブジェクトをJSON文字列に変換する String json = jsonb.toJson(emp);
toJson()メソッドはオーバーロードされており、第2引数にOutputStreamを指定することも可能です。
jsonb.toJson(emp, new PrintWriter(System.out));
他にも、引数が違うtoJson()メソッドがいくつか存在します。
JSON→Javaオブジェクトへの変換(アンマーシャリング)
JsonbインターフェイスのfromJson()メソッドを使います。
String json = "{\"id\":100,\"name\":\"Hoge\",\"joinedDate\":\"2015-04-01\"}"; Employee emp = jsonb.fromJson(json, Employee.class);
fromJson()メソッドはオーバーロードされており、第1引数にInputStreamを指定することも可能です。
InputStream is = …;
Employee emp = jsonb.fromJson(is, Employee.class);
他にも、引数が違うfromJson()メソッドがいくつか存在します。
JAX-RSでの利用について
これは予測ですが、Java EE 8でJAX-RSを利用する際は、上記のようなtoJson() / fromJson()を使ったコードを書く機会は、そんなに多くないと思います。おそらく、JSON-Bを利用したMessageBodyWriter / MessageBodyReader(JSONパーサーを呼び出して、実際にJSON変換を行うJAX-RSのクラス)が、JAX-RS実装内(Jersey、RESTEasyなど)で組み込みで提供されるはずです。しかし、MessageBodyWriter / MessageBodyReaderを自分でカスタマイズしたい場合は、上記のようなコードを書く機会があるかもしれません。
対応しているデータ型
基本的なデータ型
- java.lang.Character
- java.lang.Byte
- java.lang.Short
- java.lang.Integer
- java.lang.Long
- java.lang.Float
- java.lang.Double
- java.lang.Boolean
- 上記に対応するプリミティブ型
- java.lang.String
日付
コレクション
リスト・セット・マップのほぼ全て、および配列
JSON-P
- javax.json.JsonObject
- javax.json.JsonArray
- javax.json.JsonStructure
- javax.json.JsonValue
- javax.json.JsonPointer
- javax.json.JsonString
- javax.json.JsonNumber
その他
- Enum
- java.math.BigInteger
- java.math.BigDecimal
- java.net.URL
- java.net.URI
- java.util.Optional
- java.util.OptionalInt
- java.util.OptionalLong
- java.util.OptionalDouble
マッピングのカスタマイズ
特定のフィールドをJSONに含めたくない
JSONに含めたくないフィールドに@javax.json.bind.annotation.JsonbTransient
アノテーションを付加します。
public class Employee { // idはJSONに含まれない @JsonbTransient private int id; … }
nullの場合もJSONに含めたい
デフォルトのルールでは、null値のフィールドはJSONに含まれません。nullの場合もJSONに含めたい場合は、@javax.json.bind.annotation.JsonbProperty
アノテーションのnillable
属性をtrue
にします。
public class Employee { // nullでもJSONに出力される @JsonbProperty(nillable = true) private LocalDate joinedDate; … }
フィールド名とJSONプロパティ名を変えたい
名前を変えたいフィールドに@javax.json.bind.annotation.JsonbProperty
アノテーションを付加し、value
属性に任意の名前を指定します。
public class Employee { // JSONには「joined_date」という名前で出力される @JsonbProperty(value = "joined_date") private LocalDate joinedDate; … }
その他のカスタマイズ事項
ネーミングルールを一括で決めるjavax.json.bind.config.PropertyOrderStrategy
IDENTITY
LOWER_CASE_WITH_DASHES
LOWER_CASE_WITH_UNDERSCORES
UPPER_CAMEL_CASE
UPPER_CAMEL_CASE_WITH_SPACES
CASE_INSENSITIVE
の6種類が指定可能です。
プロパティの順序を決めるjavax.json.bind.config.PropertyOrderStrategy
LEXICOGRAPHICAL
(辞書順)REVERSE
(辞書順の逆)ANY
("the order of properties is not guaranteed to retain any order."とありますが、ちょっと意味が取れませんした・・・(^^; )
の3種類が指定可能です。
I-JSON (Internet JSON)サポート
I-JSONはあまり詳しくないので、詳細はこちらをお読みくださいm( )m
https://www.tbray.org/ongoing/When/201x/2015/03/23/i-json
可視性のカスタマイズ
ここで言う「可視性」とは、Javaのpublicとかprivateとかのことです。デフォルトでは、フィールドまたはgetterはpublicなもの以外は無視される(getterとフィールドが共にpublicの場合は、getterが優先されるようです)のですが、その設定を変えることができるのかな?ちょっとJSRとJavadocからは読み取れませんでした。
日付のフォーマット
@javax.json.bind.anntation.JsonbDateFormat
アノテーションで指定します。属性でパターンとロケールの指定が可能です。
数値のフォーマット
@javax.json.bind.anntation.JsonbNumberFormat
アノテーションで指定します。属性でパターンとロケールの指定が可能です。
バイナリデータ
javax.json.bind.config.BinaryDataStrategy
クラスで指定します。以下の3つのエンコード方式が利用できます。
BYTE
BASE_64
BASE_64_URL
JSONの整形(Pretty Print)
デフォルトでは、多くのJSONパーサーは、JSONを下記のような形で生成します。
{"id":100,"name":"Hoge","joinedDate":"2015-04-01"}
これだと人間には読みづらいので、改行・空白・インデントを入れて読みやすくするのがPretty Printです。
{ "id" : 100, "name" : "Hoge", "joinedDate" : "2015-04-01" }
この機能はまだJSRには入っていませんが、Javadocには記載されています。javax.json.bind.JsonbConfig
クラスを利用します。
JsonbConfig confing = new JsonbConfig(); // Pretty Print設定を有効化する config.withFormatting(true); Jsonb jsonb = JsonbBuilder.create(config); // 整形されたJSONが生成される String json = jsonb.toJson(…);
まとめ
今回の記事では、JSRおよびJavadocのうち主要と思われる部分のみ解説しました。全内容は解説していませんので、他の機能も知りたいという方は原典をお読みください。
JSR-000367 Java API for JSON Binding Early Draft Review
今までは、Java EE標準でないJSONパーサーやJAXBを使うしかなかったので、JSON-Bの追加は非常に嬉しいです。まだ仕様の策定中なので、今後さらに機能が追加されると思います。期待して待ちましょう!