Hatena::Groupprogram

ひとり開発日記。 このページをアンテナに追加 RSSフィード

2019/01/20 (Sun)

Jacksonを使って、JSON文字列を、イミュータブルなクラスにデシリアライズしたい。

| Jacksonを使って、JSON文字列を、イミュータブルなクラスにデシリアライズしたい。 - ひとり開発日記。 を含むブックマーク はてなブックマーク - Jacksonを使って、JSON文字列を、イミュータブルなクラスにデシリアライズしたい。 - ひとり開発日記。

例えば、 以下のようなクラスがあります。

public class UserData {
    private final Long id;
    private final String email;
    private final String displayName;
    private final boolean admin;
    
    public UserData(Long id, String email, String displayName, boolean admin) {
        this.id = id;
        this.email = email;
        this.displayName = displayName;
        this.admin = admin;
    }

    // getter
}

で、JSON文字列を、JacksonのObjectMapperを使って、このクラスにデシリアライズしようとします。

    @Test
    public void testDeserialize() throws IOException {
        String json = "{\"id\":1,\"email\":\"test@example.com\",\"display_name\":\"test user no.1\",\"admin\":false}";
        ObjectMapper mapper = new ObjectMapper();
        UserData userData = mapper.readValue(json, UserData.class);
        System.out.print(userData);
    }

上記のような適当なテストケース書いて、確認しようとすると、例外が発生します。

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `test.UserData` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

デフォルトコンストラクタ無いと、こんな場合はインスタンス作ることができないので、まぁ、仕方ないですね。

でも、それでもイミュータブルなクラスに変換したい時は、変換するクラスに、以下のようにアノテーションを与えてあげれば良い、とのこと。

public class UserData {
    private final Long id;
    private final String email;
    private final String displayName;
    private final boolean admin;
    
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public UserData(@JsonProperty("id") Long id, 
            @JsonProperty("email") String email, 
            @JsonProperty("display_name") String displayName, 
            @JsonProperty("admin") boolean admin) {
        this.id = id;
        this.email = email;
        this.displayName = displayName;
        this.admin = admin;
    }

    // getter
}

この後、先程のテストケースを実行すると、デシリアライズされている、と…。

トラックバック - http://program.g.hatena.ne.jp/halflite/20190120

2017/09/18 (Mon)

Apache Commons Text 1.1

|  Apache Commons Text 1.1 - ひとり開発日記。 を含むブックマーク はてなブックマーク -  Apache Commons Text 1.1 - ひとり開発日記。

commons-lang3*1のバージョンを3.6に上げたら、幾つかのクラスが @deprecated になっていましたね。

ランダムに文字列を生成する機能だったり、プレースホルダーっぽい機能、文字列の差分表示を提供するクラス辺りは、私もよく使ってたりするのですが、そう言うのを、外に切り出したのでしょうね…。*2

Javadoc*3を見ると、結構面白そうな機能も多いので、ちょっとづつ触ってみたいですかねー。

トラックバック - http://program.g.hatena.ne.jp/halflite/20170918

2017/08/04 (Fri)

Guice + Quartz Scheduler + Jetty で定時起動アプリケーション

|  Guice + Quartz Scheduler + Jetty で定時起動アプリケーション - ひとり開発日記。 を含むブックマーク はてなブックマーク -  Guice + Quartz Scheduler + Jetty で定時起動アプリケーション - ひとり開発日記。

2年前位、Google Guice + Quartz Schedulerで定時起動アプリのサンプルを書いたんですけど*1 久々GitHubを見たら、星が何個か付いている!!!*2 まぁ、Guice/Quartzと言う組み合わせ自体、ちょっとレア過ぎて、他に例が無かったからかもしれませんけど…。

当時は、WARを作って、それをTomcatとかのコンテナに放り込む、と言うのは普通だったんですけど、今は組み込みコンテナを使って、FatJARで自立/自走するのが主流ですよね。

という事なので、Embedding Jettyを使って、設定ファイル無しスタイル*3 *4 で、もう一個サンプルプログラムを書いてみました。

まぁ、メインは殆ど QuartzModule クラスで、ここで JobFactory / SchedulerFactory / Scheduler の設定と発火を行っているので、そこを参照して頂ければ、ほぼオッケーでしょうか。 Job クラスも Guice コンテナ管理下にあるんで、必要に応じて、AOPトランザクション管理とか書いてみても良いでしょう。

でも、 Quartz Scheduler もヴァージョンが上がって、いつの間にか、殆ど Builder Pattern/Fluent Interface*5で設定出来るようになったんだ…、とオモシロでしたね。

トラックバック - http://program.g.hatena.ne.jp/halflite/20170804

2017/06/24 (Sat)

jax-rs-pac4j 2.0.1

|  jax-rs-pac4j 2.0.1 - ひとり開発日記。 を含むブックマーク はてなブックマーク -  jax-rs-pac4j 2.0.1 - ひとり開発日記。

Pac4Jと言う、Javaベースのウェブアプリの認証をサポートしてくれる、ライブラリ群があります。*1 jax-rs-pac4jは、JAX-RSに特化したライブラリで、今回、私が報告したバグ修正2件の入った、2.0.1がリリースされました。

  1. Grizzly+Jersey+jax-rs-pac4jでNullPointerException
    • 自分で、今、The Twelve-Factor App*2ベースのウェブアプリを作ろうと思っていて、フレームワークは、Jersey MVC*3で、認証はtwitter*4、認証機構には何がいいかな、とググっていたらJAX-RSに特化した、jax-rs-pac4jがあることを知りました。
    • で、早速、推奨構成の Grizzly + Jersey MVC + pac4j-oath + jax-rs-pac4j で、プロジェクトを作成し、認証までは軽く通ったんですが、なぜかコールバックで NullPointerException(NPE) 発生…。 よく分からないので、スタックから追っていくと、pac4jのコールバック処理で、セッションの要素を消すのに、nullを書き込んでいて、Grizzlyの中のインメモリ・セッションキャッシュは ConcurrentHashMap を使っているので、null値をputすると、当然、NPEが出てしまうのです。
    • ユーザーフォーラムで報告したら、GitHubにイシュー立てろ、って言われて、立てたら、"Good find.(よう見つけたな)"ってレスされて、ちょっとイラってしましたけどね…。 まぁ、速攻で直して貰ったのでありがたいですわ。
  2. issueに書いてある回避策を試したらNullPointerException
    • issueに書いてある回避策を参考に、GrizzlySessionStore をラップしたサブクラスを作って、configに追加したら、あれ、認証前に例外発生。 しょうがないんで、またスタックから追っていくと、SessionStoreの有無判定で、三項演算子でnullチェックしてるのに、nullを再代入してる…。 これはNPE不可避ですなぁ。
    • あんまりにも致命的なバグなので、イシューもプルリクも無しで、コミットして、緊急リリースしてくれましたね。

ライブラリ群の中でも再後発、先月リリースの大きく書き直した2.0.0、しかもバグ回避ルートと言う事情なので、仕方ないかもですが、無償でデバッグしてるようで、モニョモニョと…。

とは言え、OSSとはそんなもんで、市井のプログラマーが、協力しあって育てていくものなのかもしれませんね。

*1http://takezoe.hatenablog.com/entry/2017/01/28/021818 pac4jでGitHubのOAuth認証を使ってみる - たけぞう瀕死ブログ

*2https://12factor.net/ja/

*3https://jersey.github.io/documentation/latest/mvc.html

*4:ありがち…

トラックバック - http://program.g.hatena.ne.jp/halflite/20170624

2017/06/02 (Fri)

Windowsのcmd.exeで、Mavenを使って新規プロジェクトを作る時

| Windowsのcmd.exeで、Mavenを使って新規プロジェクトを作る時 - ひとり開発日記。 を含むブックマーク はてなブックマーク - Windowsのcmd.exeで、Mavenを使って新規プロジェクトを作る時 - ひとり開発日記。

mvn archetype:generate ^
  -DarchetypeArtifactId=maven-archetype-quickstart ^
  -DinteractiveMode=false ^
  -DgroupId=net.halflite ^
  -DartifactId=testapp ^
  -Dpackage=net.halflite.testapp

毎度忘れてググってしまうので…。*1 *2

*1:cmdのバッチファイルで、1コマンドを複数行にわたって記述したい場合 http://qiita.com/ndxbn/items/089b97e33ae9b69bf48b

*2:groupId/artifactId/package は適時書き換えて下さいな

トラックバック - http://program.g.hatena.ne.jp/halflite/20170602