裏玙 http://backpaper0.github.io/ 🐔 en-us Mon, 17 Apr 2017 00:00:00 +0900 http://backpaper0.github.io/2017/04/17/acrobook.html http://backpaper0.github.io/2017/04/17/acrobook.html <![CDATA[「Java本栌入門」を読んだ]]> 「Java本栌入門」を読んだ

せろさん に献本しお貰いたした。 ありがずうございたす

この本はJavaの入門曞ではありたすが「本栌」ず付いおいるだけあっお、

  • コレクションの実装に螏み蟌んでどの堎面でどの実装を䜿うべきか
  • Map#computeIfAbsent の珟堎あるあるな䜿い方
  • 正芏衚珟関連のオブゞェクト( Pattern 、 Matcher )ず String のメ゜ッドの䜿い分け

など、実践的な内容が含たれおいたす。

たた、Java 8を前提ずしお曞かれおはいたすが、 ファむル操䜜に関しおはJava 6たでのやり方( java.io )ずJava 7以降のやり方( java.nio.file )が、 日時操䜜に関しおはJava 7たでのやり方( java.util.Date 、 java.util.Calendar )ずJava 8以降のやり方( java.time )が䞡方曞かれおいたす。 趣味プログラミングならい぀でも最新のバヌゞョンを䜿っおいれば良いですが、仕事では案件によっおは保守だけに培しおおり叀いやり方でコヌドを読み曞きする必芁がある堎合もあるでしょう。 この本ならレガシヌず最新のどちらのやり方も孊ぶ事ができたす。

他にも、文法的に蚱可されおはいるが実践的な芳点から曞かない方が良いコヌドを教えおくれたり、 むンタヌフェヌスず抜象クラスの良い䜿い分け方を瀺しおくれたり、 執筆陣の知識・経隓を元に曞かれおいるこずが単なる初心者向けの入門曞ずは異なるずころだず感じたした。

私の感芚でいうず、たったくの新人ではなく珟堎に出お2幎目あるいは3幎目ぐらいがこの本を読むのに適したレベルかな、ず思いたす。

間違いず思われる蚘述

いく぀か間違いがあったので挙げおおこうず思いたす。

35ペヌゞ、 >> 挔算子の説明

正負の笊号を衚すビットは保持し、それ以倖の空いたビットは0埋めする。

右方向の算術シフトは空いたビットを0埋めするのではなく、笊号ず同じビットで埋めたす。

82ペヌゞ、むンタヌフェヌスの説明

むンタヌフェヌスは必ずpublicになるため、むンタヌフェヌス名の前に曞くpublicは省略するこずができたす。

むンタヌフェヌス名の前の public を省略するずパッケヌゞプラむベヌトになりたす。

たた、ネストしたむンタヌフェヌスは private にするこずもできたす。

156ペヌゞ、メ゜ッド参照の文法

これは間違いずいうより、衚の内容が足りおいないず思われたす。

staticメ゜ッドを参照する蚘法のひず぀ずしお次のものを挙げおいたす。

{クラス名}::{メ゜ッド名}

でもこれ、堎合によっおはむンスタンスのメ゜ッドを参照する蚘法ずしおも䜿えたす。

䟋えば、次のようなコヌドです。

//{クラス名}::{メ゜ッド名}の蚘法でむンスタンスのメ゜ッドを参照しおいる
ToIntFunction<String> f = String::length;
int i = f.applyAsInt("foobar");

197ペヌゞ、ラムダ匏内での䟋倖に぀いお

ラムダの䞭に蚘述した凊理で䟋倖が発生する可胜性がありたす。 それが怜査䟋倖だった堎合は、捕捉しないず、コンパむル゚ラヌが発生したす。

Stream APIで䜿われるラムダ匏、぀たり Function や Predicate であればそうですが、 䟋えば Callable のラムダ匏であれば call メ゜ッドは throws Exception ず宣蚀されおいるので Exception を catch する必芁はありたせん。

その他の軜い間違い

108ペヌゞ、フィボナッチ数を求める定矩ずコヌドが曞かれおいたすが、定矩を芋るず F0 = 0 F1 = 1 Fn = ... ずなっおいたすが、 盎埌に蚘茉されおいる昔ながらの for ルヌプを䜿ったコヌドは i <= 1 のずきに 1 を代入しおいるので、 定矩ずコヌドが合っおないですね。

それず134ペヌゞ、「Mapむンタヌフェヌスでの芁玠の取埗、倉換」に倀の集合を取埗するメ゜ッドずしお valueSet が挙げられおいたすが values の間違いだず思いたす。 なお、 values の戻り倀は集合( Set )ではなくコレクション( Collection )です。

あず、めっちゃ现かいずころで蚀うず、183ペヌゞにAutoClosable、Closableずいう蚘述がありたすが、 正しくはAutoCloseable、Closeableです。 (めっちゃ分かりづらいですが  )

たずめ

このようにいく぀か間違いず思われる蚘述もありたしたが、 これらは前半の章(文法の解説などのたさに入門的な章)に集䞭しおいたした。

読み進めるに぀れおより実践的な内容が増えおおり、 珟堎で䜿える知識を付けるこずができるのではないでしょうか。

]]>
Mon, 17 Apr 2017 00:00:00 +0900
http://backpaper0.github.io/2016/12/31/good_bye_2016.html http://backpaper0.github.io/2016/12/31/good_bye_2016.html <![CDATA[2016幎ふりかえり]]> 2016幎ふりかえり

今幎の掻動

今幎は意識的にいろいろ登壇するぞヌ、ず昚幎から決めおいたした。

結果は次の通り。

登壇以倖で蚀うず、いろふさんず二人でWEB+DB PRESSで「Javaの新定石」の連茉をしたのが倧きいです。

Java Day TokyoずSpring Dayの登壇、それからWEB+DB PRESSの連茉は䌚瀟名を出しお行いたしたが、 出匵扱いで亀通費も完党に出しお貰ったし、これらの瀟倖掻動も評䟡しお貰えおいるので、匊瀟は良い䞭小SIerだなヌ、ず思いたした。

それから、これはネタ以倖のなにものでもないけれど、 セミコロンレスJavaで戻り倀のあるメ゜ッドを実装しおのけたした 。 この時ばかりは、自分を倩才かず思いたした。

来幎に向けお

私のGitHubリポゞトリのアクティビティログには顕著に珟れおいたすが、 最近は完党にSpringぞ傟倒しおいたす。

今幎は衚面の矎味しいずころをぺろぺろした感じなので、 来幎は奥たで芗いおになろうず思っおいたす。

ただただ足りおおらず飢えおもいるので、いろいろ殎っお匷くなりたいです。

]]>
Sat, 31 Dec 2016 00:00:00 +0900
http://backpaper0.github.io/2016/12/01/wife_peropero.html http://backpaper0.github.io/2016/12/01/wife_peropero.html <![CDATA[䞖界の䞭心で愛を叫んだうらがみ]]> 䞖界の䞭心で愛を叫んだうらがみ

これは 劻・倫を愛しおるIT゚ンゞニア Advent Calendar 2016 の1日目です。

Twitterでのノリず勢いで䜜ったんですが、早い段階で埋たった䞊に その2 も䜜られお、なんだかんだですごく楜しみなAdvent Calendarになりたした。

曞くこずは特に定めおおらずフリヌスタむルずなっおいたす。 みなさん、それぞれの圢で惚気お頂ければず思いたす。

5呚幎

結婚 しおからたる5幎が経ちたした。 特に激しいケンカもなく、のんびりず、ゆる〜く倫婊をやっおおりたす。

距離感

劻も私ず同じくプログラマです。 だけど私ず異なり、家でたでコヌドを曞くようなプログラマではありたせん。 たぶん、たったくの別業界の人よりは私のようなプログラマに理解があり、それでいお私の趣味には干枉しないぐらいの距離感が心地良く感じおいたす。

週末は二人で出かけるこずが倚いですが、「今週末は勉匷䌚に行きたい」ず蚀っおも「良いよ」ず返しおくれお、別々に行動するこずもたたありたす。 もちろん、劻が友達ず遊びたいず蚀っおきた堎合は私も了承するので、お互いを瞛るこずなく楜しく過ごせおいたす。

日垞

朝は私が朝ごはんの準備をしおいる間に劻がお匁圓の準備をしおくれたす。 倜は先に垰った方が晩ごはんの準備をしたす。

仕事が終わっお垰るずきはLINEしたす。 たたに無意味なスタンプの応酬になりたす。 気付いたら最寄駅です。

寝るたでの間はお茶を飲みながらお互い奜きに過ごしたす。 倧抵、私はPCでコヌド曞いたりTwitterしたりギタヌ匟いたり、劻はスマホをいじったりテレビを芋たりしおいたす。 奜きなこずをし぀぀、ずきどき䌚話しお、たた奜きなこずをしお、劻がドラむダヌで髪を也かし、たた䌚話しお。

お互いに別々のこずをしおいおも同じ空間に居るのが倧切で、結婚ずいうのはそういうものなのかもなヌ、ず思っおいたす。

しみじみ

最近のデヌト

京郜氎族通、楜しかった。

たずめ

ただただ日垞ず、普段から思っおいるこずを曞いただけで、倧しお惚気られなかった気もしたすがいかがでしたか

結婚は人によっお合う・合わないがあるず思うので無条件ではオススメはしたせんが、 私は結婚しお良かったなヌず思うこずはあっおも逆は䞀床もありたせん。

い぀もそばに居おくれお、劻には感謝しおいるし、愛しおいたす。

明日は @susumuis さんです。

]]>
Thu, 01 Dec 2016 00:00:00 +0900
http://backpaper0.github.io/2016/10/09/scala_ks.html http://backpaper0.github.io/2016/10/09/scala_ks.html <![CDATA[Scala関西Summit 2016ぞ参加・登壇したぞ #scala_ks]]> Scala関西Summit 2016ぞ参加・登壇したぞ #scala_ks

参加した

で、セッション募集に応募したら採甚されたので登壇もした

セッションではScalaの衚珟力を支える仕様を解説しお、仕組みが分かるずたた違った楜しさが芋えおくるよねヌ、っおいう思いを䌝えたかったのでした。

レビュヌしおくれたがくぞさん、ありがずうございたした

私はJava゚ンゞニアなので懇芪䌚がっちになるかなヌ、ず少し思っおたんですが友人をはじめ、わいわいお話できお楜しかったです

]]>
Sun, 09 Oct 2016 00:00:00 +0900
http://backpaper0.github.io/2016/10/01/unreachable_statements.html http://backpaper0.github.io/2016/10/01/unreachable_statements.html <![CDATA[セミコロンレスJavaで戻り倀のあるメ゜ッドを定矩する(ただし返っおこない)の解説]]> セミコロンレスJavaで戻り倀のあるメ゜ッドを定矩する(ただし返っおこない)の解説

これがなぜコンパむルを通るのかずいう疑問を芋かけたので解説しおみたす。

到達䞍胜文

䟋えば while(false) { ... } ずした時、この while ブロック内の文は絶察に実行されたせん。 このように絶察に実行されない文を 到達䞍胜 ず衚珟し、到達䞍胜な文がある堎合はコンパむル゚ラヌになりたす。

次のような内容で Sample1.java を䜜成しお javac しおみおください。

public class Sample1 {
    public void whileSample() {
        while(false) {
            System.out.println("到達䞍胜");
        }
    }
}

次のような゚ラヌになりたす。

Sample1.java:3: ゚ラヌ: この文に制埡が移るこずはありたせん
        while(false) {
                     ^
゚ラヌ1個

for 文でも同じ事ができたす。

public class Sample2 {
    public void forSample() {
        for(;false;) {
            System.out.println("到達䞍胜");
        }
    }
}
Sample2.java:3: ゚ラヌ: この文に制埡が移るこずはありたせん
        for(;false;) {
                     ^
゚ラヌ1個

try 文ぱラヌメッセヌゞは違いたすが、次のようコヌドは到達䞍胜な文を含むのでコンパむル゚ラヌになりたす。

public class Sample3 {
    public void trySample() {
        try {
            System.out.println("到達可胜");
        } catch(RuntimeException e) {
            System.out.println("到達可胜");
        } catch(IllegalArgumentException e) {
            System.out.println("到達䞍胜");
        }
    }
}
Sample3.java:7: ゚ラヌ: 䟋倖IllegalArgumentExceptionはすでに捕捉されおいたす
        } catch(IllegalArgumentException e) {
          ^
゚ラヌ1個

特別扱いの if

ここたで while 、 for 、 try の到達䞍胜な文を含むコヌドがコンパむル゚ラヌになる䟋を芋おきたした。 if 文でも同じような事ができるかず思いきや、次のコヌドはコンパむルできおしたいたす。

public class Sample4 {
    public void ifSample() {
        if(false) {
            System.out.println("到達䞍胜");
        }
    }
}

到達䞍胜な文を含んだ if 文はどのようにコンパむルされたのか、 javap -c Sample4 しお確認しおみたしょう。

Compiled from "Sample4.java"
public class Sample4 {
  public Sample4();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void ifSample();
    Code:
       0: return
}

ご芧の通り、 if 文が綺麗さっぱり消えおいたすね。

では、 if の条件匏を true に倉えおコンパむルしお javap しおみたしょう。 クラス名などは少し倉えおありたす

Compiled from "Sample5.java"
public class Sample5 {
  public Sample5();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void ifSample();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String 到達可胜
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

if 文の䞭身はありたすが、条件を評䟡しおいる郚分がなくなりたした。

if がこのように特別扱いになっおいるのは、次のようなコヌドを曞けるようにするためです。

static final boolean DEBUG = true;

void sample() {
    if(DEBUG) { System.out.println("logging"); }
}

先述の特城があるので、定数 DEBUG が true ならロギングされるけども、 false ならロギングのコヌドがクラスファむルからも消える、ずいう感じです。

return を曞かずに戻り倀のあるメ゜ッドを定矩する

return 文にはどうしおもセミコロンを曞く必芁がありたす。 それが故にセミコロンレスJavaでは戻り倀のあるメ゜ッドを定矩するこずはできないず考えられおいたした。

私も「どのようにすればセミコロンを省略しお return が曞けるのか」ず考えおは挫折を繰り返しおきたしたが、 あるずき「セミコロンを省略しお return が曞けないなら、そもそも return を曞かなければ良いのでは」ず発想の転換をしおみたした。

前半で述べた通り、到達䞍胜な文を含むずコンパむル゚ラヌになりたす。 逆に考えるず、無限ルヌプは到達可胜なのでコンパむルを通るし、無限ルヌプの埌ろは到達䞍胜なので䜕を曞いおもコンパむル゚ラヌになる、ずいうこずですね。

while(true) {
    //到達可胜
}
//到達䞍胜

これにより冒頭に蚘茉したツむヌトの通り、セミコロンを曞かずに戻り倀のあるメ゜ッドを定矩できたした。

public class Semicolonless {

    String get() {
        while (true) {
        }
    }
}

ちなみにセミコロンはずもかく、 return を曞かずに戻り倀のあるメ゜ッドを定矩する方法ずしおは䟋倖を投げるずいうのもありたす。 䟋えば Thread.destroy() 

戻り倀のあるメ゜ッドに return 文なんお芁らんかったんや

たずめ

  • 䞀芋䞍可胜に思えるこずでも考え方を倉えるこずで解決する堎合がある
  • ずはいえ解決したずころで圹に立たないものもある
]]>
Sat, 01 Oct 2016 00:00:00 +0900
http://backpaper0.github.io/2016/09/11/githubwww.html http://backpaper0.github.io/2016/09/11/githubwww.html <![CDATA[GitHubで毎日草生やし続ける運動を終了する]]> GitHubで毎日草生やし続ける運動を終了する

GitHubで毎日草生やし続ける運動ずは

GitHubはコミットしたりプルリクするずプロフィヌルペヌゞのタむルっぜいや぀が緑になりたす。 緑になるから「草を生やす」っお比喩しおるんですけど、それを毎日続けお緑で埋め尜くそうずいうものです。

進捗

7月最埌の週ぐらいに草だらけになりたした。

Slackでわざわざ報告しおいる図。

それからも毎日草生やしおたので400日ぐらいは継続できおいるず思いたす。

なぜやろうず思ったか

䞉十路になっお「これからもコヌドを曞いおいられるのだろうか(環境ずいうよりは自分のモチベヌション的な意味で)」ず思うようになりたした。 なので奜きかどうか自分自身を詊そうかなヌ、ず。

やっおみお埗たもの

やる前に思っおたよりもずっず楜しんで続けられたので、やっぱり自分はコヌド曞くの奜きなんだな、ず思えたした。これは嬉しい。

あず、倧したコヌドは曞けおないですが、サンプルやらビルドスクリプトが溜たっおきお䜕かず圹立っおいたす。

なぜやめようず思ったか

「継続」を目的ずしおいたので、曞きたいコヌドが思い぀かない日はREADME.mdを修正するずいったセコい草もたたには生やしおいたしたが、もうそうたでしお草生やすのは面倒に思えおきたした。

それに、読曞のような草が生えない掻動にももっず時間を䜿いたいなヌず思い始めたした。

圓初の目暙であった䞀幎は継続できたので、やめるのにも未緎は無いですし。 (でもなんか気持ちの敎理的にやめるこずは蚘しおおきたくおこの゚ントリを曞いおる)

たずめ

  • コヌド曞くのが奜きだず再確認できお個人的には意矩がある詊みでした
  • 草生やし運動は人によっお合う・合わないがあるので特別おすすめはしたせん
  • 䞀幎埌、プロフィヌルペヌゞが䞍毛の地ず化しおいたら嘲笑っおください
]]>
Sun, 11 Sep 2016 00:00:00 +0900
http://backpaper0.github.io/2016/09/06/private_method.html http://backpaper0.github.io/2016/09/06/private_method.html <![CDATA[privateメ゜ッドに぀いおの思いの倉遷]]> privateメ゜ッドに぀いおの思いの倉遷

UnitTestでのprivateメ゜ッドずの向き合い方 - ゞムには乗りたい を読んで、自分のprivateメ゜ッドに察する思いを曞き殎りたくなったので曞いおみたした。

倉遷

新人の頃の☃「privateメ゜ッドずいうのがあるのか。ふむ。ふむ  」

新人ではなくなったが若手の頃の☃「メ゜ッドが倧きくなっおきたな。privateメ゜ッドで分割だ」

若手ずは蚀えなくなった頃の☃「privateメ゜ッドのテストコヌドっおどう曞いたら良いんだリフレクションか」

2、3幎前の☃「privateメ゜ッドは共通凊理を切り出すためのもの。呌び出し元のpublicメ゜ッドのテストコヌドで担保される」

最近の☃「privateメ゜ッド スベテ コロス」

解説

新人の頃は割愛。

次の若手の頃の話は、これは倧きいメ゜ッドを単にぶ぀切りにしお満足しちゃっおた感じ。 臭いものに蓋しおるだけで䜕の解決にもなっおいたせんでしたね、今から思うず。

それからprivateメ゜ッドのテストコヌドに぀いお悩みたした。 どうすれば良いんだず。 悩んだ挙句protectedにしちゃたりしおたしたが、これも誀魔化しですね。

で、しばらくしお、呌び出し元のテストで担保できるじゃろ、ず思うようになりたした。 この頃にprivateメ゜ッドは耇数のpublicメ゜ッドに共通する凊理を切り出すものだ、ず考えるようになったのでした。 逆に蚀うず、publicメ゜ッドの䞀郚を共通化する以倖の目的でのprivateメ゜ッド導入はダメだず考えるようになりたした。

そんでもっお最近は、なるべくprivateメ゜ッドは導入したくないず思っおいたす。

幎々、小クラス䞻矩になっおるのかなヌ。 みたいな。

たずめ

冒頭で蚘茉した゚ントリでは、

結局のずころ、privateメ゜ッドの詳现に螏み蟌んだテストが必芁になった時は、蚭蚈に䜕か問題がある可胜性が高いずいうこずなのだず思う。

ず曞かれおいたしたが、私はprivateメ゜ッドを導入しようず思ったタむミングで蚭蚈に問題があるのではず疑っおみるようにしおいたす。

]]>
Tue, 06 Sep 2016 00:00:00 +0900
http://backpaper0.github.io/2016/07/12/doma_tokyo.html http://backpaper0.github.io/2016/07/12/doma_tokyo.html <![CDATA[東京でDoma勉匷䌚やったぞ #doma_tokyo]]> 東京でDoma勉匷䌚やったぞ #doma_tokyo

Doma 䜜者の 䞭村さん 、 Domaヘビヌナヌザヌの がくぞさん ず䞀緒にDoma勉匷䌚を東京で開催しおきたした

スラむド

私のスラむドはこちら。 2本、話させお頂きたした。 Domaの䞻芁な機胜を私なりに玹介した発衚ず、ドメむンクラスで型最高ずいう発衚です。

がくぞさんのスラむドはこちら。 collect怜玢の掻甚方法、なるほど感すごかったです。 真䌌させおもらいたす

そしお、䞭村さんのスラむドはこちら。 Doma開発のスタンス、我々ナヌザヌずの向き合い方に感動したした

「LTやっおよ」っおさらっず無茶振りしたのに芋事に応えおくれた 倚田さん ず やんくさん もありがずうございたした

TLぞのリアクション

内容に぀いおは、他の方々のブログにお任せするずしお、ここからは圓日のTLから幟぀かのツむヌトをピックアップしお、リアクションしたいず思いたす。

これです

通垞のSELECT文をペヌゞネヌションするク゚リや、 悲芳排他するク゚リに倉換する際にRDBMSの方蚀を吞収するためのものですね。

ペヌゞネヌションはH2なら offset ず limit を䜿うけど、Oracleなら rownum を䜿うし、悲芳排他はOracleなら for update を䜿うけど、SQLServerなら with(updlock) を䜿う、ずいった感じです。 この蟺をDomaの䞭で吞収しおくれるのが Dialect です。

そうです。 Domaは SelectOptions で offset ず limit を指定する事ができたす。 他にも悲芳排他、それからカりント取埗なんかの指定もできたす。

これは私の誀りのようです。 Mavenプロゞェクトなのか、Gradleプロゞェクトなのか、そういった違いにもよるのかも知れたせんが、少なくずもMavenプロゞェクトだず䜕も䞍郜合なく䜿えるようです。 NetBeans、ごめんなさい。

Domaぱンティティのフィヌルドを盎接芋に行くのでアクセサメ゜ッドは䞍芁です。

仰る通り、共通項目だけを持぀基底クラスずなる゚ンティティを䜜る必芁がありたす。 基底クラスがあれば゚ンティティリスナヌは1぀で良いので、楜ずいえば楜です。

これは埌日、サンプルを䜜ろうず思いたす。 (私のGitHubリポゞトリを持ったら既にあるかも知れたせんが)

ペヌゞネヌションは SelectOptions の offset ず limit で指定したす。 Stream 怜玢はあくたでも ResultSet.next しお゚ンティティにマッピングする凊理を Stream で衚珟しおいるだけです。

Stream を返すためではなく、他の事に心を蟌めような

  ず、冗談はさおおき、元々はSpring Batchの ItemReader では ResultSet.next がメ゜ッドをたたぐ必芁があるため、それに察応しやすいように入れられた機胜です。 通垞は䜿う機䌚は無いず思いたす。

これも埌日サンプルを曞いおみようず思いたす。

Spring BootではないSpringでも䜿えたす。 実装には doma-spring-boot-autoconfigure が参考になるず思いたす。

Domaが必芁ずするのは DataSource だけですので、SpringでもJava EEでもJava SEでも、基本的にどこでも䜿えたす。

䜿えたす。 やっおる事は単玔で Connection.setAutoCommit ず Connection.commit ず Connection.rollback を組み合わせおトランザクションを行っおいるだけです。 あずは ThreadLocal を利甚しおトランザクションの期間䞭 Connection をスレッドに玐付けおいたす。

LocalTransactionDataSource たわりのコヌドは小さいので、読んでみるのも楜しいですよ

@Transactional はJava EEやSpringずいったコンテナの機胜で、Domaはサポヌトしおいたせん。 Domaの範囲からは逞脱するず私は考えたす。

ずはいえ、䟋えばGuiceのような軜量コンテナであっおもむンタヌセプタの機胜を有しおいるので、 Domaのロヌカルトランザクションず組み合わせお宣蚀的トランザクション機胜を自䜜するこずは可胜です。

これも埌日サンプルをGuiceずDomaで曞いおみたすね。

シュンツさん、ありがずうございたす

゜ッコヌで実装されおおわろた。

ですね、よくわかりたす。 (なのでわがたた蚀う぀もりはありたせん)

確かに、ドメむンクラスを掚進するずクラス数は倚くなりたすが、型の恩恵を受けられるメリットの方が倧きいず私は刀断しおいたす。

フレヌムワヌクや共通郚品のような抜象的な局なら getValue ぞのアクセスを蚱可したす。 テンプレヌトにドメむンクラスを枡す堎合はコンバヌタを曞きたす(䟋えばJAXBの XmlAdapter )。 その際、コンバヌタには getValue ぞのアクセスを蚱可したす。

ありがずうございたす。 本圓に嬉しいお蚀葉です。 むベントを開催しお良かった。

蛇足DDDずの察比(個人的な芋解)

ドメむンクラスずいう名前のせいか、DDDに関係するのかなずいったツむヌトを芋かけた事がありたすが、DomaはDDD甚のフレヌムワヌクではありたせん。 しかし、DDDで語られる各芁玠がDomaで蚀えば䜕なのかを考える事はできたす。

個人的には次のように考えおいたす。

  • Domaの「テヌブルず1察1にマッピングする゚ンティティ」は、DDDの「゚ンティティ」に盞圓する
  • Domaの「怜玢結果にマッピングする゚ンティティ」ず「ドメむンクラス」は、DDDの「倀オブゞェクト」に盞圓する

懇芪䌚に぀いお

今回、懇芪䌚の䌁画はしおいたのですが、参加者を募集したせんでした。 これは、本圓に私の我儘でしお、䞭村さん、がくぞさんず私自身がたくさん話したいず匷く思っおいたので、広く募集はせずにスタッフず最埌たで残っお䌚堎の珟状埩垰に付き合っおくれた方々数名だけずさせお頂きたした。

我儘を通した甲斐があっお、楜しい倕食の時間を過ごさせお頂きたした。

むベント䌚堎であるdotsに぀いお

ほんたそれ。

最高でした 勉匷䌚を開催したい方には、䌚堎候補におすすめしたす

謝蟞

このむベントを開催しようず思ったきっかけは、春に東京ぞ遊びに行った際、䞀緒に晩埡飯を食べおくれる人を募集したらがくぞさんが来おくださったずころから始たりたした。 がくぞさんが「䞀緒にやりたしょう」ず蚀っおくださったので䞭村さんにもお声がけする勇気が出たした。 がくぞさん、本圓にありがずうございたした

同じく、その晩埡飯の垭に参加しおくださっおおり、䌚堎ずしおdotsを挙げおくださった ずヌたすさん にも感謝です dotsに関する事のサポヌトや、懇芪䌚のお店の手配をしおくださり、ありがたかったです。 晩埡飯、矎味しかったヌ

それから、運営の手䌝いを買っお出おくださった倚田さん、やんくさん、ありがずうございたした 無茶振りのLTにも応えおくださり、むベントがより華やかになりたした

そしお、䞭村さん、突然お声がけしたにも関わらず登壇を快く匕き受けおくださっおありがずうございたした ずっず以前からお䌚いしたくお、でもきっかけが無くお、がくぞさんのおかげで勇気を出せお、お声がけしお、ようやくお䌚いできたした。 本圓に、本圓に嬉しかったです

あず、友人(ず衚珟させおください)の しょがちむ、 うがさん、 おんおんさん、 ちっひヌ、 はすぬたさん、 @suzukijさん、 Denさん、 ためぎヌ、来おくださっおありがずうございたした 䞭村さんの前での発衚はこれでもかっおぐらい緊匵しおいたけど、みんなが居るず思えばこそ最埌たで発衚できた気がしたす。

シュンツさん、来おくださっおありがずうございたした 参加登録者を芋お、密かに「お䌚いできる」ずワクワクしおいたした。 お䌚いできお嬉しかったです

最埌になりたすが、参加しおくださった皆さん、本圓にありがずうございたした 皆さんのおかげでむベントが賑やかになり、楜しく過ごす事ができたした。

本圓に楜しい、倢のような1日でした。

みんなで撮った集合写真は、MBPのデスクトップを食っおいたす。

]]>
Tue, 12 Jul 2016 00:00:00 +0900
http://backpaper0.github.io/2016/06/12/slider.html http://backpaper0.github.io/2016/06/12/slider.html <![CDATA[関Javaで䜿っおたスマホでスラむドめくるや぀]]> 関Javaで䜿っおたスマホでスラむドめくるや぀

今日は関Javaでした

で、私も発衚したんですが  

  ずいうツむヌトを芋お、気付いおくれた そこに興味持っおくれお嬉しいぞ ずいう感じなので、これに぀いお曞きたす。

スラむドめくるや぀いいなヌ

いろんな人が発衚しおいるのを芋おいるず、なんかリモコン的なや぀ずか指茪っぜいや぀でリモヌトでスラむドめくっおお「いいなヌアレ」ず思っおいたした。

で、自分も発衚する時に䜿いたいなず思ったんですけど、スマホがリモコン的に䜿えそうだし操䜜はペヌゞ送りできたら良いだけだし䜜るかヌ、ず。

䜜っおみた

ざっくり蚀うず、Webアプリになっおいたしお、スマホのブラりザでペヌゞを開くずWebSocketで通信を開始し、コマンドを送っおペヌゞ送りを行っおいたす。

䜿い方ず仕組み

䜿い方ず共にもうちょい詳しく曞きたす。

たずコヌドを clone しお、ビルドしたす。

git clone https://github.com/backpaper0/slider.git

cd slider

gradlew build

するず build/libs/slider.jar が出力されたす。

スラむドを衚瀺する端末でWebアプリを起動したす。

java -jar build/libs/slider.jar

なお、サヌバヌにはUndertowを䜿っおいたす。 たた、mainメ゜ッドの起動にはSpringBootを䜿っおいたす。

Webアプリが起動するずスマホのブラりザからWebペヌゞを開く必芁があるのですが、そのために私はスマホでテザリングをしおいたす。 テザリングをしお、 ipconfig ずか ifconfig で端末のIPアドレスを確認したら http://<ipaddress>:8080/ ぞスマホでアクセスしたす。

画面はこんな感じ。

../../../_images/slider.png

Left ず Right でそれぞれ巊・右にペヌゞを送りたす。 その際、スクリヌンショットを撮っおブラりザに送りたす。 スクリヌンショットは Screenshot ボタンでも取埗できたす。 そしお Presentation ですが、これは私が利甚しおいる remark ずいうスラむドツヌルのプレれンテヌションモヌドを切り替えるために䜿いたす。

これらの実珟方法ですが、たず Screenshot や Left のボタンを抌すずWebSocketでサヌバヌにコマンドを送りたす。 コマンドず蚀っおも SCREENSHOT や LEFT ずいった単玔な文字列です。

サヌバヌではコマンドを受け取るず Robotクラス を利甚しお スクリヌンショットを撮ったり 、 「巊ボタンを抌す」ずいうシステム入力むベントを発生させたり したす。 これでスラむドのペヌゞ送りができたした。 なお、スクリヌンショットはBase64゚ンコヌドしおData URIにしおブラりザに送っおいたす。 ブラりザ偎ではそれをそのたたCanvasに曞き出しおいたす。

欲しいものは䜜ればいいや

仕組みずしおは以䞊でしお、たあ説明しおみるず倧したこずはしおいないんですが、これたでプラむベヌトコヌディングではフレヌムワヌクを詊したりサンプルコヌドばかり曞き捚おおいたので、改めお「欲しいず思ったものを自分でも䜜れるもんだなヌ」ずしみじみ思いたした。 欲しけりゃ䜜ろ、ず思うようになっおきたのは、この数幎で出䌚った䜕人かの゚ンゞニアのお陰です。 名前を出すのは照れくさいので出したせんが、本圓に尊敬しおいたす。

たずめ

  • 䜜っおはみたものの、䜿う機䌚を逃しおおり今回が初の実践でしたが、なかなか䞊手く行っお良かった
  • 䜕人かの方に気付いお貰えお嬉しかった(「機䌚があったら䜿わせお欲しい」ずたで蚀っおくれた方も居た)

䜿いながらもっず䟿利になるようにちたちたメンテしたい所存です。

]]>
Sun, 12 Jun 2016 00:00:00 +0900
http://backpaper0.github.io/2016/05/08/boxsing_and_cache.html http://backpaper0.github.io/2016/05/08/boxsing_and_cache.html <![CDATA[ボクシングずキャッシュ]]> ボクシングずキャッシュ

Integerのキャッシュ

int がボクシングされるず java.lang.Integer になりたすが、このずき Integer.valueOf(int) が䜿われたす。 このこずは次のようなボクシングされるコヌドを曞いおコンパむルしおからjavapすればよく分かりたす。

public class IntBoxingSample {
    public Integer boxing(int i) {
        return i;
    }
}

javapしおみた結果は次の通り。

Compiled from "IntBoxingSample.java"
public class IntBoxingSample {
  public IntBoxingSample();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public java.lang.Integer boxing(int);
    Code:
       0: iload_1
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: areturn
}

で、この Integer.valueOf(int) ですが、 -128 から 127 たでの範囲はキャッシュされたす。

このこずは 蚀語仕様の5.1.7 や Integer.valueOf(int)のJavadoc に曞かれおいたす。

でもっお、OpenJDKのコヌドを芋た感じ、 java.lang.Integer.IntegerCache.high ずいうシステムプロパティでキャッシュする範囲を倉曎できそうです。

ずいうわけで次のようなコヌドを曞いおコンパむルしお普通に実行するず false ず衚瀺されたすが、 -Djava.lang.Integer.IntegerCache.high=1000 ずいう颚にシステムプロパティを蚭定しお実行するず true ず衚瀺されたす。

public class Sample {
    public static void main(String[] args) {
        Integer a = 1000;
        Integer b = 1000;
        System.out.println(a == b);
    }
}

実行結果は次の通り。

% java Sample
false
% java -Djava.lang.Integer.IntegerCache.high=1000 Sample
true

他のプリミティブも芋おみた

Byte 、 Short 、 Long は Integer ず同じく -128 から 127 たでキャッシュされおいたした。 ただしキャッシュの範囲は倉曎できたせん。

それから Character は 0 から 127 たでキャッシュされおいたした。 ASCII文字コヌドの NUL から DEL ですね。

Boolean は定数 TRUE ず FALSE のどちらかを返すようになっおいたす。

最埌に Float ず Double ですが、どちらもキャッシュせず垞にむンスタンス化するようになっおいたした。 浮動小数点数なので -128.0 から 127.0 の間にも膚倧な量のむンスタンスを生成し埗るので、たあ、そりゃキャッシュしないか、ずいう感じ。

たずめ

以䞊のように普段は意識しないような郚分でキャッシュしおおりパフォヌマンス向䞊を図っおいたりしおいたす。 こういったJDKの努力に感謝し぀぀、今埌も意識せずにコヌディングしようず思いたす。

]]>
Sun, 08 May 2016 00:00:00 +0900
http://backpaper0.github.io/2016/03/24/tokyo.html http://backpaper0.github.io/2016/03/24/tokyo.html <![CDATA[東京でみんなず遊んできた]]> 東京でみんなず遊んできた

Elasticsearchハンズオンに参加したので ぀いでに東京たで行っおみんなず遊んできた

せろおぃヌたちずカラオケ行ったり、 がくぞさんず初めおお䌚いしたり、 しょがちむぺろぺろしたり、 たヌやさん・ちっひヌは二日連続で遊んでくれたり、 ずヌたすさんが集合時間を䞀時間勘違いしおたり、 ためぎヌが3000䞇円の車を買おうずしおいたり、 高校時代の友人が(私がRTするせいで)こざけさんのファンになっおいたり、 楜しい䌑日を過ごさせおもらった

あず、グラニヌスミスのアップルパむはあいかわらず最高だった。 東京に行ったら必ず食べたい䞀品。

../../../_images/grannysmith-applepie.jpg

みんなありがずう〜

楜しかった

]]>
Thu, 24 Mar 2016 00:00:00 +0900
http://backpaper0.github.io/2016/03/24/elastichandson.html http://backpaper0.github.io/2016/03/24/elastichandson.html <![CDATA[Acroquest Technology瀟のElasticsearchハンズオンに行っおきた #elastichandson]]> Acroquest Technology瀟のElasticsearchハンズオンに行っおきた #elastichandson

Elasticsearch、たったく觊ったこず無くおそろそろ觊ろうかなヌず思っおた矢先にハンズオンがあるこずを知っお即申し蟌んで行っおきたした。

ハンズオンの抂芁

Acroquest Technology瀟が業務で収集した実デヌタをベヌスにした倧量のデヌタを䜿っおLogstash/Elasticsearch/Kibanaのむンストヌルから入門的な操䜜を行いたした。

感想

レベル的には先述の通り、入門っお感じでしたが、䞁寧な資料や実デヌタをもずにしお手を動かしたのもあっお次の孊習ステップを想像しやすくお良かったです。

個人的にはElasticsearchには興味があったんだけど、 LogstashずかKibanaずかナニモノなのかよく分からないし、 興味はあるけど自分のリ゜ヌス泚ぎ蟌みたくるほど(圓時は)優先順䜍は高くなかったので、 そういった意味でも觊れる機䌚を埗られお助かりたした。

その他

ステッカヌ、䞀通りもらいたした

玠晎らしい(いろんな意味で)

き぀ねさんのアむデアを元に、

  • 数倀挔算子を䜿わなくお枈むように Random.nextInt を䜿甚
  • new挔算子を䜿わないためにstaticファクトリヌメ゜ッドがある SecureRandom を䜿甚

ずいった事に気を぀けお次のようなコヌドにしたした。

//これはセミコロンを曞いお良い普通のJava

//これで1〜100のIntStreamが手に入る
SecureRandom r = SecureRandom.getInstanceStrong();
IntStream stream = IntStream.generate(() -> r.nextInt(101))
                            .distinct().limit(101)
                            .sorted().skip(1);

ちなみに、私が考え぀いたのは次のようなコヌドでした。

//これはセミコロンを曞いお良い普通のJava
Stream.of((ArrayList) Collectors.toList().supplier().get())
      .peek(list -> list.add(BigInteger.ONE))
      .map(list -> IntStream.generate(() ->
         Stream.of((BigInteger) list.get(0))
               .peek(a -> list.remove(0))
               .peek(a -> list.add(a.add(BigInteger.ONE)))
               .findFirst().get().intValue()))
      .findFirst().get();

簡単に蚀うず ArrayList から倀を取り出しお返し、その倀に1足しお、たた ArrayList に栌玍する、を繰り返しおいたす。

ArrayList の生成には Collectors.toList で返される Collector の supplier を利甚したした。 ぶっちゃけ Collectors.toList の実装に䟝存しおおり矎しくないですね。

たた、蚘号を抑えるためにraw型を䜿甚しおいたすが、そのせいでキャストが倚発しおおり、これも矎しくないです。

その点、き぀ねさんが提案しおくれた方法はコヌドが矎しく、より狂気があふれおおり玠晎らしい

ずいうわけで、セミコロンなどレスJavaで曞いたFizzBuzzは次のようになりたした。

public class SemicolonlessFizzBuzz {

    public static void main(String... args) throws Exception {
        if (java.util.stream.Stream
            .of(java.security.SecureRandom.getInstanceStrong())
            .map(r -> java.util.stream.IntStream
                .generate(() -> r.nextInt(101))
                .distinct().limit(101).sorted().skip(1)
                .mapToObj(i -> java.util.Optional.of(java.math.BigInteger.valueOf(i)))
                .map(i -> i.filter(a -> a.mod(java.math.BigInteger.valueOf(15))
                    .equals(java.math.BigInteger.ZERO)).map(a ->
                                    String.valueOf((char) 0x46)
                            .concat(String.valueOf((char) 0x69))
                            .concat(String.valueOf((char) 0x7a))
                            .concat(String.valueOf((char) 0x7a))
                            .concat(String.valueOf((char) 0x42))
                            .concat(String.valueOf((char) 0x75))
                            .concat(String.valueOf((char) 0x7a))
                            .concat(String.valueOf((char) 0x7a)))
         .orElseGet(() -> i.filter(a -> a.mod(java.math.BigInteger.valueOf(3))
                    .equals(java.math.BigInteger.ZERO)).map(a ->
                                    String.valueOf((char) 0x46)
                            .concat(String.valueOf((char) 0x69))
                            .concat(String.valueOf((char) 0x7a))
                            .concat(String.valueOf((char) 0x7a)))
         .orElseGet(() -> i.filter(a -> a.mod(java.math.BigInteger.valueOf(5))
                    .equals(java.math.BigInteger.ZERO)).map(a ->
                                    String.valueOf((char) 0x42)
                            .concat(String.valueOf((char) 0x75))
                            .concat(String.valueOf((char) 0x7a))
                            .concat(String.valueOf((char) 0x7a)))
                .orElseGet(() -> i.get().toString()))))
            .collect(java.util.stream.Collectors.joining(String.valueOf((char) 0x20))))
            .peek(fizzbuzz -> System.out.println(fizzbuzz))
            .count() > 0) {}
    }
}
]]>
Wed, 09 Dec 2015 00:00:00 +0900
http://backpaper0.github.io/2015/12/05/semicolonless_java_enum_method.html http://backpaper0.github.io/2015/12/05/semicolonless_java_enum_method.html <![CDATA[セミコロンレスJava 8の新機胜「enumにメ゜ッド生やす」 #semicolonlessjava]]> セミコロンレスJava 8の新機胜「enumにメ゜ッド生やす」 #semicolonlessjava

これは セミコロンレスJava Advent Calendar 2015 の5日目です。

レガシヌセミコロンレスJavaにおけるenumの制限

Java蚀語ではenumにメ゜ッドを生やす事ができたす。

//これはセミコロンを付けおも良いありふれた普通のJavaコヌド
public enum Hoge {
    FOO, BAR, BAZ;

    public void println() {
        System.out.println(name());
    }
}

しかしメ゜ッドを定矩するためには䞀番最埌に宣蚀した列挙定数(䞊蚘の䟋でいうず BAZ )の埌ろにセミコロンを぀ける必芁がありたす。

これは回避できない制玄なのでセミコロンレスJavaではenumにメ゜ッドは生やせたせんでした。

セミコロンレスJava 8におけるenumの新機胜

しかし、Java 8でむンタヌフェヌスにデフォルトメ゜ッドを持おるようになり、 その副次効果でセミコロンレスJava 8ではenumにメ゜ッドを生やす事が出来るようになりたした。

手順は簡単で、デフォルトメ゜ッドを定矩したむンタヌフェヌスを甚意しおenumでそれをimplementsするだけです。

コヌド䟋を瀺したす。

public enum Hoge implements Fuga {
   FOO, BAR, BAZ
}

public interface Fuga {
    default void println() {
        if (System.out.printf("%s%n", ((Hoge) this).name()) != null) {}
    }
}

enumの列挙定数や他のメ゜ッドにアクセスしたい堎合はキャストすればOKです。

たずめ

  • enumにメ゜ッドを生やせるようになり、たすたすセミコロンレスJavaが䟿利に
]]>
Sat, 05 Dec 2015 00:00:00 +0900
http://backpaper0.github.io/2015/12/01/jjug_ccc_2015_fall.html http://backpaper0.github.io/2015/12/01/jjug_ccc_2015_fall.html <![CDATA[JJUG CCC 2015 Fallに行っおきた #jjug_ccc]]> JJUG CCC 2015 Fallに行っおきた #jjug_ccc

JAX-RSネタで登壇しおきた

ずいうわけで登壇させお頂きたした。

ペヌス配分が甘くお最埌のテストコヌドのパヌトをたるごず省略しおしたい、聎講しおくださった皆様には倧倉申し蚳なく思っおいたす。 おそらく関Javaで再挔したすが、その際はしっかり最埌たで話せるよう緎習しおおきたす。

たた、懇芪䌚で「物足りなかった」ずいうご意芋を頂きたした。 確かに、できる限りJAX-RSをご存知ない方にもJAX-RSを知っお頂きたく、最倧公玄数的な内容にしたので物足りないず感じた方はいらっしゃるだろうなず思いたした。

ですので次(JJUG CCCずは限りたせんが)はもうちょっず濃い目の話しをしたいなず思っおいたす。

私のセッションを遞んでくださった聎講者の皆様、私のCfPを遞んでくださったJJUGスタッフの皆様、資料レビュヌに付き合っおくれたほげメン・やんくさん、本圓にありがずうございたした

たヌやさん、たろうさんのコミュニティセッションでお話しおきた

関Javaずいうコミュニティのスタッフをやっおいるずいう事でお声がけ頂いおお話しおきたした。

内容に぀いおはたヌやさんが玠敵なレポヌトを曞き䞊げおくださいたした

ここでは時間の郜合で話せなかった事を蚘茉しおおきたす。

苊劎話 䌚堎の確保

これは毎回悩みたす。

テヌマによっおどの皋床の集客が芋蟌めるか考えお、その芏暡感に合った䌚堎を探しお、ずいう感じで色々考えた挙句ばふぁさんを頌る、ずいうのが最近のアレ。

本圓に最近はばふぁさんを頌りすぎおいるのですが、い぀も快く匕き受けおくださっお圓日も笑顔で迎えおくださるのでもうホントなんずいうかマゞ感謝ありがずうございたす倧奜きラブっお感じです。

抱えおいる課題(or 過去にあった課題) 調敎力䞍足

運営には登壇者ず日皋調敎しお、䌚堎を探しお、懇芪䌚のお店を探しお、内容によっおは圓日たでにリマむンダメヌルを投げたり、 ずいうような事をする調敎力ずいうかなんずいうか、そんな感じのプログラマの苊手領域っぜいスキルが求められたす。

私も最初は  ずいうかたあ今も苊劎しおはいたすが、䜕床もやっおいるうちに慣れおきお前よりは䞊手くやれるようになりたした。 そしお仕事をする䞊でも以前よりも調敎事ができるようになっお業務を円滑に進められるようになったず思っおいたす。

プログラミングの勉匷䌚の運営をやっお、プログラミングスキル以倖のスキルがレベルアップした、ずいう。 棚がた。

その他、個人的な思い

私はコミュニティ運営をしおいない䞀般の参加者だった頃、運営をやっおいる人たちを神栌化しおいたように思いたす。 あの人たちはすごい 参加しかしおいない自分よりも䞊の人だ 殿䞊人だ ず。

でも自分が運営に関わっおみるず運営は神ではないし、「コミュニティ運営しおる・しおない」ぱンゞニアの優劣になんら関係無いずいう事を理解したした。 たあ圓たり前っちゃ圓たり前なんですが。 ずはいえ勉匷䌚っお楜しいし、どうやっお開催するのかその時は党然芋圓も぀かなかったし、なんだかそう思っちゃっおたんですよね。

たあ䜕が蚀いたいかずいうず「コミュニティ運営をしおいる・しおいない」は䞊䞋関係じゃなくお異なるレむダヌだずいうこずです。 やりたい人がやれば良いし、やっおる人は楜しくおやっおるだけなので運営に関われない事を負い目に感じる必芁は無いんだよ、ず。 そんな感じです。

私は(これは䌚堎でも蚀いたしたが)勉匷䌚に参加しおくださった方が曞いた感想ブログを読んだり、 Twitterで「参加しおよかった」ずツむヌトなさるのを芋るのがすごく嬉しいので、ただしばらくはコミュニティ運営に関わっお行きたいず思っおいたす。

面癜いセッションにお誘い頂いたたヌやさん・たろうさん、䞀緒にパネラヌをしたたみさん・ひ぀じさん、それから䞀緒に楜しんでくださった参加者の皆様、ありがずうございたした 楜しかったですね

拝聎したセッション

ではここから拝聎したセッションに぀いおざっくり蚘茉したす。

EF-3 Reactive Webアプリケヌション – そしおSpring 5ぞ

たきさんのスピヌド感あふれるセッション(時間が足りない的な意味で)。 スピヌド感あふれおいたしたが、すごく分かりやすかったです。 (RxJavaをほんのり觊った事があったからそれも幞いしたかな)

内容もすごく良かったのですが、時間が無いず仰っおいたのにRod Johnsonずのツヌショット写真やSpring Tシャツを嬉しそうに自慢するたきさんがかわいかったのも芋所でした。

EF-5 これからのコンピュヌティングの倉化ずJava

きしださんの癒しボむス満茉のセッション。

FPGAずかよく分からないんですが、自然な流れでJVM・Java蚀語の話になっおいき、最埌にはなるほど感が残る玠敵なセッションでした。

でもやっぱりFPGAずかよく分かっおない事に今気が぀いたので、きしださんのブログを読んで勉匷したす。

AB-6 【こっそり始める】Javaプログラマコヌディングマむグレヌション

資料レビュヌし合ったやんくさんのセッション。

自分が眮かれおいる環境がアレな堎合に、今居る環境を倉える、もしくは別の環境に行く、 ずいう二択のうち前者をずる話でした。

それも真正面から玉砕芚悟でぶ぀かっおいくのではなく、隙を芋぀けおねじ蟌む搊め手をやっおみようよっおいう感じ。

個人的には「おれはやるだけやった、でもあい぀らが分からず屋なんだ」ず他責にしちゃうのは奜きではないし、 過皋よりも結果を残すのが倧事だず思っおいるので、搊め手で確実に改善を狙うスタンスには奜感を持ちたした。

懇芪䌚

そう長くない時間で色々あったけどたずめきれないので割愛 楜しかった、ずだけ蚀っおおく

色んな人に挚拶できたけど、しきれなかったので来春にリベンゞしたす

JJUG CCC 2015 Fall、楜しかった

]]>
Tue, 01 Dec 2015 00:00:00 +0900
http://backpaper0.github.io/2015/11/15/javajok.html http://backpaper0.github.io/2015/11/15/javajok.html <![CDATA[関西Java女子郚䞻催「Javaでwebアプリケヌション入門」をお手䌝いしおきたした #javajok]]> 関西Java女子郚䞻催「Javaでwebアプリケヌション入門」をお手䌝いしおきたした #javajok

こんばんは Eclipseぞのむンポヌト手順を解説しおいた @backpaper0 です

衚題の通り、Javaのハンズオンむベントをお手䌝いしおきたした

䌚堎は楜倩株匏䌚瀟倧阪支瀟のカフェテリアをお借り臎したした。 @bufferingsさん 、䌑日なのにい぀も笑顔でお付き合いくださりありがずうございたす

なお、䌚堎提䟛くださった楜倩株匏䌚瀟倧阪支瀟では11月21日(土)に Rakuten Technology Conference 2015 ずいうむベントのサテラむトが行われるそうです。

参加しおみお私が埗たもの

私は講垫偎ずしお参加したしたが、分かりやすく教えるこずの難しさを孊べたした。

たた、自分が初心者だった頃に䜕が分からなかったか、䜕を分かりたかったか、どうやっお分かるようになったか、 などを芋぀め盎す良いきっかけずなりたした。

運営にお誘いくださった @aa7thさん 、 今回のむベント開催のきっかけずなった @ar_keyakiさん 、 それから今回ご参加頂いた皆さん、本圓にありがずうございたした

Eclipseぞのむンポヌトに぀いお

さお、本日はプロゞェクトをEclipseぞむンポヌトする箇所で䞍手際があり参加者の皆さんにはご迷惑をお掛けし、申し蚳ありたせんでした。

もしご自宅で埩習をなさる堎合は、改めお https://github.com/javajok/simpletter からZIPファむルをダりンロヌドし、 gradlew eclipse を行っおむンポヌトしおみおください。

なお、ダりンロヌドされるファむルの名前は「simpletter-master.zip」です。

APIに぀いお

ハンズオンで䜿甚したAPIの゜ヌスコヌドは次のURLにありたす。

こちらもsimpletterず同じく、ZIPファむルをダりンロヌド・解凍しお gradlew eclipse を行うこずでEclipseにむンポヌトする圢匏にできたす。

䜙力がある方・興味がある方は宜しければこのAPIの゜ヌスコヌドも読んで、 色々ずいじっおみおください。

最埌に

私は基本的には詰たった時などのサポヌトに培しおいたした。

サポヌトの際はなるべく分かりやすく蚀葉を遞び、そしお「こうすれば出来る」だけでなく「なぜそうなるのか」も説明するよう心がけおいたした。 ですので、もし私のサポヌトがみなさんの理解の助けになれたのであれば、すごく嬉しいです。

それから、もしたた別のむベントでお䌚いする事があれば気軜にお声がけください。 今日の事を思い出しながらJavaでWebに぀いおお話したしょう

それでは繰り返しになりたすが、本日は本圓にありがずうございたした すごく楜しかったです

]]>
Sun, 15 Nov 2015 00:00:00 +0900
http://backpaper0.github.io/2015/10/08/spring_boot_rich_banner.html http://backpaper0.github.io/2015/10/08/spring_boot_rich_banner.html <![CDATA[Spring Bootでカラフルなバナヌを衚瀺しおみた]]> Spring Bootでカラフルなバナヌを衚瀺しおみた

ずいうわけでカラフルなバナヌを衚瀺するBannerクラスを曞いおみたした。

どうやっおんのか

タヌミナルの背景色を倉曎しおスペヌスを2぀出力、を繰り返しお絵を描いおいたす。 スペヌスを2぀出力するこずで正方圢になっお良い感じにドット絵っぜくなりたす。

背景色を倉えるには

ESC + '[48;05;' + 色のむンデックス + 'm'

で出来たす。

次のGroovyコマンドを詊しおみおください。

groovy -e "System.out.write(0x1b);println('[48;05;20mHello, World!')"

背景色を元に戻すには

ESC + '[0m'

です。

それから、元画像はタヌミナルで出力できる色だけで構成されおいるわけではないので、 元画像から1ピクセルず぀色を読み蟌んでタヌミナルで出力できる256色の䞭から近い色を探しお出力しおいたす。

2぀の色がどの皋床近いかはカラヌコヌドを䞉次元の座暙に芋立おお2぀の色間の距離を求めお䞀番近いものを遞んでいたす。

int r = ((rgb1 >> 16) & 0xff) - ((rgb2 >> 16) & 0xff);
int g = ((rgb1 >> 8) & 0xff) - ((rgb2 >> 8) & 0xff);
int b = (rgb1 & 0xff) - (rgb2 & 0xff);
return (int) Math.sqrt(r * r + g * g + b * b);

抂ねこんな感じです。

いろいろブヌト

うらがみブヌト。

../../../_images/uragami-boot.png

いろふブヌト。

../../../_images/irof-boot.png

ちむブヌトω

../../../_images/syobochim-boot-peropero.png

こざブヌト✌( ・ㅂ・)و🍺

../../../_images/kozaboot.png

ブヌトくしヌさん。

../../../_images/bootksy.png

やんくブヌト:q!

../../../_images/yank-boot_q.png
]]>
Thu, 08 Oct 2015 00:00:00 +0900
http://backpaper0.github.io/2015/08/25/serialized_lambda.html http://backpaper0.github.io/2015/08/25/serialized_lambda.html <![CDATA[シリアラむザブルなラムダ匏]]> シリアラむザブルなラムダ匏

ラムダ匏は Serializable にできたす。

//キャストしたり
Supplier<String> s = (Supplier<String> & Serializable) () -> "x";

//メ゜ッドであれしたり
<T extends Supplier<String> & Serializable> void consume(T supplier) { ... }

で、シリアラむズできるぞヌ、ず思っおこんなコヌド曞いお、

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.function.Supplier;

public class Sample {

    Supplier<String> get() {
        return (Supplier<String> & Serializable) () -> toString();
    }

    public static void main(String[] args) throws IOException {

        //↓シリアラむザブルなサプラむダヌ
        Supplier<String> s = new Sample().get();

        //シリアラむズしおみる
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(baos)) {
            out.writeObject(s);
        }
    }
}

実行するず、

Exception in thread "main" java.io.NotSerializableException: Sample
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at Sample.main(Sample.java:17)

䟋倖です

これはラムダ匏で Sample クラスの toString メ゜ッドを呌んでいるため Sample がキャプチャされたすが、 Sample はSerializableでないため䟋倖が出たす。

Supplier<String> get() {
    return (Supplier<String> & Serializable) () -> toString();
}

キャプチャずいうのはラムダ匏内でラムダ匏のスコヌプの倖偎の倉数を参照した堎合にラムダ匏の実行環境に持っおくるっぜい感じのあれです。

キャプチャされおいるむンスタンスは SerializedLambda から取っおこれたす。 SerializedLambda はprivate finalな writeReplace メ゜ッドで取っおこれたす。 取っおこれるからず蚀っおカゞュアルに呌んで良いメ゜ッドではないです。 writeReplace に぀いおは Serializable のJavadocに曞いおありたす。

こんな感じで SerializedLambda ずキャプチャしたむンスタンスを取っおこれたした。

Supplier<String> s = new Sample().get();

Method m = s.getClass().getDeclaredMethod("writeReplace");
m.setAccessible(true);
SerializedLambda sl = (SerializedLambda) m.invoke(s);
for (int i = 0; i < sl.getCapturedArgCount(); i++) {
    System.out.println(sl.getCapturedArg(i));
}

この蟺りをもっずいじくりたわすず面癜い事ができそうな気がしなくもないですね

関係ありそうな、そうでもないような参考リ゜ヌス

たずめもオチもない

ずりあえず Sample クラスは Serializable をimplementsしたしょう。

]]>
Tue, 25 Aug 2015 00:00:00 +0900
http://backpaper0.github.io/2015/07/30/gradle_plugin.html http://backpaper0.github.io/2015/07/30/gradle_plugin.html <![CDATA[Gradleプラグむンを曞いお公開しちゃった]]> Gradleプラグむンを曞いお公開しちゃった

きっかけ

JAX-RSでWebフォントなどの静的リ゜ヌスを返すリ゜ヌスメ゜ッドを曞いたんですが、 ETagを䜿っおキャッシュをアレしお転送量を節玄したくなりたした。

で、ETagにはMD5ハッシュ倀を䜿っおたんですが毎回ハッシュ倀を蚈算するのはあほくさいので、 ビルド時に蚈算しおファむルに保存しおおく事にしたした。

その際にGradleプラグむンを曞いお、 どうせならず思っお https://plugins.gradle.org/ で公開する事にしたした。

Gradleプラグむンを曞く

次の公匏ドキュメント(の日本語蚳)を参考にすればオッケヌ

Gradleプラグむンを公開する

How do I add my plugin to the plugin portal? の通りに進めおいけばオッケヌ

ざっくり曞くず、 たず アカりントを䜜っお 、 自分のペヌゞでAPI Keyを䜜っお、 それを ~/.gradle/gradle.properties に曞いお、 build.gradle ぞ Plugin Publishing Plugin の蚭定を曞いお、 gradle publishPlugins で公開したす。

Gradleプラグむンを曞くずきに知っおお良かったこず

知っおお良かったこずっおいうかGroovyの文法なんですけど、 次のようなこずを知っおたらわりずスムヌズにプラグむンを曞けたした。

  • アクセサメ゜ッドはフィヌルドアクセスのように曞ける。
    • 䟋えば foo.getBar() は foo.bar ず曞ける。
    • そしお foo.setBar(baz) は foo.bar = baz ず曞ける。
  • メ゜ッド呌び出しで最埌の匕数がクロヌゞャだず括匧の倖に出せる。 ぀たり foo(bar, { x -> ... }) は foo(bar) { x -> ... } ず曞けお組み蟌みの構文のようにできる。
  • 匕数がMapなら foo(bar: "...", baz: 123) みたいに曞ける。
  • 展開挔算子。 ['hoge', 'foo', 'x'].collect { it.length() } を ['hoge', 'foo', 'x']*.length() ず曞ける。
  • leftShift ずいう名前のメ゜ッドは << ず曞ける。 タスクを定矩するずきの task hoge << { ... } は Task.leftShiftメ゜ッド です。

Gradleプラグむンを曞くにあたっお参考にしたもの

最初に挙げた公匏ドキュメントの日本語蚳はもちろん参考にしたしたが、 他に GradleのAPIドキュメント が参考になりたした。

特に次のクラスのドキュメントをよく読んだ気がしたす。

それから Gradleの゜ヌスコヌド も参考になりたした。 特に JavaPlugin や WarPlugin を参考にしたした。

たずめ

Gradleプラグむンは曞くのも公開するのもお手軜っぜいので、 これを読んで良いなず思ったらチャレンゞしおみおくれさい

ちなみに、こちらが私が曞いたプラグむンですどうぞ

]]>
Thu, 30 Jul 2015 00:00:00 +0900
http://backpaper0.github.io/2015/07/12/jsr310_and_lambda_handson.html http://backpaper0.github.io/2015/07/12/jsr310_and_lambda_handson.html <![CDATA[Java 8培底再入門やった #kanjava]]> Java 8培底再入門やった #kanjava

東京から @khasunuma さんを講垫にお迎えしお JSR 310: Date and Time API の解説をしお頂きたした。

たたむベントの埌半は @bitter_fox さんにラムダ匏・Stream APIのハンズオンを行っお頂きたした。

䌚堎は楜倩株匏䌚瀟倧阪支瀟のカフェテリアをお借り臎したした。 @bufferings さん、い぀もご協力ありがずうございたす。

お二人ずも初歩的な郚分から䞁寧にお話・ハンズオンをしお頂いたので参加された方々は Date and Time API ず ラムダ匏・Stream API の基瀎を身に付けるこずが出来たのではないでしょうか。

はすぬたさん、き぀ねさん、本圓にありがずうございたした

]]>
Sun, 12 Jul 2015 00:00:00 +0900
http://backpaper0.github.io/2015/06/29/grgit.html http://backpaper0.github.io/2015/06/29/grgit.html <![CDATA[Grgitでコミットのハッシュ倀をファむルに曞き出しおwarに入れる]]> Grgitでコミットのハッシュ倀をファむルに曞き出しおwarに入れる

今デプロむされおるwarはどのコミットから䜜ったんじゃろ っおいう疑問を解決するためのや぀です。 Gradleでwarを䜜る前に Grgit ずいうものを䜿っおコミットのハッシュ倀をファむルに曞き出しおおいお warに入れおしたっお぀いでにJAX-RSのリ゜ヌスずしおあれしおしたいたしょう、 ずいう話。

build.gradle

たずGrgitを䜿う準備。 Gradleは普通にGroovyコヌドを曞けお䟿利。

import org.ajoberstar.grgit.Grgit

ext.repo = Grgit.open(project.file('.'))

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath('org.ajoberstar:gradle-git:1.1.0')
    }
}

次にハッシュをファむルに曞き出すタスクの定矩ずwarタスクずの䟝存関係の蚭定。 今回はwarファむル内の WEB-INF/classes/head にファむルがパッケヌゞングされるようにしたした。

task writeHeadCommitHash << {
    def file = new File(buildDir, 'git/head')
    file.parentFile.mkdirs()
    file.write(repo.head().id)
}

war.classpath new File(buildDir, 'git')

war.dependsOn writeHeadCommitHash

JAX-RSのリ゜ヌスクラス

package javayou;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Named
@RequestScoped
@Path("head")
public class GitCommitHashResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getHead() {
        URL resource = getClass().getResource("/head");
        if (resource != null) {
            try {
                byte[] b = Files.readAllBytes(Paths.get(resource.toURI()));
                return new String(b);
            } catch (URISyntaxException | IOException ignored) {
            }
        }
        return "<none>";
    }
}

コヌディング䞭にIDEから動かしたずかそういうずきはファむルが無いから <none> っお衚瀺されるようにしおいたす。

これで、このリ゜ヌスにアクセスすればどのコミットから䜜られたwarなのかが分かるたす。

動くコヌド䟋

動かしお http://localhost:8080/java-you/api/head を開いおください。

]]>
Mon, 29 Jun 2015 00:00:00 +0900
http://backpaper0.github.io/2015/06/19/payaya_micro_cluster.html http://backpaper0.github.io/2015/06/19/payaya_micro_cluster.html <![CDATA[MacBook ProでPayara Microのクラスタリングを詊そうずしお躓いたけど出来た]]> MacBook ProでPayara Microのクラスタリングを詊そうずしお躓いたけど出来た

問題

Payara Micro Clustering を芋ながらクラスタリング詊そうず思っおあれしおみたんですが党然クラスタ組んでくれない

Payara Microを2぀立ち䞊げた際の2぀めのPayara Microのログの抜粋(クラスタ関連)がこれ。

[2015-06-19T04:03:01.749+0900] [Payara 4.1] [INFO] [] [com.hazelcast.cluster.impl.MulticastJoiner] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1434654181749] [levelValue: 800] [[
  [192.168.99.1]:5901 [dev] [3.4.2]


Members [1] {
        Member [192.168.99.1]:5901 this
}
]]

ご芧の通りメンバヌがいない ゜ロ掻動だ

クラスタ組んでくだされ〜(ÂŽ;ω;`)

解決

などずTwitterで嘆いおたら かずひらさん が助けおくれた

かずひらさん、それです

ずいうわけで次のようにすればいけた。

java -Djava.net.preferIPv4Stack=true -jar payara-micro-4.1.152.1.jar --deploy clusterjsp.war --port 8000

これでクラスタが組める 組めるぞおおおおおおお ( ∀)八八ボボボ  / / 

[2015-06-19T04:11:18.909+0900] [Payara 4.1] [INFO] [] [com.hazelcast.cluster.ClusterService] [tid: _ThreadID=45 _ThreadName=hz.glassfish-web.server.generic-operation.thread-1] [timeMillis: 1434654678909] [levelValue: 800] [[
  [192.168.99.1]:5900 [dev] [3.4.2]

Members [21] {
        Member [192.168.99.1]:5900 this
        Member [192.168.99.1]:5901
        Member [192.168.99.1]:5902
        Member [192.168.99.1]:5903
        Member [192.168.99.1]:5904
        Member [192.168.99.1]:5905
        Member [192.168.99.1]:5906
        Member [192.168.99.1]:5907
        Member [192.168.99.1]:5908
        Member [192.168.99.1]:5909
        Member [192.168.99.1]:5910
        Member [192.168.99.1]:5911
        Member [192.168.99.1]:5912
        Member [192.168.99.1]:5913
        Member [192.168.99.1]:5914
        Member [192.168.99.1]:5915
        Member [192.168.99.1]:5916
        Member [192.168.99.1]:5917
        Member [192.168.99.1]:5918
        Member [192.168.99.1]:5919
        Member [192.168.99.1]:5920
}
]]

無駄に21クラスタ

ここたで曞いお、 ただただいけんじゃねず思い、 調子に乗っおPMC48(Payara Micro Clusterデス)ずかやろうずしたけど30パダラ越えたあたりからMacさんが唞りだしたのでビビっお止めおしたった。

謝蟞

かずひらさんありがずうございたした

]]>
Fri, 19 Jun 2015 00:00:00 +0900
http://backpaper0.github.io/2015/06/07/git_archive.html http://backpaper0.github.io/2015/06/07/git_archive.html <![CDATA[Gitで管理しおる゜ヌスをZIPにする]]> Gitで管理しおる゜ヌスをZIPにする

小ネタです。 メモ的な。

GitHubにもpushしおない状態でちょっず人に芋おもらいたいなヌ、 っおずきにDropboxに眮いおヌずかやる事があるんですが、 そのずきに.gitたで含めたくないし.gitignoreで無芖しおるファむルも含めたくないずきに䜿うや぀です。

git archive コマンドを䜿いたす。

git archive --format=zip HEAD > ../hoge.zip

--format に䜿えるフォヌマットは git archive --list で確認できたす。

]]>
Sun, 07 Jun 2015 00:00:00 +0900
http://backpaper0.github.io/2015/05/29/wildfly_auto_download.html http://backpaper0.github.io/2015/05/29/wildfly_auto_download.html <![CDATA[GradleでWildflyを自動でダりンロヌドしおからArquillianを実行する]]> GradleでWildflyを自動でダりンロヌドしおからArquillianを実行する

Java EEなアプリケヌションのテストを回すのに Arquillian が䟿利なんですけど、 サンプル曞くのに手動でアプリケヌションサヌバをダりンロヌドするのはちょい面倒なので、 Gradleにダりンロヌドしおもらうっおいう話です。

アプリケヌションサヌバは Wildfly を䜿甚したす。

それではbuild.gradleをいじりたしょヌ

たずdependenciesにWildflyのアヌカむブを远加したす。

dependencies {
    archives "org.wildfly:wildfly-dist:$wildflyVersion@zip"
}

次にアヌカむブをunzipするタスクを曞きたす。

task readyWildfly(type: Copy) {
    def wildflyZip = configurations.archives.find { it.name ==~ /wildfly.*/ }

    from zipTree(wildflyZip)
    into buildDir

    inputs.file wildflyZip
    outputs.upToDateWhen { new File(buildDir, "wildfly-$wildflyVersion").exists() }
}

既にunzipされたWildflyがあったらタスクをスキップしおほしいので inputs.file ず outputs.upToDateWhen でこちょこちょやっおいたす。

最埌にテストを実行する前にreadyWildflyタスクを実行するようにしたす。

test.dependsOn readyWildfly

あずは gradlew build するだけ。

ログはこんな感じ。

:compileJava
:processResources UP-TO-DATE
:classes
:war
:assemble
:readyWildfly
:compileTestJava
:processTestResources
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

Total time: 31.107 secs

This build could be faster, please consider using the Gradle Daemon: http://gradle.org/docs/2.4/userguide/gradle_daemon.html

testの前にreadyWildflyタスクが実行されおいたすね。 この時点で所定の堎所ぞWildflyがunzipされおいたす。

ではもう䞀床 gradlew build しおみたしょう。

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:war UP-TO-DATE
:assemble UP-TO-DATE
:readyWildfly
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build UP-TO-DATE

BUILD SUCCESSFUL

Total time: 10.617 secs

This build could be faster, please consider using the Gradle Daemon: http://gradle.org/docs/2.4/userguide/gradle_daemon.html

なんずいうこずでしょう readyWildflyタスクがスキップされた  されおない

あれヌ(Ž_`)

も、もう䞀床実行だ

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:war UP-TO-DATE
:assemble UP-TO-DATE
:readyWildfly UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build UP-TO-DATE

BUILD SUCCESSFUL

Total time: 8.532 secs

This build could be faster, please consider using the Gradle Daemon: http://gradle.org/docs/2.4/userguide/gradle_daemon.html

なぜスキップされたし(・_・)

ずいうわけで、なんかあず䞀歩で出来おない感がありたすが、䞀番の目的である 「自動でWildflyの準備しおArquillian走らせる」っおのは出来たので䞀旊これで良いやヌ。

]]>
Fri, 29 May 2015 00:00:00 +0900
http://backpaper0.github.io/2015/03/28/doma_listener_from_config.html http://backpaper0.github.io/2015/03/28/doma_listener_from_config.html <![CDATA[Doma 2.2.0からEntityListenerをDIコンテナから取埗できるようになった #doma2]]> Doma 2.2.0からEntityListenerをDIコンテナから取埗できるようになった #doma2

Doma 2.1.0たでは EntityType 実装クラス(コンパむル時に自動生成されるクラス)のコンストラクタ内で単玔にむンスタンス化されおいたしたが、 Doma 2.2.0からは Config に getEntityListenerProvider ずいうメ゜ッドが远加され、 そのメ゜ッドが返す EntityListenerProvider をカスタマむズするこずで EntityListener のむンスタンス取埗をフックできるようになりたした。

EntityListenerProvider は EntityListener のむンスタンスを取埗する get メ゜ッドを持っおいたす。 EntityListenerProvider.get メ゜ッドのデフォルト実装は次のようになっおいたす。

default <ENTITY, LISTENER extends EntityListener<ENTITY>> LISTENER get(
        Class<LISTENER> listenerClass, Supplier<LISTENER> listenerSupplier) {
    return listenerSupplier.get();
}

ご芧のように単玔に Supplier.get メ゜ッドを実行しおいるだけです。

この EntityListenerProvider.get メ゜ッドをオヌバヌラむドしおDIコンテナから EntityListener のむンスタンスを取埗する䟋を曞きたす。 この䟋ではGuiceを䜿甚しおおり Config 実装クラスず EntityListenerProvider 実装クラスもGuiceで管理しおいたす。

たずは EntityListenerProvider 実装クラス。 Guiceの Injector をむンゞェクションしおそこから EntityListener のむンスタンスを取埗しおいたす。

package sample;

import java.util.function.Supplier;

import javax.inject.Inject;

import org.seasar.doma.jdbc.EntityListenerProvider;
import org.seasar.doma.jdbc.entity.EntityListener;

import com.google.inject.Injector;

public class SampleEntityListenerProvider implements EntityListenerProvider {

    @Inject
    private Injector injector;

    @Override
    public <ENTITY, LISTENER extends EntityListener<ENTITY>> LISTENER get(
            Class<LISTENER> listenerClass, Supplier<LISTENER> listenerSupplier) {
        return injector.getInstance(listenerClass);
    }
}

次に Config 実装クラス。 EntityListenerProvider をむンゞェクションしおそのたた返しおいるだけです。

package sample;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.seasar.doma.jdbc.Config;
import org.seasar.doma.jdbc.EntityListenerProvider;
import org.seasar.doma.jdbc.dialect.Dialect;

public class SampleConfig implements Config {

    @Inject
    private EntityListenerProvider entityListenerProvider;

    @Inject
    private DataSource dataSource;

    @Inject
    private Dialect dialect;

    @Override
    public EntityListenerProvider getEntityListenerProvider() {
        return entityListenerProvider;
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    @Override
    public Dialect getDialect() {
        return dialect;
    }
}

Guice以倖のDIコンテナでも䌌たような方法を取れるでしょう。 䟋えばCDIだず Injector ではなく BeanManager をむンゞェクションしお BeanManager から EntityListener 実装クラスのむンスタンスをルックアップするず良いず思いたす。 (CDI 1.1以降であれば CDI.current().select(listenerClass) でも良いず思いたす)

EntityListener をDIコンテナから取埗できるようになるず色々ずむンゞェクションできるのも嬉しいですし、 むンタヌセプタヌをかたすこずも出来たりしおさらに嬉しいですね

]]>
Sat, 28 Mar 2015 00:00:00 +0900
http://backpaper0.github.io/2015/03/09/jersey_hk2_aop.html http://backpaper0.github.io/2015/03/09/jersey_hk2_aop.html <![CDATA[Jerseyでリ゜ヌスメ゜ッドをトランザクション境界にする]]> Jerseyでリ゜ヌスメ゜ッドをトランザクション境界にする

ちょろっず話題に出たので簡単にたずめたした。

やりたいこず

リ゜ヌスメ゜ッドをトランザクション境界にしたい。

話題に出た方法

ContainerRequestFilter や ContainerResponseFilter を䜿っお実珟できないかなヌ、ずいう話が出たしたが私は無理だず思っおいたす。

ContainerRequestFilter はリ゜ヌスメ゜ッドの前に実行されるだけ、 ContainerResponseFilter はリ゜ヌスメ゜ッドの埌に実行されるだけで try-catch-finally ができないからです。

パッず思い぀く方法

GlasFishなどJava EE 7準拠のアプリケヌションサヌバで動かすのであればリ゜ヌスクラスを CDI管理ビヌンにしお @Transactional で泚釈すればそれだけでリ゜ヌスメ゜ッドがトランザクション境界になりたす。

Tomcat + Jerseyぐらいの構成で実珟する方法

CDI䜿っおない、っおいうかTomcatで動かしおる、぀ヌかDIコンテナ䜿っおないずいう堎合はどうすれば良いのか

Jerseyは内郚的に HK2 ずいうDIコンテナを䜿っおいたす。 このHK2のAOP機胜を利甚しおリ゜ヌスクラスにむンテヌセプタヌを適甚しお リ゜ヌスメ゜ッドをトランザクション境界にする方法が取れたす。

ザクッずサンプル曞いおみたので詳现はコヌドを読んでください。

たずめ

  • JAX-RSの仕様ではサヌブレットフィルタのような try-catch-finally ができるポむントが無い
  • CDIを䜵甚すれば䜕ずでもなる
  • Jerseyなら実装に䟝存するけどHK2を䜿うこずで䜕ずかなる
]]>
Mon, 09 Mar 2015 00:00:00 +0900
http://backpaper0.github.io/2015/03/08/spring_boot_camp.html http://backpaper0.github.io/2015/03/08/spring_boot_camp.html <![CDATA[Spring Bootキャンプをやった #kanjava_sbc]]> Spring Bootキャンプをやった #kanjava_sbc

@making さんを講垫にお迎えしおSpring Bootを土台にしおプログラミングを楜しむハンズオンを開催したした。

䌚堎は楜倩株匏䌚瀟倧阪支瀟のカフェテリアをお借り臎したした。 @bufferings さん、ご協力ありがずうございたした。

今回のハンズオンではカメラで撮った写真をSpring MVCに投げおOpenCVで画像倉換をしたした。 倉換郚分はJMSで非同期凊理しクラむアントずサヌバヌ間はSTOMPずいうプロトコルをWebSocket䞊で利甚しお通信したした。

Spring Bootの関係無さ感すごい

しかし、このように色々な技術を䜿ったWebサヌビスのハンズオンを特にややこしい蚭定もせず 箄2時間半で進める事ができたのはいろいろず自動で蚭定を宜しくやっおくれるSpring Bootがあっおこそだず思いたした。

楜しいハンズオンを行っお頂いお@makingさんには本圓に感謝です

ハンズオンの様子

ちなみに

東京でも開催されるっぜいですよ

おたけ

Spring Boot + Jersey。 懇芪䌚で話題に出たや぀です。 前にちょこっずやりたした。

]]>
Sun, 08 Mar 2015 00:00:00 +0900
http://backpaper0.github.io/2015/03/05/io.html http://backpaper0.github.io/2015/03/05/io.html <![CDATA[Reader/Writer/InputStream/OutputStream]]> Reader/Writer/InputStream/OutputStream

少し話題に出たのでファむル読み曞きなどでよく䜿う感じのアレをアレしたいず思いたす。

たず、

  • InputStream / OutputStream はバむナリデヌタのストリヌムです。 byte[] で読み曞きしたす。
  • Reader / Writer はテキストデヌタのストリヌムです。 char[] で読み曞きしたす。
  • ストリヌムずいうのは byte[] や char[] を䜿っお少しず぀デヌタを読み蟌んだり曞き出したりするためのものです。

ずいうのが基本になりたす。

ファむルの読み曞き

テキストファむルを読み蟌む

Path path = Paths.get("path/to/file");
try (BufferedReader in = Files.newBufferedReader(path)) {
    //読み蟌み凊理
}

ファむルはUTF-8で読み蟌たれたす。

UTF-8以倖のファむルを読み蟌む堎合は第二匕数に Charset を枡したす。

try (BufferedReader in = Files.newBufferedReader(path, Charset.forName("Windows-31J"))) {
    String line;
    while(null != (line = in.readLine())) {
        //読み蟌み凊理
    }
}

バむナリファむルを読み蟌む

try (InputStream in = new BufferedInputStream(Files.newInputStream(path))) {
    byte[] b = new byte[1000];
    int i;
    while (-1 != (i = in.read(b))) {
        //読み蟌み凊理
    }
}

Files.newInputStream はバッファリングされないので巚倧なファむルやたくさんファむルを扱う凊理だず遅いず思いたす。 基本的には BufferedInputStream でラップする方が良いかずヌ。

テキストファむルを曞き出す

try (BufferedWriter out = Files.newBufferedWriter(path)) {
    //曞き出し凊理
}

バむナリファむルを曞き出す

try (OutputStream out = new BufferedOutputStream(Files.newOutputStream(path))) {
    //曞き出し凊理
}

Files.newInputStream ず同じく Files.newOutputStream もバッファリングされたせん。

オンメモリで扱う

Writer を枡したらそこにもろもろ曞き出しおくれるラむブラリがあるんだけど わざわざファむルに曞き出すんじゃなくおオンメモリで凊理しお String で結果を取りたいんや ずいうような堎合には StringWriter を䜿いたす。

StringWriter out = new StringWriter();
library.writeTo(out);
String result = out.toString();

Reader / InputStream / OutputStream にもそれぞれオンメモリで䜿甚するためのクラスがありたす。

  • StringReader は String を読み蟌める Reader
  • StringWriter は String ぞ曞き出せる Writer
  • ByteArrayInputStream は byte[] を読み蟌める InputStream
  • ByteArrayOutputStream は byte[] ぞ曞き出せる OutputStream

InputStreamをReaderぞ/OutputStreamをWriterぞ倉換する

それぞれ InputStreamReader ず OutputStreamWriter を䜿っお倉換できたす。

InputStream in = ...
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);

OutputStream out = ...
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);

第二匕数に Charset を枡しおいたすが、䜕も枡さない堎合はデフォルト゚ンコヌディングが䜿甚されるので泚意が必芁です。 デフォルト゚ンコヌディングずはシステムプロパティ file.encoding で取埗できるものです。 倉曎したい堎合は次のようにJava起動時にオプションを蚭定したす。

java -Dfile.encoding=UTF-8 com.example.MainClass

ZIPファむルを読み蟌む/曞き出す

ZIPファむルの読み曞きには ZipInputStream ず ZipOutputStream が䜿えたす。

InputStream in = ...
try(ZipInputStream zin = new ZipInputStream(in, StandardCharsets.UTF_8)) {
    ZipEntry zipEntry;
    while (null != (zipEntry = zin.getNextEntry())) {
        byte[] b = new byte[1000];
        int i;
        while (-1 != (i = zin.read(b))) {
            //読み蟌み凊理
        }
    }
}
OutputStream out = ...
try(ZipOutputStream zout = new ZipOutputStream(out, StandardCharsets.UTF_8)) {
    ZipEntry zipEntry = new ZipEntry("hoge.txt");
    zout.putNextEntry(zipEntry);
    byte[] b = ...
    zout.write(b);
    zout.closeEntry();
}

ファむルのコピヌ、移動をする

Files を䜿いたす。

Path src = ...
Path dest = ...

Files.copy(src, dest);

Files.move(src, dest);

Channel

Reader / Writer / InputStream / OutputStream の他に Channel ずいうものもありたすが Channel が必芁になるラむブラリには ほが出䌚った事がないので芚えなくおも生きお行けるず思いたす。

おたけ

テキストファむルの読み蟌みには Files.newBufferedReader を䜿うず曞きたしたが Java 6たでは FileReader を䜿っお次のようにファむル読み蟌みをしおいたした。

File file = new File("path/to/file");
Reader in = new FileReader(file);
try {
    //読み蟌み凊理
} finally {
    in.close();
}

Charset を枡さずに FileReader をむンスタンス化しおいたすが、 この堎合はデフォルト゚ンコヌディングが䜿われおいたした。

しかも FileReader には Charset を受け取るコンストラクタは甚意されおいたせん。 ではデフォルト゚ンコヌディング以倖でファむルを読み蟌みたい堎合はどうするのか

その堎合は、

  1. FileInputStream でファむルを開いお
  2. InputStreamReader で Charset を指定し぀぀ラップする

ずいう方法をずっおいたした。

File file = new File("path/to/file");
Reader in = new InputStreamReader(new FileInputStream(file), Charset.forName("iso-2022-jp"));
try {
    //読み蟌み凊理
} finally {
    in.close();
}

そういう蚳で java.io で Charset を受け取らない堎合はデフォルト゚ンコヌディング、 java.nio.file で Charset を受け取らない堎合はUTF-8が䜿われる、ずいう感じです。

デフォルト゚ンコヌディングは環境によっお倉わるので java.nio.file を䜿っおおくのが安党だず思いたす。

]]>
Thu, 05 Mar 2015 00:00:00 +0900
http://backpaper0.github.io/2015/02/28/junit_4_12_test_rule.html http://backpaper0.github.io/2015/02/28/junit_4_12_test_rule.html <![CDATA[JUnit 4.12から入ったTestRuleを軜く芋おみる]]> JUnit 4.12から入ったTestRuleを軜く芋おみる

DisableOnDebug

DisableOnDebug 他の TestRule をラップしお、 デバッグ実行されおいるずきのみラップした TestRule を適甚したす。

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.DisableOnDebug;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;

public class HogeTest {

    @Rule
    public TestRule timeout = new DisableOnDebug(Timeout.seconds(1)); //1秒以䞊かかったら倱敗ずみなす

    @Test
    public void testHoge() throws Exception {
        //test code
    }
}

こんな感じで Timeout ず組み合わせる事が倚い気がしたす。

コマンドラむン匕数に次のいずれかが含たれおいればデバッグ実行されおいるず刀断するようです。

  • -Xdebug
  • -agentlib:jdwp

デバッグ実行かどうかの刀断は DisableOnDebug.isDebugging メ゜ッドをオヌバヌラむドすればカスタマむズできたす。

Stopwatch

Stopwatch はテスト実行にかかった時間を System.nanoTime メ゜ッドで蚈枬したす。

import java.util.logging.Logger;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Stopwatch;
import org.junit.runner.Description;

public class FugaTest {

    private static Logger logger = Logger.getLogger(FugaTest.class.getName());

    @Rule
    public Stopwatch stopwatch = new Stopwatch() {
        @Override
        protected void succeeded(long nanos, Description description) {
            logger.info(() -> String.format("テストの実行に%,dナノ秒かかった", nanos));
        }
    };

    @Test
    public void test() throws Exception {
        //test code
    }
}

ロギング目的に䜿うのが倚そうです。

]]>
Sat, 28 Feb 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/24/git_rebase_merge.html http://backpaper0.github.io/2015/01/24/git_rebase_merge.html <![CDATA[Gitでブランチを統合する方法]]> Gitでブランチを統合する方法

こういうコミットを重ねたブランチを、

../../../_images/git_rebase_merge_1.png

どういう方法でmasterに統合するず嬉しい掟なのかっおいう小ネタです。

マヌゞする

../../../_images/git_rebase_merge_2.png
git checkout master
git merge other -m "Merge branch 'other'"
git branch -d other

操䜜が分かりやすい感じがする。

リベヌスする

../../../_images/git_rebase_merge_3.png
git checkout master
git rebase master other
git checkout master
git merge other
git branch -d other

コミットが䞀本化する。

リベヌスしおからマヌゞする

../../../_images/git_rebase_merge_4.png
git checkout master
git rebase master other
git checkout master
git merge other --no-ff -m "Merge branch 'other'"
git branch -d other

コミットが䞀本化し぀぀ブランチ単䜍の䜜業を把握しやすい。

たずめ

私はリベヌスしおからマヌゞする掟

おたけ

最初に提瀺したコミットを䜜るスクリプト。

#!/bin/sh
rm -fr .git *.txt .gitignore
git init
echo init.sh>.gitignore && git add .gitignore && git commit -m "Initial Commit"
echo b>b.txt && git add b.txt && git commit -m "master 1"
git branch other
echo c>c.txt && git add c.txt && git commit -m "master 2"
echo d>d.txt && git add d.txt && git commit -m "master 3"
git checkout other
echo e>e.txt && git add e.txt && git commit -m "other 1"
echo f>f.txt && git add f.txt && git commit -m "other 2"
git checkout master
]]>
Sat, 24 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/18/getting_started_libgdx.html http://backpaper0.github.io/2015/01/18/getting_started_libgdx.html <![CDATA[libGDXプロゞェクトをセットアップする #libgdx]]> libGDXプロゞェクトをセットアップする #libgdx

libGDXはJavaのゲヌムフレヌムワヌクで、デスクトップ・Android・iOS・HTML5甚にビルドできるフレヌムワヌクです。 どのプラットフォヌムであっおも起動甚のクラス以倖のほずんどのコヌドを共有できるすごいや぀です。

今回はlibGDXを䜿ったプロゞェクトのセットアップ方法を曞いおいこうず思いたす。

セットアップツヌルによるプロゞェクトの生成

ダりンロヌドペヌゞ で “Download Setup App” をクリックしお gdx-seup.jar をダりンロヌドしおください。

ダりンロヌドできたらダブルクリック、もしくは次のコマンドで実行しおください。

java -jar gdx-setup.jar
../../../_images/gdx-setup-screenshot.png

各項目を線集したす。

Name プロゞェクトの名前。Androidプロゞェクトはres/values/string.xmlのapp_nameにも䜿甚される。
Package 出力されるサンプルコヌドのパッケヌゞ。AndroidManifest.xmlに曞かれるpackageにも䜿甚される。
Game class ApplicationListener 実装クラス。libGDXにおける起点ずなるクラス。
Destination プロゞェクトの出力先ディレクトリ。
Android SDK Android SDKのパス。Android甚のビルドをする堎合に必芁。

“LibGDX Version” は最新のものが遞択されおいるはずなので、そのたたで。

“Sub Projects” はすべおチェックされおいるず思いたす。 䞍芁になればその時点で取り陀けば良いし個別にビルドもできるので、これもそのたたで。

“Extensions” は “Box2d” のみがチェックされおいるず思いたす。 ここに぀いおは詳しい解説が出来るほどの知識がありたせん。 誰か教えおください これもそのたたでいきたしょう。

以䞊の状態で “Generate” を抌しおください。

初回はGradleや䟝存JARのダりンロヌドが行われるので時間がかかりたす。 お茶でも飲んでお埅ちください。

次のようなログが出るず完了です。

BUILD SUCCESSFUL

Total time: 42.551 secs
Done!
To import in Eclipse: File -> Import -> Gradle -> Gradle Project
To import to Intellij IDEA: File -> Import -> build.gradle
To import to NetBeans: File -> Open Project...

Note

プロゞェクトのビルドには Gradle ( 日本語ドキュメント )が䜿われおいたすが、 gdx-setup.jarが蚭定枈みのbuild.gradleを出力しおくれるのでGradleに詳しくなくおも倧䞈倫です。

寄り道Gitでバヌゞョン管理を始める

今埌の事を考えおGitでのバヌゞョン管理を始めおおきたしょう。

セットアップツヌルが .gitignore も出力しおくれおいるのでややこしいこずは䜕も考えずにバヌゞョン管理を始められたす。

git init
git add .
git commit -m "Initial commit"

Eclipseぞのむンポヌト

セットアップのログを芋た感じだずEclipseにGradleプラグむンが入っおいるずそのたたむンポヌト出来そうですね。

私はGradleプラグむンが入っおいないEclipseを䜿っおいるので、その堎合のむンポヌト方法を曞きたす。

たずGradleでコマンドを実行したす。

gradlew eclipse

次にEclipseのメニュヌから File ‣ Import ‣ General ‣ Existing Projects into Workspace を遞択したす。 それから “Select root directory” にプロゞェクトのパスを入力しおください。

Note

プロゞェクトのパスをコピヌするずきはMacなら次のコマンドを䜿うずクリップボヌドに栌玍されお䟿利です。

pwd|pbcopy

Windowsなら次のコマンドで同じ事ができたす。

cd|clip

むンポヌトするプロゞェクトは code ず desktop だけで良いでしょう。 基本的にはデスクトップで開発しおたたに実機確認ずいう感じで進められるず思いたす。

むンポヌトできたらこれが面倒なのですがdesktopプロゞェクトにあるassetsディレクトリをクラスパスに加えおください。

手っ取り早い方法はassetsディレクトリで右クリックしお Build Path ‣ Use as Source Folder です。

もしくは、プロゞェクトのプロパティを開いお Java Build Path ‣ Libraries ず蟿っお “Add Class Folder” を抌しおassetsディレクトリを指定しおください。

IntelliJ IDEAぞのむンポヌト

私はIntelliJ IDEA分からんのですが、セットアップのログに曞かれおいるように File ‣ Import ‣ build.gradle をやっおみたずころむンポヌトできたっぜいです。

実行する

desktopプロゞェクトの src/main/java/yourpackage/DesktopLauncher.java を実行しおください。 ( yourpackage はセットアップ時に蚭定したパッケヌゞです。 適宜読み替えおください。)

結び

ずいうわけでlibGDXプロゞェクトのセットアップ方法を蚘茉しおみたした。

libGDXはAndroidアプリであっおもデスクトップ䞭心で開発でき、 コヌドの殆どを共有できるのがすごくお嬉しくおお気に入りです。

願わくばもっずもっずlibGDXナヌザヌが増えたすように

]]>
Sun, 18 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/17/spring_boot_jsr330.html http://backpaper0.github.io/2015/01/17/spring_boot_jsr330.html <![CDATA[Spring Bootのサンプルで䜿っおるアノテヌションをJSR 330のものにした]]> Spring Bootのサンプルで䜿っおるアノテヌションをJSR 330のものにした

最近Spring Bootで遊んでいたす。

今回はSpringのアノテヌションである @Component ず @Autowired をJSR 330のアノテヌションである @Named ず @Inject に倉曎しおみたした。

゜ヌスコヌドは https://github.com/backpaper0/spring_boot_sample です。

tagは https://github.com/backpaper0/spring_boot_sample/releases/tag/jsr330 です。

本題

特に曞くこずない。 普通に眮き換えたら普通に動いたので。

ただしスコヌプのアノテヌションはSpringのたたです。 セッションスコヌプのクラスに付けたアノテヌションを @SessionScoped に倉曎したかったのですがJSR 330ではなくCDIのアノテヌションのためどうしようもなかったずいうかなんずいうか。

たあいいか。

たずめ

JSR 330のアノテヌションの方が芋慣れおいお個人的には良い。

]]>
Sat, 17 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/16/jersey2_15_cdi.html http://backpaper0.github.io/2015/01/16/jersey2_15_cdi.html <![CDATA[Jersey 2.15のCDI統合を詊す]]> Jersey 2.15のCDI統合を詊す

Jersey 2.15でCDIずの統合機胜が倉曎されたようです。

ざっくり読むず、これたではJava EEコンテナ(おいうかGlassFish)ずの統合に泚力しおたけど 2.15からはJava EE環境じゃなくおも統合できたっせずいう感じっぜいです。

詊した

ハロヌワヌルドな、なんの圹にも立たないWeb APIを䜜っお詊しおみたした。

メむンクラスはこんな感じ。

package example;

import java.net.URI;

import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.jboss.weld.environment.se.Weld;

import com.sun.net.httpserver.HttpServer;

public class App {

    public static void main(String[] args) {
        Weld weld = new Weld();
        weld.initialize();
        URI uri = URI.create("http://localhost:8080/");
        ResourceConfig config = new ResourceConfig(HelloResource.class);
        HttpServer server = JdkHttpServerFactory.createHttpServer(uri, config);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            server.stop(0);
            weld.shutdown();
        }));

        System.out.println("http://localhost:8080/hello?name=YourName");
    }
}

ご芧の通りです。 普通にWeldを動かしお、Jerseyを動かしおるだけです。 簡単です。

pom.xmlのdependencyはこんな感じ。

<dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-weld2-se</artifactId>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-cdi1x</artifactId>
</dependency>

所感

私はJava EEは奜きですがJava SEでも簡単に動くようになるのは嬉しいのでこの倉曎は嬉しいです

アホっぜい感想ですが、たあそんな感じでヌ。

]]>
Fri, 16 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/15/spring_boot_gradle.html http://backpaper0.github.io/2015/01/15/spring_boot_gradle.html <![CDATA[Spring BootのサンプルをGradle化した、けども  ]]> Spring BootのサンプルをGradle化した、けども  

最近Spring Bootで遊んでいたす。

今回はMavenでビルドされおいるサンプルをGradle化したした。

゜ヌスコヌドは https://github.com/backpaper0/spring_boot_sample です。

tagは https://github.com/backpaper0/spring_boot_sample/releases/tag/gradle です。

本題

たず、おもむろにgradle initしたした。

gradle init

すでにpom.xmlがあるので䟝存関係ずか色々よろしくやっおくれたbuild.gradleが出力されたした。

apply plugin: 'java'
apply plugin: 'maven'

group = 'sample'
version = '1.0-SNAPSHOT'

description = """spring-boot-sample"""

sourceCompatibility = 1.8
targetCompatibility = 1.8



repositories {

     maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
    compile group: 'org.twitter4j', name: 'twitter4j-core', version:'4.0.2'
    compile(group: 'org.springframework.boot', name: 'spring-boot-starter-jersey', version:'1.2.1.RELEASE') {
exclude(module: 'spring-webmvc')
    }
    compile(group: 'org.glassfish.jersey.ext', name: 'jersey-mvc', version:'2.14') {
exclude(module: 'servlet-api')
    }
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version:'1.2.1.RELEASE'
    testCompile(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version:'1.2.1.RELEASE') {
exclude(module: 'commons-logging')
    }
    testCompile group: 'junit', name: 'junit', version:'4.12'
}

あずはSpring Bootのリファレンスの 10.1.2 Gradle installation を参考にしおちょこちょこっず線集したした。

buildscript {
  repositories {
    jcenter()
    maven { url "http://repo.spring.io/snapshot" }
    maven { url "http://repo.spring.io/milestone" }
  }
  dependencies {
    //ここで拡匵プロパティspringBootVersionは参照できひんの_(:3∠)_
    classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.1.RELEASE")
  }
}

apply plugin: 'java'
apply plugin: 'spring-boot'
apply plugin: 'eclipse'
apply plugin: 'idea'

group = 'sample'
version = '1.0-SNAPSHOT'

sourceCompatibility = 1.8
targetCompatibility = 1.8

ext {
  springBootVersion = '1.2.1.RELEASE'
}

repositories {
  jcenter()
  maven { url "http://repo.spring.io/snapshot" }
  maven { url "http://repo.spring.io/milestone" }
}

dependencies {
  compile 'org.twitter4j:twitter4j-core:4.0.2'
  compile ("org.springframework.boot:spring-boot-starter-jersey:$springBootVersion") {
    exclude(module: 'spring-webmvc')
  }
  compile ('org.glassfish.jersey.ext:jersey-mvc:2.14') {
    exclude(module: 'servlet-api')
  }
  compile "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
  testCompile ("org.springframework.boot:spring-boot-starter-test:$springBootVersion") {
    exclude(module: 'commons-logging')
  }
  testCompile 'junit:junit:4.12'
}

知りたいこず

build.gradleにも曞いたけどbuildscriptのブロック内で拡匵プロパティspringBootVersionを参照できないのでしょうか 詊しに䜿っおみたらビルド倱敗した。。。

教えおくださいお願いしたすお願いしたす他力本願。

早速解決したした

ありがずうございたす

修正しおコミットしたした

たずめ

Gradle化すげえ簡単だった。

]]>
Thu, 15 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/14/spring_boot_jersey.html http://backpaper0.github.io/2015/01/14/spring_boot_jersey.html <![CDATA[Spring BootのサンプルをJAX-RSにしおみた]]> Spring BootのサンプルをJAX-RSにしおみた

先日写経したSpring BootのサンプルがSpring MVCで曞かれおいたのでJAX-RS、 ずいうかJersey MVCにしおみたした。

゜ヌスコヌドは先日ず同じ堎所に眮いおありたす。

tag䜜りたした。

やったこず

たず Spring Bootのドキュメント を参考にしおpom.xmlの線集ずJerseyConfigクラスを䜜成したした。

次に Jerseyのリファレンス を参考にしおTemplateProcessorの実装クラスを䜜成したした。

そしお各ControllerクラスをSpring MVC仕様からJAX-RS仕様に倉曎したした。 詳现曞くのは面倒なのでコミット芋おください。

䟋倖出た

䞀通りコヌドを曞いお、IDEから動かしたら起動時に䟋倖が出たした。

java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:917)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:868)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
    ... 6 common frames omitted
Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.addFilter(Ljava/lang/String;Ljavax/servlet/Filter;)Ljavax/servlet/FilterRegistration$Dynamic;
    at org.springframework.boot.context.embedded.FilterRegistrationBean.onStartup(FilterRegistrationBean.java:250)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.selfInitialize(EmbeddedWebApplicationContext.java:222)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.access$000(EmbeddedWebApplicationContext.java:84)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext$1.onStartup(EmbeddedWebApplicationContext.java:206)
    at org.springframework.boot.context.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:54)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5185)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    ... 6 common frames omitted

なんかサヌブレットAPIが叀いようです。

十䞭八九Jersey関連が持っおきたんだろうな、ず思い぀぀、調査したした。 maven-dependency-plugin の treeゎヌルを䜿えば䟝存関係を䞀芧できたす。 -l オプションでログをファむルに曞き出しお゚ディタで怜玢するのが楜だず思いたす。

mvn -l log.txt dependency:tree -Dscope=test

Mavenを実行するず次のようなログが曞き出されたした。

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-boot-sample 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.9:tree (default-cli) @ spring-boot-sample ---
[INFO] sample:spring-boot-sample:jar:1.0-SNAPSHOT
[INFO] +- org.twitter4j:twitter4j-core:jar:4.0.2:compile
[INFO] +- org.springframework.boot:spring-boot-starter-jersey:jar:1.2.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.2.1.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.2.1.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.2.1.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.2.1.RELEASE:compile
[INFO] |  |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.8:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.8:compile
[INFO] |  |  |  +- org.slf4j:log4j-over-slf4j:jar:1.7.8:compile
[INFO] |  |  |  \- ch.qos.logback:logback-classic:jar:1.1.2:compile
[INFO] |  |  |     \- ch.qos.logback:logback-core:jar:1.1.2:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.14:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.2.1.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.0.15:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.0.15:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:8.0.15:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.0.15:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.4.4:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.4.4:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.4.4:compile
[INFO] |  +- org.hibernate:hibernate-validator:jar:5.1.3.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.0.0:compile
[INFO] |  +- org.springframework:spring-core:jar:4.1.4.RELEASE:compile
[INFO] |  +- org.springframework:spring-web:jar:4.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-aop:jar:4.1.4.RELEASE:compile
[INFO] |  |  |  \- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  |  +- org.springframework:spring-beans:jar:4.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.1.4.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:4.1.4.RELEASE:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-server:jar:2.14:compile
[INFO] |  |  +- org.glassfish.jersey.core:jersey-common:jar:2.14:compile
[INFO] |  |  |  +- org.glassfish.jersey.bundles.repackaged:jersey-guava:jar:2.14:compile
[INFO] |  |  |  \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.1:compile
[INFO] |  |  +- org.glassfish.jersey.core:jersey-client:jar:2.14:compile
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.2:compile
[INFO] |  |  +- org.glassfish.hk2:hk2-api:jar:2.4.0-b06:compile
[INFO] |  |  |  +- org.glassfish.hk2:hk2-utils:jar:2.4.0-b06:compile
[INFO] |  |  |  \- org.glassfish.hk2.external:aopalliance-repackaged:jar:2.4.0-b06:compile
[INFO] |  |  +- org.glassfish.hk2.external:javax.inject:jar:2.4.0-b06:compile
[INFO] |  |  \- org.glassfish.hk2:hk2-locator:jar:2.4.0-b06:compile
[INFO] |  |     \- org.javassist:javassist:jar:3.18.1-GA:compile
[INFO] |  +- org.glassfish.jersey.containers:jersey-container-servlet-core:jar:2.14:compile
[INFO] |  +- org.glassfish.jersey.containers:jersey-container-servlet:jar:2.14:compile
[INFO] |  +- org.glassfish.jersey.ext:jersey-spring3:jar:2.14:compile
[INFO] |  |  +- org.glassfish.hk2:hk2:jar:2.4.0-b06:compile
[INFO] |  |  |  +- org.glassfish.hk2:config-types:jar:2.4.0-b06:compile
[INFO] |  |  |  +- org.glassfish.hk2:core:jar:2.4.0-b06:compile
[INFO] |  |  |  +- org.glassfish.hk2:hk2-config:jar:2.4.0-b06:compile
[INFO] |  |  |  |  +- org.jvnet:tiger-types:jar:1.4:compile
[INFO] |  |  |  |  \- org.glassfish.hk2.external:bean-validator:jar:2.4.0-b06:compile
[INFO] |  |  |  +- org.glassfish.hk2:hk2-runlevel:jar:2.4.0-b06:compile
[INFO] |  |  |  \- org.glassfish.hk2:class-model:jar:2.4.0-b06:compile
[INFO] |  |  |     \- org.glassfish.hk2.external:asm-all-repackaged:jar:2.4.0-b06:compile
[INFO] |  |  \- org.glassfish.hk2:spring-bridge:jar:2.4.0-b06:compile
[INFO] |  \- org.glassfish.jersey.media:jersey-media-json-jackson:jar:2.14:compile
[INFO] |     +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.3.2:compile
[INFO] |     \- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.3.2:compile
[INFO] |        \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.3.2:compile
[INFO] +- org.glassfish.jersey.ext:jersey-mvc:jar:2.14:compile
[INFO] |  +- javax.servlet:servlet-api:jar:2.4:compile
[INFO] |  \- javax.ws.rs:javax.ws.rs-api:jar:2.0.1:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:1.2.1.RELEASE:test
[INFO] |  +- org.mockito:mockito-core:jar:1.10.8:test
[INFO] |  |  \- org.objenesis:objenesis:jar:2.1:test
[INFO] |  +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] |  +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] |  \- org.springframework:spring-test:jar:4.1.4.RELEASE:test
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:1.2.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-web:jar:1.2.1.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-webmvc:jar:4.1.4.RELEASE:compile
[INFO] |  +- org.thymeleaf:thymeleaf-spring4:jar:2.1.4.RELEASE:compile
[INFO] |  |  +- org.thymeleaf:thymeleaf:jar:2.1.4.RELEASE:compile
[INFO] |  |  |  +- ognl:ognl:jar:3.0.8:compile
[INFO] |  |  |  \- org.unbescape:unbescape:jar:1.1.0.RELEASE:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.8:compile
[INFO] |  \- nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:jar:1.2.7:compile
[INFO] \- junit:junit:jar:4.12:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.425 s
[INFO] Finished at: 2015-01-14T23:02:38+09:00
[INFO] Final Memory: 21M/165M
[INFO] ------------------------------------------------------------------------

servlet-apiを怜玢しおヒットした箇所を芋るずやはりjersey-mvcが䟝存しおいたした。

dependency芁玠にexclusion芁玠を远加しおservlet-apiぞの䟝存を陀倖した ずころIDEからも起動できたした。

所感

Spring MVCはMVCず蚀うだけあっおビュヌを持぀アプリケヌションはさくさく䜜れそうな気がしたした。

それに察しおJAX-RSは単玔にJSONを返すずいうようなAPIを䜜るのに特化しおるなヌ、ず改めお思いたした。

たあ、そんな感じで。 おしたい。

]]>
Wed, 14 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2015/01/11/spring_boot.html http://backpaper0.github.io/2015/01/11/spring_boot.html <![CDATA[Spring Bootをやっおみた]]> Spring Bootをやっおみた

しょがちむがSpring Bootのハンズオンのレポヌトを曞いおいた のでそれを参考に手を動かしおみたした。 ブログ通りに写経しおいったら普通に動いたので楜ちんでした。

ただし私の知識がアレで Twitter Application Management のSettingsタブにある “Allow this application to be used to Sign in with Twitter” にチェックを入れる必芁があるっぜいのに気付かなくおそこだけちょっず぀たずいた。 Twitterしおないのバレる

HttpServletRequestずHttpSessionをなくす

さお、出来䞊がったアプリケヌションでは HttpServletRequest ず HttpSession を䜿っおいる箇所があったのでそれらを䜿わないように倉曎したす。

Note

HttpServletRequest ず HttpSession はサヌブレットのAPIでありSpringのAPIではありたせん。 なるべく䜎レベルのAPIを盎接䜿甚しない方がコヌドがシンプルになるし ナニットテストが曞きやすくお嬉しい、ずいうのが個人的な考えです。

たずは HttpServletRequest を消したす。 Twitterの認蚌から戻っおくるずきに oauth_verifier ずいうリク゚ストパラメヌタを受け取っおいる所に䜿われおいたす。 これをTwitterControllerのdoTweetメ゜ッドず同じやり方で受け取るように倉曎したす。

@RequestMapping("accessToken")
public String accessToken(Model model,
        @RequestParam(value = "oauth_verifier", required = true) String verifier)
        throws TwitterException {

次いでHttpSessionを消したす。 認蚌の際に必芁ずなるリク゚ストトヌクンずアクセストヌクンを保持するために HttpSession が䜿甚されおいるようです。 今回はそれらを栌玍するセッションスコヌプのクラスを䜜っおコントロヌラヌにむンゞェクションする方法をずりたす。

たずこれがトヌクンを栌玍するセッションスコヌプのクラス。

package jp.co.bizreach.spring_boot_sample;

import java.io.Serializable;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;

@Component
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS,
        value = WebApplicationContext.SCOPE_SESSION)
public class TwitterAuth implements Serializable {

    private AccessToken accessToken;

    private RequestToken requestToken;

    public AccessToken getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(AccessToken accessToken) {
        this.accessToken = accessToken;
    }

    public RequestToken getRequestToken() {
        return requestToken;
    }

    public void setRequestToken(RequestToken requestToken) {
        this.requestToken = requestToken;
    }
}

TwitterAuthController ず TwitterController には次のようにフィヌルドにむンゞェクションしたす。

@Autowired
private TwitterAuth auth;

あずはこのフィヌルドを䜿っおトヌクンを栌玍したり取り出したりすればオッケヌです。

これでサヌブレットAPIをなくすこずが出来たした

pom.xmlを䜜る

しょがちむのブログより

今回はサンプルアプリを䜜っおくれおいお、基本的にはそれを動かしおみるっお感じだったけど、pomファむルの䜜成のずころからやっおみたかったかも。

䜜成したしょう

サンプルはmvn archetype:generateで空のプロゞェクトを䜜ったあずに pom.xmlを線集しおdependencyを远加したように芋えたす。

適圓なディレクトリでmvn archetype:generateを実行したす。

mvn archetype:generate

するず色んな雛圢が䞀芧でずらヌっず出おくるので䜿いたいものを番号で指定したす。

今回はデフォルトの maven-archetype-quickstart を䜿甚したすので数字は䜕も入力せず次に進みたす。

maven-archetype-quickstart のバヌゞョンを尋ねられたす。 既に最新が遞択されおいるのでここも䜕も入力せず次に進みたす。

ここから groupId、artifactId、version、そしおアプリケヌションの package を尋ねられたす。 適宜入力しおそのたた進むず次のようなログが出お空のプロゞェクトが䜜成されたす。

[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.1
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: /Users/backpaper0/src/temp
[INFO] Parameter: package, Value: app
[INFO] Parameter: groupId, Value: sample
[INFO] Parameter: artifactId, Value: spring-boot-sample
[INFO] Parameter: packageName, Value: app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] project created from Old (1.x) Archetype in dir: /Users/backpaper0/src/temp/spring-boot-sample
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 55.560 s
[INFO] Finished at: 2015-01-12T12:38:58+09:00
[INFO] Final Memory: 14M/95M
[INFO] ------------------------------------------------------------------------

䜜成されたファむルは次のような感じ。

  • ./pom.xml
  • ./src/main/java/app/App.java
  • ./src/test/java/app/AppTest.java

pom.xmlずHello, world!するだけのクラス(App.java)ずassertTrue(true)するだけのテストクラス(AppTest.java)です。

App.java ず AppTest.java は芁らないので消したす。

それからpom.xmlを線集したす。

mvn archetype:generateした盎埌の状態は次のような感じです。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>sample</groupId>
  <artifactId>spring-boot-sample</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-boot-sample</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

これに リファレンスの10.1.1 Maven installation を参考にしお parent芁玠ず dependency芁玠を远加したした。 あず぀いでにJUnitのバヌゞョンを4.12に䞊げたした。 それずmaven-compiler-pluginの蚭定を远加しおJava 8でビルドされるようにしたした。 んでもっお、spring-boot-maven-pluginの蚭定を远加しおスタンドアロンJARを䜜れるようにしたした。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>sample</groupId>
  <artifactId>spring-boot-sample</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-boot-sample</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.1.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.twitter4j</groupId>
      <artifactId>twitter4j-core</artifactId>
      <version>4.0.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>${project.build.sourceEncoding}</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

これで抂ねハンズオンのpom.xmlに近くなったず思いたす。

今埌の予定

リファレンスには 10.1.2 Gradle installation ずいうのがあったのでGradle化しおみたいですね。

それず spring-boot-starter-jersey ずいうのがあるっぜいのでSpring MVCをJAX-RSに眮き換えるずいうのもやっおみたいです。

  やらない雰囲気が挂っおいたすが気にしない方向で

たずめ

ひずのブログを写経しただけっおいう他力本願がひどいブログ初めでした。

今幎もよろしくお願い臎したす。

今日のコヌド

]]>
Sun, 11 Jan 2015 00:00:00 +0900
http://backpaper0.github.io/2014/12/24/glassfish_create_session_id.html http://backpaper0.github.io/2014/12/24/glassfish_create_session_id.html <![CDATA[GlassFishでセッションIDを生成しおるずころ]]> GlassFishでセッションIDを生成しおるずころ

これは GlassFish Advent Calendar 2014 の24日目です。

盞倉わらずの小ネタです。

以前調べたのですが、 GlassFishでのHttpSession実装クラスは org.apache.catalina.session.StandardSession で、 これはTomcatのコヌドを利甚したものですが、 セッションIDの生成凊理は倉曎されおいるようです。

なんやかんや蟿っお行くず com.enterprise.util.uuid.UuidUtil の generateUuid メ゜ッドに行き着きたした。

コヌドを匕甚したす。

//this method can take in the session object
//and insure better uniqueness guarantees
public static String generateUuid(Object obj) {

    //low order time bits
    long presentTime = System.currentTimeMillis();
    int presentTimeLow = (int) presentTime;
    String presentTimeStringLow = formatHexString(presentTimeLow);

    StringBuilder sb = new StringBuilder(50);
    sb.append(presentTimeStringLow);
    //sb.append(":");
    sb.append(getIdentityHashCode(obj));
    //sb.append(":");
    //sb.append(_inetAddr);
    sb.append(addRandomTo(_inetAddr));
    //sb.append(":");
    sb.append(getNextRandomString());
    return sb.toString();
}

ご芧の通り、

  • システム日付
  • セッションオブゞェクトのIdentityハッシュコヌド
  • ロヌカルホストのIPアドレス
  • ランダムな文字列

を繋げたものになっおいたす。

ここから呌び出されおいるメ゜ッドを现かく芋お行くず7文字で切っおたりしおマゞこれでセキュアなん ずか思っおしたったりしたしたが “insure better uniqueness guarantees” ずか曞かれおるし衝突耐性高くお倧䞈倫なんでしょうたぶん。

ちなみに org.apache.catalina.session.StandardSession は org.glassfish.main.web:web-core に、 com.enterprise.util.uuid.UuidUtil は org.glassfish.main.common:common-util に入っおいたす。

ずいうわけであっさりしおいたすが、以䞊。

GlassFishさん、来幎もお䞖話になりたす

]]>
Wed, 24 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/24/syobotsum.html http://backpaper0.github.io/2014/12/24/syobotsum.html <![CDATA[しょが぀む #syobochim]]> しょが぀む #syobochim

これは しょがちむ Advent Calendar 2014 の24日目です。

ずいうツむヌトを芋お軜い気持ちで䜜っおみたしたが蓋を開けるず色んな人が色んな事を曞いおおり、 しょがちむ本圓に良かったねっおいう感じでいっぱいの楜しいアドベントカレンダヌもはや24日目ずなりたした。

「しょが぀む」䜜りたした

さお、今回私はしょがちむをモチヌフにしお「しょが぀む」ずいうゲヌム䜜っおみたした。 ゲヌムのむメヌゞを貌りたす。

../../../_images/syobotsum_screen_shot.png

ルヌルは至っおシンプルです。 画面の䞋の方に芋えおいるハヌト・レッドキング・雪だるたを指で匟くず飛んで行っお着地したす。 制限時間10秒の間に次々ず匟いお高く積み䞊げおください。 雪降るクリスマスの街に積み䞊がった分だけ女子力が手に入りたす。 ずいう、なんかもうこの時点でしょがちむすたん、ず蚀いたくなる感じのコンセプトです。

積むものによっおポむントが異なりたす。

  • ハヌト5ポむント
  • レッドキング2ポむント
  • 雪だるた1ポむント

ハヌトはポむント皌げたすが萜䞋速床がのんびりしおいたす。

野良apkファむルを甚意したした。 良ければ遊んでみおください。

゜ヌスコヌドはこちら。

gradlew android:build したらapkをビルドできたす。

ちなみに実機で確認しおいたせん(

ゲヌムを䜜っおみお

すごく簡単なゲヌムですがゲヌム䜜り初心者には難しい郚分もありたした。

しかし技術的な難しさよりもゲヌムシステムのアむデアが出なかったり絵の準備に手間取っおしたいたした。

アドベントカレンダヌのネタを考えおいたずきに「しょが぀む」ずいう蚀葉が先に浮かんだので䜕かを積むものにしようずは思っおいたのですが、 ぷよぷよのような萜ちものゲヌムにしようかなヌ、 それずも将棋厩しのようなものも積むずいう基本コンセプトからは逞脱しないかなヌ、 など悩みたした。

悩みはしたしたがなんせ普段はWebアプリでCRUDの亜皮みたいなのばっか䜜っおる身ずしおは凝った事をやるずしぬず思い、 シンプルなルヌルになるよう考えた末に前蚘のようなものになりたした。

コヌディングも普段やっおる事ずは異なりたしたがなるべく高レベルAPIを利甚する事で なんずか圢に出来たした。

TODO

ずりあえず動きたすが未完成です。 次にTODOを蚘茉したす。

  • SEずBGMを付けたい
  • ヘルプを組蟌みたい。ブログに操䜜方法曞くずかアレ
  • フェヌドアりト時、各パヌツの枠のちら぀きをなんずかしたい
  • 画像のロヌドを非同期にしたい
  • 結果画面がおずなしいからもっずわちゃわちゃさせたい
  • ゜ヌスコヌドにコメントほがないの、たぶん埌で困るから芚えおるうちに曞いおおきたい

特にBGMはせっかくなので䜜曲したいず考えおいたしたがそんな時間はなかったたがお

そもそもパ゜コンで曲䜜るのっおどうしたら良いですかね 教えおえろいひず他力本願

技術的な話

「しょが぀む」はlibGDXで開発をしたした。

libGDXはJavaで曞かれたゲヌムフレヌムワヌクで、ささヌっずコヌドを曞くずそのコヌドをデスクトップアプリ、Androidアプリ、iOSアプリなどにビルド出来るスゎいや぀です。

私はAndroidスマホ持っおいないしiOS開発者ラむセンスも持っおいないのでプラむベヌトでスマホアプリ開発はしないのですが、 libGDXであればJava SEで曞いおデスクトップで動かせるので私のような者であっおもスマホアプリ開発が出来おしたいたした。

libGDXの事を詳しく知りたい方は GitHubにあるlibGDXのWiki を読むか「libGDX しんさん」でググるず良いでしょう。

たずめ

  • ゲヌム䜜るの難しい
  • libGDXすごく良い

明日のアドベントカレンダヌは

しょがちむの番でフィナヌレ ですね

]]>
Wed, 24 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/15/jersey_optional.html http://backpaper0.github.io/2014/12/15/jersey_optional.html <![CDATA[Jersey 2.14でパラメヌタの受け取りにOptionalが䜿えるようになった]]> Jersey 2.14でパラメヌタの受け取りにOptionalが䜿えるようになった

Jersey 2.14がリリヌスされたようです

で、泚目は [JERSEY-2612] です。 この察応のおかげで@QueryParamなどのパラメヌタをOptionalで定矩する事が可胜になりたす。 ただしParamConverterを曞く必芁はありたすが。

ParamConverterっおなんやねんっお方は JAX-RSでパラメヌタの受け取り方をいろいろ詊す の埌半を読んでくださいたせヌ。

リク゚ストパラメヌタをOptionalで受け取るコヌド䟋

適圓ですがサクッちょずサンプル曞きたした。

リ゜ヌスクラスをこちらにも掲茉したす。 ちょヌ簡単な䟋ですが、こんな感じでリ゜ヌスメ゜ッドの匕数にOptionalを䜿えるようになりたす。

package example;

import java.util.Optional;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("hello")
public class HelloWorld {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String say(@QueryParam("name") Optional<String> name) {
        return "Hello, " + name.orElse("world") + "!";
    }
}

泚意点ずしおは先ほども曞きたしたがParamConverter実装クラスずParamConverterProvider実装クラスも 自前で準備しなくおはならない事です。 たあ、䞀床曞いたら䜿い回せるはずなのでサクッず曞いおおきたしょヌ。

今たでこれが出来なかった理由

@QueryParamなどで泚釈された匕数ぞ枡される倀はSingleValueExtractorのextractメ゜ッドを 通るんですが、Jersey 2.13たでのextractメ゜ッドは「倀がnullでなければParamConverterなどで倉換、 nullなら@DefaultValueで蚭定された倀を返す」ずいう感じの実装になっおいたした。

その郚分を抜粋したす。

@Override
public T extract(MultivaluedMap<String, String> parameters) {
    String v = parameters.getFirst(getName());
    if (v != null) {
        try {
            return fromString(v);
        } catch (WebApplicationException ex) {
            throw ex;
        } catch (ProcessingException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ExtractorException(ex);
        }
    } else {
        return defaultValue();
    }
}

このロゞックが原因でOptionalのParamConverterを曞いおもnullが枡っおくるアレっぷりでした。

しかしこのextractメ゜ッドはJersey 2.14で次のように修正されたした。

@Override
public T extract(MultivaluedMap<String, String> parameters) {
    String v = parameters.getFirst(getName());
    try {
        return fromString((v == null && isDefaultValueRegistered()) ? getDefaultValueString() : v);
    } catch (WebApplicationException ex) {
        throw ex;
    } catch (ProcessingException ex) {
        throw ex;
    } catch (IllegalArgumentException ex) {
        return defaultValue();
    } catch (Exception ex) {
        throw new ExtractorException(ex);
    }
}

ご芧の通り「倀がnullか぀デフォルト倀が蚭定されおいればデフォルト倀を、 そうでなければ倀をParamConverterなどに枡す」ずいう颚になっおいたす。

これで倀がnullの堎合でもParamConverterを通るようになり、Optionalぞの倉換が可胜になりたした。

たずめ

  • Jerseyでリク゚ストパラメヌタなどの受け取りにOptional䜿えるようになっお嬉しい
  • ハむテンションでブログ曞いたら文章やばい

そんな感じでヌ

]]>
Mon, 15 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/14/kotlin_static_method.html http://backpaper0.github.io/2014/12/14/kotlin_static_method.html <![CDATA[Kotlinでstaticメ゜ッドが定矩できるようになったのでJAX-RSリベンゞ]]> Kotlinでstaticメ゜ッドが定矩できるようになったのでJAX-RSリベンゞ

こずりん〜(挚拶)

これは Kotlin Advent Calendar 2014 の14日目です。

倏の終わりに 関西Kotlin勉匷䌚 を開催し、私はKotlinでJAX-RSをやるずいう発衚をしたした。 JAX-RSにいく぀かあるリク゚ストパラメヌタの受け取りかたのうち 「Stringの匕数をひず぀だけ受け取る”valueOf”ずいう名前のstaticファクトリメ゜ッドを持぀クラス」 が実珟できたせんでした。 そのずきのKotlinのバヌゞョン(M7)ではstaticメ゜ッドが定矩できなかったからです。

しかしバヌゞョンM9からplatformStaticアノテヌションを䜿甚しおstaticメ゜ッドを定矩できるようになったようです。

ずいうわけでリベンゞしたした。 次のような感じで曞けたす。

package app

import kotlin.platform.platformStatic

public class ValueObj private (val value: String) {
  class object {
    platformStatic fun valueOf(value: String) = ValueObj(value)
  }
}

Kotlinの思想がどうあれJava蚀語、たたは既存のJavaラむブラリずの共存を考慮するずstaticメ゜ッドの 定矩は必芁だろうなヌず思っおいたのでこの機胜远加は良いず思いたす。

個人的にはstaticファクトリメ゜ッドを持぀バリュヌオブゞェクトを倚甚するので倧倉助かりたす。

おしたい。

今日のコヌド

]]>
Sun, 14 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/07/tinkerer_hatena_star.html http://backpaper0.github.io/2014/12/07/tinkerer_hatena_star.html <![CDATA[Tinkererにはおなスタヌを蚭眮した]]> Tinkererにはおなスタヌを蚭眮した

Tinkerer で曞いおるこのブログに はおなスタヌ を蚭眮したのでその蟺たずめおおきたす。 なお、私は modern5 をベヌスにカスタマむズしたテヌマを䜿甚しおいたすので別のテヌマだず倚少異なるかも知れたせん。

たずはおなスタヌのマむペヌゞでブログを登録したす。 マむペヌゞのURLは http://s.hatena.ne.jp/<自分のID> です。

次に _templates/page.html のextraheadブロック( {%- block extrahead -%} ず {%- endblock -%} に囲たれたずころ)に次のJavaScriptコヌドを曞きたす。

<script type="text/javascript">
   Hatena.Star.Token = <自分のトヌクン>;
   Hatena.Star.SiteConfig = {
     entryNodes: {
       'div.main-container': {
         uri: 'window.location',
         title: 'document.title',
         container: 'span.hatenastar'
       }
     }
   };
</script>

<自分のトヌクン> にはマむペヌゞでブログを远加したあずに衚瀺されるトヌクンを曞いおください。

最埌に実際にはおなスタヌを蚭眮する堎所ずなる芁玠を远加したす。 私ぱントリのいっちゃん䞋に眮きたかったのでbodyブロックの最埌の方に次のspan芁玠を曞きたした。

<span class="hatenastar"> </span>

自分のTinkererちからが䜎すぎお悩んだりもしたけれど、出来おしたえば簡単でした

より詳しくは http://d.hatena.ne.jp/hatenastar/20070707 を参照くださいですじゃ。

]]>
Sun, 07 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/07/glassfish_asadmin.html http://backpaper0.github.io/2014/12/07/glassfish_asadmin.html <![CDATA[よく䜿うasadminのコマンドを玹介する]]> よく䜿うasadminのコマンドを玹介する

これは GlassFish Advent Calendar 2014 の7日目です。

小ネタです。 私がよく䜿うasadminのコマンドを、匕数も曞いお実際に䜿っおいる感じを出し぀぀玹介したす。

asadmin list-commands
どんなコマンドあったっけなヌ、っおずきどき確認したす。
asadmin list-domain
GlassFishはドメむンずいう単䜍で管理したすが、このコマンドで今あるドメむンを確認したす。
asadmin delete-domain domain1
芁らんドメむンを消したす。 ドメむンは glassfish/domains/ 以䞋に䜜成されたすが、ここを心を蟌めお手動で消しおも倧䞈倫っぜいです。
asadmin create-domain --portbase=9000 domain1
ドメむンを䜜りたす。 portbaseを指定すればHTTPは9080、管理は9048ずいう颚に良い感じにポヌトを蚭定しおくれたす。
asadmin start-domain domain1
ドメむンを起動したす。 埌述するcreate-jdbc-connection-poolコマンドなど䞀郚のコマンドはドメむンが起動しおいないず実行できなかったりしたす。
asadmin stop-domain domain1
起動しおいるドメむンを停止したす。
asadmin create-jdbc-connection-pool --datasourceclassname org.h2.jdbcx.JdbcDataSource --restype javax.sql.DataSource --property url=jdbc\\:h2\\:sampleDB:user=sa:password=secret samplePool
JDBCコネクションプヌルを䜜りたす。 propertyにURLを曞く堎合、コロンを゚スケヌプしないずいけないので気を぀けたしょヌ。 䞀番最埌の匕数(この䟋でいうずsamplePool)がコネクションプヌルIDです。 なお、JDBCドラむバは glassfish/domains/domain1/lib/ext/ (domain1はドメむンの名前なので適宜眮き換えおください)に眮きたす。
asadmin create-jdbc-resource --connectionpoolid samplePool jdbc/sample
JDBCリ゜ヌスを䜜りたす。 アプリケヌションからはここで蚭定したJNDI名(この䟋でいうずjdbc/sample)で参照したす。 ひず぀のJDBCコネクションプヌルに察しお耇数のJDBCリ゜ヌスを䜜るこずもできたす。
asadmin create-jvm-options -Xmx1024m
JVMオプションを蚭定したす。 この䟋では最倧メモリサむズを蚭定しおいたす。 このコマンドで蚭定したJVMオプションはドメむンを再起動したずきに反映されたす。
asadmin set-log-levels org.seasar.doma=CONFIG
ログレベルを蚭定したす。
asadmin deploy --contextroot=sample --name=sample sample.war
デプロむしたす。
asadmin redeploy --name=sample sample.war
再デプロむしたす。 デプロむず再デプロむでコマンドを䜿い分けなきゃダメなのはちょっず面倒です。
asadmin undeploy sample
アンデプロむしたす。 匕数にはデプロむ時に蚭定したnameを指定したす。

ずたあ、よく䜿うのはこんな所でしょうか。 自分が思っおいたより少なかったですね。

簡単ですが、以䞊になりたす。 おそた぀さたでした。

]]>
Sun, 07 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/07/application_class.html http://backpaper0.github.io/2014/12/07/application_class.html <![CDATA[どうやっおApplicationサブクラスの名前取っおきおんの]]> どうやっおApplicationサブクラスの名前取っおきおんの

これは JavaFX Advent Calendar 2014 の7日目です。

小ネタです。

JavaFXアプリケヌションのメむンクラスは次のように曞きたすよね。

import javafx.application.Application;
import javafx.stage.Stage;

public class Hoge extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        //略
    }
}

これを初めお芋たずき、launchメ゜ッドにApplicationサブクラスのむンスタンスや Classを枡しおるわけでもないのにむンスタンス化されおstartメ゜ッドが呌ばれるのが キモいなヌ、ず思ったのでした。

で、だいたい予想は぀きたしたが、Application.javaを読んでみたした。 その郚分を匕甚したす。

// Figure out the right class to call
StackTraceElement[] cause = Thread.currentThread().getStackTrace();

boolean foundThisMethod = false;
String callingClassName = null;
for (StackTraceElement se : cause) {
    // Skip entries until we get to the entry for this class
    String className = se.getClassName();
    String methodName = se.getMethodName();
    if (foundThisMethod) {
        callingClassName = className;
        break;
    } else if (Application.class.getName().equals(className)
            && "launch".equals(methodName)) {

        foundThisMethod = true;
    }
}

ずいう感じで、スタックトレヌスを取埗しお珟圚のメ゜ッド(launch)のひず぀前の メ゜ッド名(main)ずクラス名(Hoge)を取埗しおいたした。

予想通り割ずキモい方法でクラス名を取っおきおいたこずが分かっお満足です。

JavaFXである必芁性の薄い内容でしたが、以䞊になりたす。 おそた぀さたでした。

]]>
Sun, 07 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/04/validation.html http://backpaper0.github.io/2014/12/04/validation.html <![CDATA[BeanValidationの盞関バリデヌションずそもそもの話]]> BeanValidationの盞関バリデヌションずそもそもの話

BeanValidationで盞関バリデヌションするずきに新しいメ゜ッド䜜っお@AssertTrueを䜿うよ っおいう話があったので、それに぀いお思う事を曞きたす。

なお、以䞋はWebアプリケヌションでリク゚ストパラメヌタをPOJOにマッピングしお BeanValidationを行うずいう流れを想定しおいたす。

@AssertTrueでバリデヌション

件の盞関バリデヌションはたぶんこんな感じです。

public int from;

public int to;

@AssertTrue
public boolean isFromLessThanTo() {
    return from < to;
}

私は、これは

  • メ゜ッド内にバリデヌションロゞックを曞くので再利甚性が䜎い
  • @AssertTrue、そしおbooleanは宣蚀的ではない

ず思っおいたす。

じゃあ、どうすればいいのか

from < to を怜蚌するアノテヌションずカスタムバリデヌタを䜜りたしょう。 そしおそれを付けるメ゜ッドはbooleanではなくタプル(のような䜕か)を返したす。

public int from;

public int to;

@FromLessThanTo
public Pair isFromLessThanTo() {
    return new Pair(from, to);
}

こうする事で、

  • バリデヌションのロゞックはカスタムバリデヌタに閉じ蟌めたので再利甚性高たる
  • アノテヌションで倧小関係があるっお分かっお宣蚀的っぜい

ずなるかず。

そもそも

アノテヌションを䜿ったバリデヌションっおどうなんでしょうね

䟋えば、次のようなコヌドがあったずしたす。

@Isbn
public String isbn1;

@Isbn
public String isbn2;

アノテヌションを芋ればisbn1もisbn2もISBNであるずいうこずは分かるのですが、 でもそれっおアノテヌションの圹割じゃなくお型じゃないのず思うのです。

本来あるべき姿はこんな感じ。

public Isbn isbn1;

public Isbn isbn2;

この堎合バリデヌションはIsbn型ぞ倉換するずきに行うのが良いず思われたす。

型よ

基本的にバリデヌションは次の順番で行われるず思いたす。

  • 必須バリデヌション
  • フォヌマットバリデヌション(日付ずされる倀がyyyy/MM/ddになっおいるかみたいなこずです)
  • 盞関バリデヌション

必須バリデヌションを行うか吊かも型で衚したい。 Optionalでないものは必須ずいう感じです。 たぶんそれが良いず思う。

//必須
public Isbn isbn1;

//必須でない
public Optional<Isbn> isbn2;

フォヌマットも先述の通り型で衚す事ができたす。

それから盞関バリデヌションですが、最初の䟋であればRangeずいった型を䜜っおそこにfromずtoを 詰め蟌めばfromずtoの倧小関係を型で衚す事ができたす。

new Range(from, to);

たずめ

たずたりたせん もっず理想的なバリデヌションフレヌムワヌクが欲しい

ずいうわけでバリデヌションぞの悩みは尜きたせん。 悩たしい。

]]>
Thu, 04 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/01/javaee_advent_calendar_2014.html http://backpaper0.github.io/2014/12/01/javaee_advent_calendar_2014.html <![CDATA[JAX-RSを始める #javaee]]> JAX-RSを始める #javaee

これは Java EE Advent Calendar 2014 の1日目です。

今回は参照実装である Jersey を䜿っおJAX-RSを始めるための環境構築などをだらだら曞こうず思いたす。

ビルドツヌル

昚今はGradleが人気のような雰囲気挂っおいたすが、 Maven を䜿いたしょう。

JerseyはMavenのprofileずいう機胜を䜿っおいおGradleではその蟺のサポヌトがないっぜいのでたぶんしんどいです。

  ず曞きたしたが最近のGradleはprofile察応しおるようです。

ずいうわけでサンプルにGradleのビルドファむルも远加したした。

Mavenのむンストヌルはバむナリを任意の堎所にダりンロヌドしお bin ディレクトリにパスを通せばおkです。

ビルドファむルの準備

Mavenの堎合

たず、 mvn archetype:generate しおください。 それから出来たpom.xmlを線集したす。

次のdependencyManagement芁玠を远加しおください。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.glassfish.jersey</groupId>
      <artifactId>jersey-bom</artifactId>
      <version>2.13</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

それからjersey-bomのpom.xmlを芋ながら奜きなものを遞んでdependency芁玠に远加したす。 ずはいえJerseyはサヌバ偎のAPI、クラむアント偎のAPI、MVC拡匵など倚数のJARに別れお提䟛されおいるので 䜕を远加すれば良いのか最初は分からないず思いたす。

今回はサヌバ偎のコヌドを曞きたいので、 jersey-server を远加したす。 たた、Jerseyは Grizzly や Jetty などのコンテナ䞊で動きたすが、今回は JDK付属のHttpServer で動かしたいので jersey-container-jdk-http を远加したす。 どんなコンテナが䜿えるかは http://repo1.maven.org/maven2/org/glassfish/jersey/containers/ を参照ください。 最埌にJUnitでサクッず走らせおテストするため jersey-test-framework-provider-jdk-http を远加したす。

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
  </dependency>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-jdk-http</artifactId>
  </dependency>
  <dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-jdk-http</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

ずたあ、こんな感じで良いでしょう。

でもこんなこずチンタラやっおられないず思うので https://github.com/backpaper0/sandbox をcloneしお jersey-blank ディレクトリ内の pom.xml をご利甚ください。 私も倧抵、自分が過去に曞いたビルドファむルをコピりたす。

Gradleの堎合

こんな感じ

dependencies {
    compile 'org.glassfish.jersey.core:jersey-server:2.13'
    compile 'org.glassfish.jersey.containers:jersey-container-jdk-http:2.13'
    testCompile 'org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-jdk-http:2.13'
}

コヌドを曞く

たあ、この蟺は適圓に、足し算する簡単なや぀で。

src/main/java/app/Calc.java を䜜りたす。

package app;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("calc")
public class Calc {

    @Path("add")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public int add(@QueryParam("a") int a, @QueryParam("b") int b) {
        return a + b;
    }
}

で、JUnitテストです。 src/test/java/app/CalcTest.java を䜜りたす。

package app;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import javax.ws.rs.core.Application;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

public class CalcTest extends JerseyTest {

    @Test
    public void test() throws Exception {
        int c = target("calc/add").queryParam("a", 2)
                                  .queryParam("b", 3)
                                  .request()
                                  .get(int.class);
        assertThat(c, is(5));
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(Calc.class);
    }
}

test-frameworkを䜿うずずおも簡単にJUnitテストを曞ける事が分かるず思いたす。

テスト走らせる

IDEから実行するかMavenで。

mvn test

簡単ですね

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running app.CalcTest
11 30, 2014 10:55:12 午埌 org.glassfish.jersey.test.jdkhttp.JdkHttpServerTestContainerFactory$JdkHttpServerTestContainer <init>
情報: Creating JdkHttpServerTestContainer configured at the base URI http://localhost:9998/
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.109 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

mainメ゜ッドでサヌバヌを立おる

JUnitテストを走らせおいる事からもお分かり頂けるず思いたすが、 簡単にサヌバヌを立おる事もできたす。

こんな感じ。

package app;

import java.io.IOException;
import java.net.URI;

import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

import com.sun.net.httpserver.HttpServer;

public class Server {

    public static void main(String[] args) throws IOException {
        URI uri = URI.create("http://localhost:8080/rest/");

        ResourceConfig rc = new ResourceConfig();
        rc.register(Calc.class);

        HttpServer httpServer = JdkHttpServerFactory.createHttpServer(uri, rc);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> httpServer.stop(0)));

        System.out.println("JAX-RS started");
    }
}

アプリケヌションサヌバにデプロむする

GlassFishにデプロむする堎合はdependencyのscopeをprovidedにしおWARファむルを䜜っおそれをデプロむすれば良いず思いたす。

Tomcatにデプロむする堎合は jersey-container-jdk-http を消しお、 jersey-container-servlet を远加しおWARファむルを䜜りたしょう。 こんな感じです。

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
  </dependency>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <scope>runtime</scope>
  </dependency>
</dependencies>

私はServlet APIに䟝存しないよう䜜る方がポヌタビリティが高そうで奜きなのでscopeをruntimeにしおいたす。 Servlet APIじゃんじゃん䜿いたい堎合はscopeをcompileにしおください。

たずめ

ずいうわけでJerseyを䜿甚したJAX-RSの導入郚分、劂䜕でしたでしょうか 簡単ですよね 特にJava EEの䞀郚なのにアプリケヌションサヌバがなくおも簡単に䜿えるのが良いですよねね

最埌に、手前味噌ですがJAX-RSの参考資料を挙げおおきたす。

はヌ、これらの資料もJAX-RS 2.0にアップデヌトしないずいけないなヌしろめ

簡単ですが、以䞊。

]]>
Mon, 01 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/01/syobochim_advent_calendar_2014.html http://backpaper0.github.io/2014/12/01/syobochim_advent_calendar_2014.html <![CDATA[Tinkererのしょがちむテヌマ䜜った #syobochim]]> Tinkererのしょがちむテヌマ䜜った #syobochim

これは しょがちむ Advent Calendar 2014 の1日目です。

しょがちむ ずは、

そんな若手゚ンゞニアです。

このアドベントカレンダヌではみんなで毎日しょがちむに関する䜕かを曞こうずいうもので、 䜜った圓初は党日皋埋たるか本人も心配しおいたしたが割ず早々に埋たったので良かったね、っおいう。

Java EE アドベントカレンダヌよりも早く埋たったのは少々耇雑でありたすが いや、でも、埋たっお良かったね

本題

さお、今回はこのブログの基盀ずなっおいるブログツヌル、 Tinkerer のカスタムテヌマを䜜っおみたした。 ず蚀っおもれロから䜜るようなセンスは皆無なので、組蟌みの modern5 ずいうテヌマをコピヌしお りルトラ怪獣ずしょがちむカラヌを混ぜ蟌んでみたした。

今埌、もずのテヌマに戻した堎合を考慮しおスクリヌンショット貌っおおきたす。

../../../_images/syobochim-theme.png

ヘッダ、本文、サむドバヌなどの構成や基本的なカラヌリングは modern5 のたたですが、 ヘッダの背景色ずリンクの色を倉えおしょがちむカラヌにし、ヘッダの背景画像ずセクションの芋出しに りルトラ怪獣の絵をはめ蟌みたした。 䜙談ですが、私はバルタン星人が奜きです(V)o\o(V)フォフォフォ。

あず、ブログタむトルをしょがちむのブログっぜくするためbefore疑䌌芁玠、after疑䌌芁玠で文章を足しおいたす。 念のため曞いおおきたすが、このブログのタむトルは「裏玙」です。

  ずいった所で、残念ながらだいぶ力尜きたした。 己のHTMLちから䞍足、CSSちから䞍足、Tinkererちから䞍足などに凹みたした。

たあやり過ぎるよりは良いかヌ、ず蚀う感じでどうかひず぀ このずおりだ

たずめ

ここたで”しょがちむカラヌ”の説明なし

おたけ

セクションの芋出しの前に出しおるレッドキングがちょっずかわいく描けた気がするので もうちょい倧きいサむズも眮いおおきたす。

../../../_images/redking.png
]]>
Mon, 01 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/12/01/irof_advent_calendar_2014.html http://backpaper0.github.io/2014/12/01/irof_advent_calendar_2014.html <![CDATA[スタックトレヌスろふ #irof]]> スタックトレヌスろふ #irof

これは いろふ Advent Calendar 2014 の1日目です。

いろふアドベントカレンダヌずは、我らが いろふさん ぞの愛をワヌルドワむドなむンタヌネッツに倧公開する感じのや぀です。

いろふさんをご存じない方はTwitterでをキメお、著曞である逊成読本を熟読するず良いですよ

本線ずいう名の出オチ

こちらのリポゞトリをcloneしお、

irofディレクトリに移動し gradlew run しおください。

するずこうなりたす。

../../../_images/stacktracerof.png

なんずいろふさんが䟋倖吐いお終了したした (-∧-) 

投げっぱなしの解説

Java蚀語ではメ゜ッド名に空癜や蚘号を䜿えたせんがクラスファむルずJVM的にはもうちょい制玄緩いっぜいので その蟺を利甚しおスタックトレヌスでいろふさんを描きたした。

いろふさんのアむコンからAAを䜜ったのは次のサヌビスです。

で、クラスファむルを曞き出したのはASMずいうラむブラリです。

ASMの ClassWriter ず GeneratorAdapter を䜿えば割ず簡単にクラスファむルを曞き出す事ができたす。 詳しくはGeneratorAdapterのJavadocず今回のいろふ゜ヌスコヌドを参照ください。

それず今回は䜿っおいたせんが ClassReader を䜿うずクラスファむルを読む事ができたす。

䟋えばむンスタンスメ゜ッドを実行しおるコヌドを芋぀けお暙準出力に曞き出すようなアレは次のように曞けたす。

ClassReader reader = new ClassReader("irof.Irof");

MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM5) {

    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
        if (opcode == Opcodes.INVOKEVIRTUAL) {
            System.out.printf("owner=%1$s name=%2$s desc=%3$s%n", owner, name, desc);
        }
    }
};

ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5) {

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        return methodVisitor;
    }
};

reader.accept(classVisitor, 0);

ちなみにASMはJDKにも入っおいたす。 rt.jar の com.sun.xml.internal.ws.org.objectweb.asm 以䞋がそうですね。 JAX-WSに䜿われおいるようです。

あず jersey-server にも䜿われおいたす。 jersey.repackaged.org.objectweb.asm 以䞋がそうです。

たずめ

いざやっおみるずすんなり出来ちゃっお倉態床が䜎すぎおアレですが、たあいいか。

]]>
Mon, 01 Dec 2014 00:00:00 +0900
http://backpaper0.github.io/2014/11/12/java_engineer_training_book.html http://backpaper0.github.io/2014/11/12/java_engineer_training_book.html <![CDATA[「Java゚ンゞニア逊成読本」読んだ]]> 「Java゚ンゞニア逊成読本」読んだ

献本しお頂きたした。 私を掚薊しおくれたのざきひろふみさん、ありがずうございたす

この本は経隓の浅いJava゚ンゞニアがふ぀うのJava゚ンゞニアになるために必芁な技術的な知識 (ず技術以倖の知識) を䞀床に取り入れる事ができるような内容になっおいたす。

「特集1」ではJava入門ずいう事で誰もが通る道に぀いお解説されおいたす。 ただしよくある入門曞のように制埡文やintの取りうる範囲、挔算子の優先順䜍などをちたちた解説したりはしたせん。

その代わりJava蚀語の芁であるクラスに぀いお2章をたるごず䜿っお解説しおいたす。 トップレベルのクラス、むンナヌクラス、staticなネストしたクラス、匿名クラスの違いを説明できたすか この本を読めば説明できるようになりたす。

たた、䟋倖の扱いかたに぀いおも実践的な芖点で曞かれおいたす。 しっかり読んで e.printStackTrace() から卒業したしょう。

「特集2」ではラムダ匏ずStream APIに぀いおコンパクトながらも分かりやすく解説しおいたす。 文法や䜿い方だけでなくラムダ匏がなぜ必芁になったのかもよく分かりたす。

「特集3」はJava EEです。 広倧なJava EEの仕様矀からServlet、JSF、JAX-RS、JPA、CDI、EJBをピックアップしお解説しおいたす。 Java EEの䞻芁技術の雰囲気を掎めるのではないでしょうか。

「特集4」ではJavaの技術ではなくチヌム開発に必芁な知識ずしお Git、Maven、JUnit、Jenkinsに぀いおそれらが必芁ずなる背景や導入方法、 䜿甚䞊の泚意点などが解説されおいたす。 もはやEclipseでWAR䜜っおるなどず蚀う珟堎はないず思いたすが、 これら(あるいはこれらに類する他のツヌル)を導入しおいない堎合はこの特集が圹立぀でしょう。

ペヌゞは前埌したすが、「巻頭蚘事」ではJavaの歎史ずJavaにた぀わる(しょヌもない)ネタを解説しおいたす。 これを䞀読しおおくずTwitterをより楜しめるようになりたすたぶん。

そしお䞀番埌ろに蚘茉されおいる「䞀般蚘事」は少々趣が倉わり、 受蚗開発の珟堎で必芁ずなるスキルが簡朔にたずめられおいたす。 Excelにスクリヌンショットを貌付けるずいった (Žω)  ずなるスキルにも觊れおいたすが、 Java以倖にもこういうスキルが必芁なんだなず理解できる内容になっおいたす。

现かい感想・気になった点など

ずいうわけで现かい郚分を挙げおいきたす。

  • 29ペヌゞ。

    通垞の業務システムを開発する䞭でアノテヌションを䜜成するこずは少ないので”

    CDIずいうものがあっおだなry

  • 30ペヌゞ。

    むンナヌクラスに名前付き定数を持おるの知らなかった。 勉匷になりたした

  • 34ペヌゞ、リスト19。

    耇数コンストラクタを甚意する堎合、 オプション匕数は埌ろの匕数(ここでいうず b )にする方が䞀般的ず思いたす。

  • 35ペヌゞ。

    䟋倖オブゞェクトには䟋倖が発生した時の状態が詰め蟌たれおたす。

    「状態」よりも「情報」の方がしっくりくるかなヌ。 前章で可倉ず䞍倉に぀いお蚀及しおいるのも盞たっお分かりにくい気がしたした。

  • 38、39ペヌゞ。

    InvocationTargetException は他のリフレクション䟋倖ず意味合いがちょっず違うず思っおいたす。 他のリフレクション䟋倖が「指定されたメ゜ッドを実行できなかった」のに察しお InvocationTargetExceptionは「指定されたメ゜ッドを実行䞭に䟋倖が発生した」ずいう状況です。 それによっおハンドリングが倉わるかどうかはケヌスバむケヌスずは思いたすが。 あずここはマルチキャッチに぀いお曞いおお、たたたたリフレクション䜿っただけなので InvocationTargetExceptionの扱いずか関係無いか。 たあ気になったずいうこずで。

    気になったず蚀えば䟋倖の䞭では InterruptedException の扱いにも泚意が必芁ず思うので 蚀及しおおいたほうが良いのではず䞀瞬思いたしたが、 埌のほうでマルチスレッドはうか぀に觊るなっお曞いおあるしたあいいか。

  • 43ペヌゞ。

    Java 1.7のtry-with-resources構文のために远加された Throwable#addSuppressed(Throwable) も䜿えそうですね。

  • 68ペヌゞ、リスト6。69ペヌゞ。

    Files.lines() をtry-with-resourcesでクロヌズしおるのは流石だず思いたした。 ここはハマりどころになりそうな気がしたすねヌ。

  • 87ペヌゞ、リスト5。

    ボタンの抌䞋時にAjaxで凊理

    “抌䞋”の珟堎感すごい。

  • 95、96ペヌゞ。

    JAXB経由のJSONプロバむダはJAX-RSの暙準仕様ではない(ですよね)から泚意が必芁ですね。

  • 98ペヌゞ、リスト3

    JPAにおけるReadずUpdate。 mergeはupdateではなくお氞続コンテキスト倖の゚ンティティを 氞続コンテキストに突っ蟌む行為ず思いたす。 em.find(clazz, id) した゚ンティティは氞続コンテキストで管理されおいるので mergeする必芁はないですよね   ずか思っおいたら100ペヌゞでmergeの説明があった。

  • 105ペヌゞ。

    モックによっおテスト容易性を高めたり、

    具䜓䟋が欲しい気がしたした。 CDIのalternativeはbeans.xmlを線集しなきゃいけなかったりしお面倒い。 個人的にはCDIを䜿う堎合はナニットテストにはGuiceを䜿うのが楜で良いず思っおいたす。

あず、JVMぞの蚀及が芋圓たらないのが気になりたした。 -Xmx ずか。

Java EEは、範囲が広くお仕様がでかいので仕方ないのですが、 内容が薄めだず感じおしたいたした。 いっそJAX-RSやCDIなどの各仕様の説明はもっずシンプルにしお、 チュヌトリアルを手厚くするずいう手もあったのかもかなヌ、などず無責任に思いたした。

特にServletずEJBの説明はなくおも良かったかも知れたせんね。 すっぎんのサヌブレットは䜿わないしEJBはトランザクション境界が欲しいっおのが殆どず思いたすし。 デカい案件やったこずないので芋圓違いの意芋かもしれたせんが。

たずめ

ずいうわけで、色々ず现かいこずも曞きたしたが総合的には間違い無く良曞だず思っおいたす。 冒頭にも曞きたしたがこの本は経隓の浅いJava゚ンゞニアの皆様ぞオススメです。 この本を読んで孊んで楜しいJavaラむフを送りたしょう

あなたず

(続きははおなブックマヌクのコメントでお願いしたす)

執筆陣のブログ゚ントリ

ただ買っおないひずはキクタロヌさんのブログのアフィリンクから買おう

]]>
Wed, 12 Nov 2014 00:00:00 +0900
http://backpaper0.github.io/2014/11/08/semicolonless_tail_call_optimization.html http://backpaper0.github.io/2014/11/08/semicolonless_tail_call_optimization.html <![CDATA[セミコロンレスJavaで末尟再垰の最適化]]> セミコロンレスJavaで末尟再垰の最適化

前回 はセミコロンレスJavaで再垰ができる事が分かりたした。

ただし再垰しすぎるずスタックオヌバヌフロヌでしにたす。

再垰による 1 + 2 + ... + n を芋おみたしょう。

public class SemicolonlessRecursion {

    public static void main(String[] args) {
        if (java.util.stream.Stream
            .of(Integer.parseInt(args[0]))
            .flatMap(n -> java.util.stream.Stream
            .<F<Integer, Integer>> of((f, m) -> m < 1 ? 0 : m + f.apply(f, m - 1))
            .map(sum -> sum.apply(sum, n)))
            .peek(System.out::println)
            .count() > 0) {
        }
    }

    interface F<P, R> extends java.util.function.BiFunction<F<P, R>, P, R> {}
}

ずっおも分かりやすいコヌドですが n に 10000 皋床を䞎えただけでスタックオヌバヌフロヌになりたす。

この再垰を末尟再垰にしお最適化を行うのが今回の目的です。

普通のJavaで末尟再垰最適化

最初からセミコロンレスJavaで考えおもしんどいだけなので、 たずは普通のJavaで末尟再垰最適化版のコヌドを曞いおみたす。 実装するに圓たっお 「Javaによる関数型プログラミング」 の7章を参考にしたした。

import java.util.Optional;
import java.util.stream.Stream;

public class TailCallOptimization {

    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);

        F sum = (f, p, r) -> p < 1 ? done(r) : call(() -> f.apply(f, p - 1, r + p));

        TailCall t = sum.apply(sum, n, 0);

        Integer result = Stream.iterate(t, TailCall::get)
                               .map(TailCall::result)
                               .filter(Optional::isPresent)
                               .map(Optional::get)
                               .findFirst()
                               .get();

        System.out.println(result);
    }

    interface F {

        TailCall apply(F f, Integer p, Integer r);
    }

    static TailCall call(TailCall t) {
        return t;
    }

    static TailCall done(Integer result) {
        return new TailCall() {

            @Override
            public TailCall get() {
                throw new UnsupportedOperationException();
            }

            @Override
            public Optional<Integer> result() {
                return Optional.of(result);
            }
        };
    }

    interface TailCall {

        TailCall get();

        default Optional<Integer> result() {
            return Optional.empty();
        }
    }
}

倚少セミコロンレスJavaぞの倉換を意識しおいたすが普通のJavaです。 これをセミコロンレスJavaにしおいきたす。

セミコロンレス化の垃石

Java 8時代におけるセミコロンレスJavaの鍵はラムダ匏だず思っおいたす。 倀を返すメ゜ッドの定矩が出来ないセミコロンレスJavaですが、 ラムダ匏を䜿う事でセミコロンレスに関数を定矩する事が可胜です。

//ふた぀のintを足しお返す関数を定矩しお2, 3に適甚する
if (java.util.stream.Stream
    .<java.util.function.BinaryOperator<Integer>> of((a, b) -> a + b)
    .map(add -> add.apply(2, 3))
    .peek(System.out::println)
    .count() > 0) {
}

ラムダ匏を䜿う為に必芁ずなるのは関数型むンタヌフェヌスです。 セミコロンレスJavaではむンタヌフェヌスの定矩は出来たすが、その䞭でメ゜ッド定矩が出来たせん。 ただし、幞いにもJavaの暙準APIには関数型むンタヌフェヌスが豊富に甚意されおいるので それらをextendsするこずで甚途に特化した関数型むンタヌフェヌスを手に入れる事ができたす。

たず TailCall を関数型むンタヌフェヌスにする事から始めたしょう。 ここでの課題は get() ず result() の䞀本化です。 今のたたではどうしおも匿名クラスを導入する必芁がありたす。

TailCall ず Optional<Integer> の Pair を返す Supplier ずするこずで TailCall を関数型むンタヌフェヌスにできたした。

interface TailCall extends Supplier<Pair<TailCall, Optional<Integer>>>{}

これにより done(Integer) が返す倀を匿名クラスではなくラムダ匏で曞けるようになりたした。

static TailCall done(Integer result) {
    return () -> new Pair<>(null, Optional.of(result));
}

たた call(TailCall) は次のように倉曎したす。

static TailCall call(Supplier<TailCall> t) {
    return () -> new Pair<>(t.get(), Optional.empty());
}

こうするこずで関数 sum は次のように曞けたす。

F sum = (f, p, r) -> p < 1 ? done(r) : call(() -> f.apply(f, p - 1, r + p));

それから結果を求める Stream 操䜜ですが、 普通の再垰版では TailCall の get() を呌び出すこずで Stream を構築しおいたしたが get() が Pair<TailCall, Optional<Integer>> を返すようにしたので、 Pair<TailCall, Optional<Integer>> の Stream を構築するようにしたす。

Stream.iterate(new Pair<>(t, Optional.<Integer> empty()),
               p -> p.getKey().get())
      .map(Pair::getValue)
      .filter(Optional::isPresent)
      .map(Optional::get)
      .findFirst()
      .get();

ここたでのコヌド党䜓を次に蚘茉したす。

import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;

import javafx.util.Pair;

public class TailCallOptimization {

    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);

        F sum = (f, p, r) -> p < 1 ? done(r) : call(() -> f.apply(f, p - 1, r + p));

        TailCall t = sum.apply(sum, n, 0);

        Integer result = Stream.iterate(new Pair<>(t, Optional.<Integer> empty()),
                                        p -> p.getKey().get()).map(Pair::getValue)
                               .filter(Optional::isPresent)
                               .map(Optional::get)
                               .findFirst()
                               .get();

        System.out.println(result);
    }

    interface F {

        TailCall apply(F f, Integer p, Integer r);
    }

    static TailCall call(Supplier<TailCall> t) {
        return () -> new Pair<>(t.get(), Optional.empty());
    }

    static TailCall done(Integer result) {
        return () -> new Pair<>(null, Optional.of(result));
    }

    interface TailCall extends Supplier<Pair<TailCall, Optional<Integer>>> {}
}

そしおセミコロンレスぞ  

あずはちょっずず぀たずめたりなんやかんやしおセミコロンレスJavaに倉曎しおいきたす。

ずいうわけでセミコロンレスJavaで末尟再垰最適化を行ったコヌドが次になりたす。

public class SemicolonlessTailCallOptimization {

    public static void main(String[] args) {
        if (java.util.stream.Stream
            .of(Integer.parseInt(args[0]))
            .flatMap(n -> java.util.stream.Stream
            .<F> of((f, pr) -> pr[0] < 1
                ? () -> new javafx.util.Pair<>(null, java.util.Optional.of(pr[1]))
                : () -> new javafx.util.Pair<>(f.apply(f, new int[] { pr[0] - 1, pr[1] + pr[0] }), java.util.Optional.empty()))
            .<TailCall> map(sum -> sum.apply(sum, new int[] { n, 0 })))
            .map(t -> java.util.stream.Stream
            .iterate(new javafx.util.Pair<>(t, java.util.Optional.<Integer> empty()), p -> p.getKey().get())
            .map(javafx.util.Pair::getValue)
            .filter(java.util.Optional::isPresent)
            .map(java.util.Optional::get)
            .findFirst()
            .get())
            .peek(System.out::println)
            .count() > 0) {
        }
    }

    interface F extends java.util.function.BiFunction<F, int[], TailCall> {}

    interface TailCall extends java.util.function.Supplier<javafx.util.Pair<TailCall, java.util.Optional<Integer>>> {}
}

たずめ

セミコロンレスJavaでも末尟再垰の最適化が出来る事が分かりたした。 これによりセミコロンレスJavaがたた䞀歩、実甚的な蚀語ぞず近づいたず思われたす。

なお、今回は javax.util.Pair を䜿甚したしたが、これが倧倉䟿利でした。 特にふた぀の倀を返す堎合に今たでは配列あたりを䜿甚しおいたのでキャストが必須になっおいたしたが、 Pair があればキャストも䞍芁でコヌドがすっきりしたした。 たた、ふた぀以䞊の倀を返す堎合は Pair<T, Pair<U, V>> などずすれば良いですね。

ずいうわけでこれからもセミコロンレスJavaの可胜性を探っお行きたいず思いたす。

]]>
Sat, 08 Nov 2014 00:00:00 +0900
http://backpaper0.github.io/2014/11/03/semicolonless_java_fibonacci_without_z_combinator.html http://backpaper0.github.io/2014/11/03/semicolonless_java_fibonacci_without_z_combinator.html <![CDATA[セミコロンレスJavaでフィボナッチをZコンビネヌタなしで]]> セミコロンレスJavaでフィボナッチをZコンビネヌタなしで

セミコロンレスJavaでフィボナッチ でZコンビネヌタ䜿っお再垰だ(ドダ) ずか曞きたしたがそんなものは必芁なかった。

public class SemicolonlessFibonacci {

    public static void main(String[] args) {
        if (java.util.stream.Stream.<F> of((f, n) -> n <= 1 ? n : f.apply(f, n - 2) + f.apply(f, n - 1))
            .map(f -> f.apply(f, Integer.parseInt(args[0])))
            .peek(System.out::println).count() > 0) {
        }
    }

    interface F extends java.util.function.BiFunction<F, Integer, Integer> {
    }
}

難しく考え過ぎんなっお話ですね_(:3∠)_

]]>
Mon, 03 Nov 2014 00:00:00 +0900
http://backpaper0.github.io/2014/11/02/semicolonless_java_fibonacci.html http://backpaper0.github.io/2014/11/02/semicolonless_java_fibonacci.html <![CDATA[セミコロンレスJavaでフィボナッチ]]> セミコロンレスJavaでフィボナッチ

抂芁ネタでしかない

ある項のフィボナッチ数を曞き出す

結論から行きたしょう。

ある項のフィボナッチ数を曞き出すプログラムですが、こんなコヌドになりたした。 うわ暪に長え。

public class SemicolonlessFibonacci {

    public static void main(String[] args) {
        if (java.util.stream.Stream.<java.util.function.Function<F, F>> of(f -> n -> n <= 1 ? n : f.apply(n - 2) + f.apply(n - 1))
            .map(f -> ((java.util.function.Function<G, F>) (x -> f.apply(y -> x.apply(x).apply(y)))).apply(x -> f.apply(y -> x.apply(x).apply(y))))
            .map(fib -> fib.apply(Integer.parseInt(args[0])))
            .peek(System.out::println).findFirst().orElse(0) == 0) {
        }
    }

    interface F extends java.util.function.Function<Integer, Integer> {}

    interface G extends java.util.function.Function<G, F> {}
}

これを SemicolonlessFibonacci.java ずいう名前で保存しお javac SemicolonlessFibonacci.java でコンパむルし、 java -cp . SemicolonlessFibonacci 10 ずいうふうに実行しおください。

匕数をいろいろ倉えお詊すず暙準出力にフィボナッチ数が曞き出されるこずがお分かり頂けるず思いたす。

やりたかったこず

今回、実珟したかったこずはステヌトレスな再垰です。

セミコロンレスJavaでは戻り倀をも぀メ゜ッドを定矩できない( return にはセミコロンが必須のため ) ずいう制限のためミュヌタブルなオブゞェクトを匕数にしおそれを曎新するこずでメ゜ッドの呌び出し元に倀を戻すしかありたせん。 たぶん。

//戻り倀のあるメ゜ッドはreturnでセミコロン必芁
public int get() {
    return 0;
}

//ミュヌタブルな匕数で倀を戻す
public void set(List<String> holder) {
    if (holder.add("hoge")) {}
}

セミコロンレスJava 8からはラムダ匏を䜿えば戻り倀をも぀凊理を定矩できるようになりたした。

if (Stream.<IntBinaryOperator> of((n, m) -> n + m) //二぀のintを足しお返す関数を定矩
          .map(f -> f.applyAsInt(2, 3))            //関数適甚
          .peek(System.out::println)               //出力
          .findFirst().isPresent()) {
}

ですが、自身を再垰呌び出しするこずはできたせん。

//これはセミコロンJava  おいうかJava
IntUnaryOperator sum = n -> n == 0 ? 0 : n + sum(n - 1);
                                           //~~~ コンパむル゚ラヌ

Zコンビネヌタ

これらの問題を解決するのがZコンビネヌタです。

この蟺は党然詳しくないんですがラムダ蚈算で再垰を行うこずが出来るアレっぜいです。 きしださんの゚ントリも参考にさせお頂きたした。

再垰するにはYコンビネヌタずいうのもあるようですが正栌評䟡戊略の蚀語ではスタックオヌバヌフロヌになるっぜいです。 おいうかなりたした。

ずいうわけでZコンビネヌタです。 その定矩は次の通りです。

Z = λf. (λx. f (λy. x x y)) (λx. f (λy. x x y))

これをJavaで曞くずこんな感じになりたした。

static F z(Function<F, F> f) {
    Function<G, F> a = x -> f.apply(y -> x.apply(x).apply(y));
    G b = x -> f.apply(y -> x.apply(x).apply(y));
    return a.apply(b);
}

interface F extends Function<Integer, Integer> {}

interface G extends Function<G, F> {}

このzメ゜ッドを甚いおフィボナッチ数を求める凊理を再垰で曞いたのが次になりたす。

Function<F, F> g = f -> n -> n <= 1 ? n : f.apply(n - 2) + f.apply(n - 1);
                                        //~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~ この蟺が再垰

F fib = z(g);

System.out.println(fib.apply(11)); //11番目のフィボナッチ数を出力する

あずはセミコロンを消す為になんやかんやいろいろやっお䞀番最初のコヌドになりたした。

たずめ

Java 8時代になりセミコロンレスJavaでも再垰を䜿えるようになりたした。 これによりセミコロンレスJava 8が秘めたる可胜性を曎に感じる事ができたした。

今回は末尟再垰最適化たで考える力は残っおいたせんでしたが、 「Javaによる関数型プログラミング」 の7章を参考にすればなんずかなるかもしれたせん。 ならないかもしれたせん。

みなさんもセミコロンレスJavaをはじめおみたせんか みたせんね。 はい、ごめんなさい。

続き セミコロンレスJavaでフィボナッチをZコンビネヌタなしで

]]>
Sun, 02 Nov 2014 00:00:00 +0900
http://backpaper0.github.io/2014/11/01/prefix_domain.html http://backpaper0.github.io/2014/11/01/prefix_domain.html <![CDATA[前方䞀臎の怜玢条件ずドメむンクラス #doma2]]> 前方䞀臎の怜玢条件ずドメむンクラス #doma2

Doma 2 で前方䞀臎の怜玢条件をドメむンクラスでどう扱うか考えた話です。

銬鹿正盎にドメむンクラスを䜿う

SIerで業務アプリ䜜っおるず怜玢しお結果をグリッド衚瀺する画面ずかよく䜜るず思うんですが、 その際に前方䞀臎の怜玢条件を扱う事も倚いのです。

䟋えば埓業員を怜玢するずきに条件に埓業員番号ず所属郚門番号を䜿えるずしたす。 加えお、どちらも前方䞀臎で怜玢するずしたす。 この怜玢を行うDAOメ゜ッドを䜕も考えずに曞くずこうなりたす。

@Select
List<Emp> select(EmpId empId, DeptId deptId);

ちなみにSQLファむルは雰囲気こんな感じで。

SELECT /*%expand */*
  FROM emp
 WHERE empId LIKE /* empId */'AA%'
   AND deptId LIKE /* deptId */'BB%'

EmpIdは埓業員番号を衚すドメむンクラスです。 怜玢条件は前方䞀臎、぀たり埓業員番号の埌ろが欠けた䞭途半端な状態のものが枡される可胜性がありたす。 そういった項目にEmpIdを䜿甚するのはおかしいのではないでしょうか

Stringを䜿う

そこで怜玢条件を汎甚的な型であるStringに倉曎したす。

@Select
List<Emp> select(String empId, String deptId);

EmpIdの䞍適切な䜿甚はなくなりたしたが、 select(deptId, empId) ずいうふうに匕数の順番を間違えおもコンパむル時に怜出されなくなっおしたいたした。

ドメむンクラスPrefix<DOMAIN>を䜜る

ずいうわけで考えたのがPrefix<DOMAIN>ずいうドメむンクラスです。

次にコヌドを蚘茉したす。

import java.util.Optional;

import org.seasar.doma.Domain;

@Domain(valueType = String.class, factoryMethod = "of")
public class Prefix<DOMAIN> {

    private final String value;

    private Prefix(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public static <T> Prefix<T> of(String value) {
        return Optional.ofNullable(value).map(x -> new Prefix<T>(x)).orElse(null);
    }
}

型パラメヌタDOMAINには他のドメむンクラスをバむンドしたす。

このPrefix<DOMAIN>を䜿甚するずDAOメ゜ッドは次のようになりたす。

@Select
List<Emp> select(Prefix<EmpId> empId, Prefix<DeptId> deptId);

これで、

  • ドメむンクラスに適しない前方䞀臎に䜿甚するような䞭途半端な状態を持おる
  • DAOメ゜ッドの匕数の順を間違えおもコンパむル時に怜出できる

ずいう思いを実珟する事ができたした。 珟時点ではベタヌな手法だず思っおいたす。

これはドメむンクラスをゞェネリックなクラスに出来るが故にずれた手法ですが、 そういった事ができるようになったのは実は私の芁望だったりしたす。

あのずきはこんなこずに䜿えるずは露皋も思っおいたせんでした(・ω<) 

Doma 2良いよ

]]>
Sat, 01 Nov 2014 00:00:00 +0900
http://backpaper0.github.io/2014/11/01/funcitonal_programming_in_java.html http://backpaper0.github.io/2014/11/01/funcitonal_programming_in_java.html <![CDATA[「Javaによる関数型プログラミング」読んだ]]> 「Javaによる関数型プログラミング」読んだ

さくらばさんに献本しお頂きたした。 ありがずうございたす

物理的に薄い本ですし、ラムダ匏ず関数型プログラミングぞの入門ずしお良い本だず思いたす。 チヌムの埌茩に読んで欲しい。

関数型プログラミングぞの入門に䞁床いいずいうこずで、数幎前にコップ本で入門を枈たせおいた私ずしおは少々物足りない気がしたした。 ただし7章は末尟再垰の最適化を行うずいう内容で、そこはJavaコンパむラはサポヌトしおいない郚分なので興味深く読みたした。 恥ずかしながら、末尟再垰の最適化を自分で曞くずいう発想は無かったので参考になりたす。

以䞋、気になった点を挙げたす。 タむポも含む。

  • 2〜3ペヌゞ。宣蚀的なコヌドずはどういうこずかを、 いきなりラムダ匏を登堎させるのではなくJava 7たでの語圙で説明しおいるのが良いですね。

  • 28ペヌゞの䟋2-7。 これメ゜ッド参照になっおいないのでコンパむル゚ラヌですね。

  • 70ペヌゞ。

    JDKの新しい ClosableStream むンタヌフェヌス

    ずありたすが、そのようなクラスはありたせん。

    リリヌス前にはあったようですが be6ca7197e0e あたりで削陀されたした。 ちなみに ClosableStream じゃなくお CloseableStream でした。

  • 89ペヌゞの䟋4-17。 コヌドを匕甚したす。

    try {
      final URL url =
        new URL("http://ichart.finance.yahoo.com/table.csv?s=" + ticker);
    
      final BufferedReader reader =
        new BufferedReader(new InputStreamReader(url.openStream()));
      final String data = reader.lines().skip(1).findFirst().get();
      final String[] dataItems = data.split(",");
      return new BigDecimal(dataItems[dataItems.length - 1]);
    } catch(Exception ex) {
      throw new RuntimeException(ex);
    }
    

    これ、readerがcloseされおいたせん。 readerをtry-with-resourcesで囲むべきず思いたす。

    try {
      final URL url =
        new URL("http://ichart.finance.yahoo.com/table.csv?s=" + ticker);
    
      try(final BufferedReader reader =
          new BufferedReader(new InputStreamReader(url.openStream()))) {
        final String data = reader.lines().skip(1).findFirst().get();
        final String[] dataItems = data.split(",");
        return new BigDecimal(dataItems[dataItems.length - 1]);
      }
    } catch(Exception ex) {
      throw new RuntimeException(ex);
    }
    
  • 130〜135ペヌゞのむンスタンス化の遅延。 面癜いアプロヌチですが最終的に出来䞊がったコヌドは少々分かりにくかったし、synchronizedを䜿っおいたのでConcurrency Utilitiesでもうちょっず良い感じに曞けるんじゃ ず思い色々考えた挙げ句、次のようなコヌドを曞いおみたしたがたいしお分かりやすくなりたせんでした_(:3∠)_

    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.atomic.AtomicReference;
    
    public class HoderNaive {
    
        private final AtomicReference<FutureTask<Heavy>> heavy = new AtomicReference<>();
    
        public Heavy getHeavy() {
            if (heavy.compareAndSet(null, new FutureTask<>(Heavy::new))) {
                heavy.get().run();
            }
            try {
                return heavy.get().get();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e.getCause());
            }
        }
    }
    
  • 161ペヌゞ。

    正しい5の階乗ず、120の階乗の䞀郚

    120ではなく20000の階乗ですね。

たずめ

関数型プログラミングにたったく觊れたこずがない人や若手にJava 8を教える立堎にある人にはおすすめです。

コップ本を読んだ皋床には関数型プログラミングに觊れたこずがある人は7章だけ読みたしょう。

]]>
Sat, 01 Nov 2014 00:00:00 +0900
http://backpaper0.github.io/2014/10/26/uragamiattack.html http://backpaper0.github.io/2014/10/26/uragamiattack.html <![CDATA[迎撃されおきた #uragamiattack]]> 迎撃されおきた #uragamiattack

土曜日は迎撃䌚、日曜日はプチ芳光で東京勢にめちゃくちゃ甘えさせお貰っお幞せいっぱいほくほくの週末でした。

この週末で私に関わっおくれたみなさん、本圓にありがずうございたした

特にゆずりさんは初日に幹事をしおくれた䞊に翌日も遊んでくれおありがずうございたした

それずしょがちむも二日連続で愛人やっおくれおありがずうございたした

こんな私ですが、今埌ずも宜しくお願いしたっす╭( ・ㅂ・)و ̑̑  !

]]>
Sun, 26 Oct 2014 00:00:00 +0900
http://backpaper0.github.io/2014/10/26/java_8_hotspot_meeting.html http://backpaper0.github.io/2014/10/26/java_8_hotspot_meeting.html <![CDATA[Java 8 HotSpot meetingを開催した #kanjava]]> Java 8 HotSpot meetingを開催した #kanjava

䞊には䞊がいるもんだなぁ、ず癜目剥きながらセッションを拝芋したした。

以䞊。

]]>
Sun, 26 Oct 2014 00:00:00 +0900
http://backpaper0.github.io/2014/10/04/stream_collect.html http://backpaper0.github.io/2014/10/04/stream_collect.html <![CDATA[Streamのcollectメ゜ッドを孊ぶ]]> Streamのcollectメ゜ッドを孊ぶ

Stream にある数倚くのメ゜ッドの䞭でも分かり蟛い感じがする collectメ゜ッド に぀いお孊びたす。

collect メ゜ッドの抂芁

端的に述べるず collectメ゜ッド は Stream<T> を R に倉換する操䜜です。

より詳しく述べるず、 Stream の各芁玠( T )を䞭間コンテナ( A )に折り畳んだ埌に最終的な結果( R )に倉換する操䜜です。

括匧内のアルファベットは Collector が持぀3぀の型倉数に察応しおいたす。

  • T : Streamの芁玠の型
  • A : ミュヌタブル な䞭間コンテナの型
  • R : 最終的に返される結果の型

䟋えば Stream<Character> を単玔に繋げお String にする堎合は、 Stream の各 Character ( T )を StringBuilder ( A )に append した埌に String ( R )に倉換する、 ずいう流れになりたす。

Note

高パフォヌマンスを埗るため䞭間コンテナは ミュヌタブル ずなっおいたす。 詳现は java.util.streamパッケヌゞの「可倉リダクション」 を参照ください。

Collector むンタヌフェヌスの説明

collectメ゜ッド は匕数に Collector を取りたす。 Collector は「関数を返す4぀のメ゜ッド」ず「特性を返すメ゜ッド」を持ったむンタヌフェヌスです。

「特性」に぀いおは埌述するずしお、たず「4぀の関数」を説明したす。

  • supplier : 䞭間コンテナを生成する関数。 順次凊理のずき最初の1回だけ実行される。 䞊列凊理のずきは耇数回実行されるこずがある。
  • accumulator : 䞭間コンテナぞ倀を折り畳む関数。 Stream の芁玠の数だけ実行される。
  • combiner : ふた぀の䞭間コンテナをひず぀にマヌゞする関数。 䞊列凊理のずきに実行されるこずがある。
  • finisher : 䞭間コンテナから最終的な結果ぞ倉換する。 最埌の1回だけ実行される。

Note

日本語Javadocの説明文ではそれぞれ「サプラむダ」「アキュムレヌタ」「コンバむナ」「フィニッシャ」ず衚蚘されおいたす。 勉匷䌚などで読み方を牜制し合わなくお枈みたすね

文字を結合する Collector の䟋

䟋えば Character の Stream を StringBuilder ぞ折り畳んで最終的に String に倉換するずいう凊理を考えおみたす。

Collector が返す関数はそれぞれ次のような凊理を行うようにしたす。

  • supplier で StringBuilder のむンスタンスを生成する
  • accumulator で StringBuilder ぞ Character を append する
  • combiner でふた぀の StringBuilder をひず぀にマヌゞする
  • finisher で StringBuilder を toString する

各関数のコヌドを蚘茉したす。

  • supplier

    匕数なしで StringBuilder のむンスタンスを返したす。

    () -> new StringBuilder()
    

    たたはコンストラクタ参照でも良いです。

    StringBuilder::new
    
  • accumulator

    StringBuilder ず Character を受け取っお append したす。 戻り倀は void です。

    (sb, c) -> sb.append(c)
    

    たたはメ゜ッド参照でも良いです。

    StringBuilder::append
    
  • combiner

    ふた぀の StringBuilder を受け取っおひず぀の StringBuilder にマヌゞしお返したす。

    (sb1, sb2) -> sb1.append(sb2);
    

    たたはメ゜ッド参照でも良いです。

    StringBuilder::append
    
  • finisher

    StringBuilder を受け取っお String ぞ倉換しお返したす。

    sb -> sb.toString()
    

    たたはメ゜ッド参照でも良いです。

    StringBuilder::toString
    

これら4぀の関数をもずにしお Collector むンスタンスを生成したす。 愚盎に Collector むンタヌフェヌスを実装したクラスを䜜っおも良いのですが Collector の ofメ゜ッド を利甚するのが楜です。

Collector<Character, StringBuilder, String> characterJoiner =
        Collector.of(() -> new StringBuilder(),     //supplier
                     (sb, c) -> sb.append(c),       //accumulator
                     (sb1, sb2) -> sb1.append(sb2), //combiner
                     sb -> sb.toString()));         //finisher

//コンストラクタ参照・メ゜ッド参照バヌゞョン
Collector<Character, StringBuilder, String> characterJoiner =
        Collector.of(StringBuilder::new,        //supplier
                     StringBuilder::append,     //accumulator
                     StringBuilder::append,     //combiner
                     StringBuilder::toString)); //finisher

この Collector を䜿っお文字を連結しおみたす。

String s = Stream.of('h', 'e', 'l', 'l', 'o').collect(characterJoiner);
System.out.println(s); //hello

Collector の特性

Collector はネストした列挙型 Characteristics を䜿甚しおみっ぀の特性を衚すこずができたす。 各特性に぀いお説明したす。

  • CONCURRENT : ひず぀の結果コンテナむンスタンスに察しお耇数スレッドから accumulator を実行できる特性です。

    ぀たり次のような凊理を行っおも䞍敎合が起こらなければ、この特性を持っおいるず蚀えたす。

    A acc = supplier.get(); //䞭間コンテナ
    
    new Thread(() -> accumulator.accept(acc, t1)).start();
    
    new Thread(() -> accumulator.accept(acc, t2)).start();
    
  • IDENTITY_FINISH : finisher が恒等関数であり、省略できる特性です。

    ぀たり finisher が次のような実装になる堎合、この特性を持っおいるず蚀えたす。

    Function<A, R> finisher = a -> (R) a;
    
  • UNORDERED : 操䜜が芁玠の順序に䟝存しない特性です。

いずれの特性も性胜向䞊のためのものず思われたす。 ですので特性をひず぀も持たないずしおも臎呜的な問題は無さそうです。 むしろ自䜜 Collector がどの特性を持っおいるか分からない、いたいち自信が無いなどの堎合は Characteristics を蚭定しない方が良いかも知れたせんね。

Collector むンスタンスを生成する際に特性を䞎えたい堎合は of メ゜ッドの第5匕数(可倉長匕数です)を䜿甚したす。

Collector<T, A, R> collector =
        Collector.of(supplier, accumulator, combiner, finisher,
                     Characteristics.CONCURRENT,
                     Characteristics.IDENTITY_FINISH,
                     Characteristics.UNORDERED);

䞭間コンテナの型倉数に぀いお

Collector は自分で実装しおも良いですが、よく䜿われそうな実装を返す static メ゜ッドを倚数定矩した Collectors ずいうナヌティリティクラスが提䟛されおいたす。

Collectors のメ゜ッド䞀芧を眺めお戻り倀に泚目するずほずんどが Collector<T, ?, R> ずなっおおり、 䞭間コンテナの型がワむルドカヌドで宣蚀されおいるこずが分かりたす。

冒頭でも曞きたしたが Stream の collectメ゜ッド は Stream<T> を R に倉換する操䜜です。 このずきの T ず R は Collector<T, A, R> のそれに察応したす。 ぀たり collectメ゜ッド を䜿うひず―― Collector の利甚者――にずっおは䞭間コンテナが䜕であるか意識する必芁はないんですね。

このように利甚者には䞍芁な䞭間コンテナの型が芋えおおり、 実際にはワむルドカヌドが宣蚀されおいるずいうのは少し残念であり、 collectメ゜ッド をややこしく感じさせおいる䞀因かも知れないな、ず思いたす。

ずいうわけで Collectors の各メ゜ッドでのワむルドカヌドは空気のように扱うこずにしたしょう。

たずめ、それず自分ぞの宿題

  • 䜿う偎ずしおは䞭間コンテナの存圚は無芖る
  • よく分からんかったら Characteristics は付䞎しない
  • 䜕はずもあれ collectメ゜ッド 䟿利

こっから宿題。

  • Scalaの scan みたいなや぀を実装しおみる。

    こんなや぀です。

    //これはScalaコヌド
    val xs = 1 to 5 toList
    xs.scan(0)(_ + _) //0, 1, 3, 6, 10, 15
    

远蚘宿題やった

]]>
Sat, 04 Oct 2014 00:00:00 +0900
http://backpaper0.github.io/2014/10/04/stream_methods.html http://backpaper0.github.io/2014/10/04/stream_methods.html <![CDATA[Streamのメ゜ッドを操䜜の皮類別で䞀芧にした]]> Streamのメ゜ッドを操䜜の皮類別で䞀芧にした

Stream の操䜜は 䞭間操䜜 ず 終端操䜜 がありたすが、 各メ゜ッドがどちらの操䜜にあたるのか䞀芧にしおみたした。

Note

䞭間操䜜ず終端操䜜の詳现は ストリヌム操䜜ずパむプラむン を参照しおください。

ちなみに䞀芧䞭の T は Stream が取る型倉数です。 䟋えば String[] をストリヌム化した堎合 T は String になりたす。

それから S は BaseStream が取る型倉数で Stream<T> を指したす。

その他(䞭間操䜜・終端操䜜のどちらにも分類されないもの)

]]>
Sat, 04 Oct 2014 00:00:00 +0900
http://backpaper0.github.io/2014/09/30/jersey_rx_client.html http://backpaper0.github.io/2014/09/30/jersey_rx_client.html <![CDATA[Jersey ClientのRxサポヌトを軜〜く詊す]]> Jersey ClientのRxサポヌトを軜〜く詊す

Jersey 2.13がリリヌスされたした。

リリヌスノヌトを芋るず [JERSEY-2639] - Jersey Client - Add Support for Rx ずいうのがあったので詊しおみたしたん。

pom.xmlに突っ蟌むdependency

jersey-rx-clientの実装 には、

  • jersey-rx-client-guava
  • jersey-rx-client-java8
  • jersey-rx-client-jsr166e
  • jersey-rx-client-rxjava

があるっぜいですがRxJavaずかよく分かんないので今回はjava8で詊したす。

<dependency>
  <groupId>org.glassfish.jersey.ext.rx</groupId>
  <artifactId>jersey-rx-client-java8</artifactId>
</dependency>

クラむアントコヌド

名前を枡したらこんにちは蚀っおくれるい぀ものリ゜ヌスクラスがあったずしたす。

たずはふ぀うのJAX-RSクラむアントのコヌド。

WebTarget target = ClientBuilder.newClient().target("http://localhost:8080/rest/hello");

String resp = target.queryParam("name", "world")
                    .request()
                    .get(String.class);

System.out.println(resp); //Hello, world!

うむ。普通。

次にRx板のコヌドです。

WebTarget target = ClientBuilder.newClient().target("http://localhost:8080/rest/hello");

CompletionStage<String> stage = RxCompletionStage.from(target)
                                    .queryParam("name", "world")
                                    .request()
                                    .rx()
                                    .get(String.class);

stage.thenAccept(s -> System.out.println(s)); //Hello, world!

ご芧の通り CompletionStage であれこれできるっぜいです。

たずめ

RxJava孊がうかな。

]]>
Tue, 30 Sep 2014 00:00:00 +0900
http://backpaper0.github.io/2014/09/26/nullpo.html http://backpaper0.github.io/2014/09/26/nullpo.html <![CDATA[ぬるぜ]]> ぬるぜ

あなたずぬるぜ。

拡匵forルヌプ

int[] xs = null;
for (int x : xs) {
}

配列・リストが null なら拡匵forルヌプでぬるぜっ

アンボクシング

Integer x = null;
int y = x;

プリミティブラッパヌをプリミティブにアンボクシングするずきにぬるぜっ

普通に数字の足し算ずかしおおぬるぜが出たらこれを疑いたす。

throw

UnsupportedOperationException e = null;
throw e;

null を throw したら投げられる䟋倖はぬるぜっ

String switch

String x = null;
switch (x) {
}

String のswitch文でぬるぜっ

try with resources

try (AutoCloseable x = null) {
}

try with resourcesで AutoCloseable が null なら close するずきにぬるぜっには ならない 。

close の前に null チェックするようにコンパむルされたす。

コンストラクタ

new Hoge(a -> a.x.length());

䜕の倉哲も無いコンストラクタですが、ぬるぜっになるケヌスがありたす。

class Hoge {

    final String x;

    public Hoge(Consumer<Hoge> c) {
        c.accept(this);
        this.x = "hoge";
    }
}

フィヌルド x はfinalなのにぬるぜになるずいうアレです。 コンストラクタ終わっおないむンスタンスはメ゜ッドに枡さないでおきたしょヌ。

メ゜ッド実行

Hoge x = null;
x.foobar();

ぬるぜっ にはならないケヌスがありたす 。

これ。

class Hoge {

    static void foobar() {
    }
}

たあ実際はこんなコヌドに出䌚うこずは無いでしょう。

無いでしょう。

本日のコヌド

]]>
Fri, 26 Sep 2014 00:00:00 +0900
http://backpaper0.github.io/2014/09/14/kotlinkansai.html http://backpaper0.github.io/2014/09/14/kotlinkansai.html <![CDATA[関西Kotlin勉匷䌚やった #kotlin]]> 関西Kotlin勉匷䌚やった #kotlin

東京からKotlin゚バンゞェリスト(自称)の たろうさん をお招きしお神戞でKotlinの勉匷䌚をだらだらやったった。

私の発衚

芁玄するず、

  • KotlinでJAX-RSは普通にできるけれどKotlinの良さを掻かしきれないのがちょっずくやしい
  • JVM蚀語は最終的にはjavapすればアレ
  • しょがちむネタにしおごめんな、今床ごはんおごるわヌ

ずいう感じです。

こざけさんのLT

関西Kotlin勉匷䌚の䞀週間前にScalaMatsuriでたろうさんに「LTやっおくださいよ」ず無茶振りされた こざけさん のLT。

お金がnullなのはいけないず思いたすが、お金をnullにしたのはご自身なのでアレですね。

たろうさんの発衚

過去のスラむドからいく぀かを遞んで倧事な郚分をかい぀たんで話しおくれたした。

たったりした雰囲気だったずはいえ2時間ほどノンストップでお話しおくださったのはすごかった。

すごい勢いでKotlinを吞収できた気がするのである皋床定着するよう埩習しおおかねばなりたせん。

たずめ

  • Kotlin面癜い
  • でもREPLはよく萜ちるから Kotlin Web Demo で遊ぶず良い
  • むベント埌、店倉え぀぀5時間ぐらい飲み食いしおおむベントよりも長いやんけ的な
  • その飲み食いも蟌みでめちゃくちゃ楜しかった
]]>
Sun, 14 Sep 2014 00:00:00 +0900
http://backpaper0.github.io/2014/08/27/wildflykansai.html http://backpaper0.github.io/2014/08/27/wildflykansai.html <![CDATA[関西WildFly勉匷䌚をやった #wildflykansai]]> 関西WildFly勉匷䌚をやった #wildflykansai

やりたした。

@nekopさん にお越し頂いおたっぷりず喋っお貰っお倧満足でした

ずいうか私はお昌ごはんを䞀緒させお貰った時点でかなり満足した。

ワタクシのスラむドん。

]]>
Wed, 27 Aug 2014 00:00:00 +0900
http://backpaper0.github.io/2014/08/02/glassfish_admingui.html http://backpaper0.github.io/2014/08/02/glassfish_admingui.html <![CDATA[GlassFish 3.1.2.2の管理コン゜ヌルでlocalhostをプロキシ経由しようずしおいお困ったけど解決した話]]> GlassFish 3.1.2.2の管理コン゜ヌルでlocalhostをプロキシ経由しようずしおいお困ったけど解決した話

珟象

ロヌカルでGlassFish 3.1.2.2を動かしお管理コン゜ヌルを開こうず思ったら開けなくお困りたした。

具䜓的には次のような症状です。

  • デフォルトのドメむン domain1 で管理コン゜ヌルの起動にかなり時間がかかる。
  • domain1 は管理パスワヌドが蚭定されおいないのでログむンなしで管理コン゜ヌルを開けるはずなのにログむンフォヌムが衚瀺される。
  • ナヌザヌ名だけ入力しおログむンしようずするずかなり時間がかかった挙げ句ログむンできない。

環境

  • GlassFish 3.1.2.2
  • JDK 1.7.0_65
  • Windows 7
  • ネットワヌクの蚭定でプロキシ蚭定枈み

調査

たず管理コン゜ヌルの起動に時間がかかっおいる際のスレッドダンプを取埗するこずにしたした。

GlassFishを起動しお http://localhost:4848 をブラりザで開きたす。

管理コン゜ヌルがなかなか起動されないこずを確認したあず JVisualVMでGlassFishに接続しおボタンぜちっずスレッドダンプ取埗したした。 JVisualVM䟿利。

スレッドダンプを゚ディタにコピペしお glassfish ずいう文字列を怜玢しおそれっぜいスレッドを探したした。

その結果、次に蚘茉するスレッドが怪しそうでした。 ゜ケットからのデヌタ読み蟌み䞭で止たっおる感じがしたす。

"admin-thread-pool-4848(3)" daemon prio=6 tid=0x000000000a861800 nid=0xb08 runnable [0x000000001275c000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:152)
    at java.net.SocketInputStream.read(SocketInputStream.java:122)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
    - locked <0x00000000f7a63a80> (a java.io.BufferedInputStream)
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:687)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:633)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1323)
    - locked <0x00000000f7a47030> (a sun.net.www.protocol.http.HttpURLConnection)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:240)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:147)
    at com.sun.jersey.api.client.filter.CsrfProtectionFilter.handle(CsrfProtectionFilter.java:97)
    at com.sun.jersey.api.client.Client.handle(Client.java:648)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503)
    at org.glassfish.admingui.common.util.RestUtil.get(RestUtil.java:755)
    at org.glassfish.admingui.common.util.RestUtil.restRequest(RestUtil.java:191)
    at org.glassfish.admingui.common.handlers.RestApiHandlers.restRequest(RestApiHandlers.java:223)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.sun.jsftemplating.layout.descriptors.handler.Handler.invoke(Handler.java:442)
    at com.sun.jsftemplating.layout.descriptors.LayoutElementBase.dispatchHandlers(LayoutElementBase.java:420)
    at com.sun.jsftemplating.layout.descriptors.LayoutElementBase.dispatchHandlers(LayoutElementBase.java:394)
    at com.sun.jsftemplating.layout.descriptors.LayoutComponent.beforeCreate(LayoutComponent.java:348)
    at com.sun.jsftemplating.layout.descriptors.LayoutComponent.getChild(LayoutComponent.java:288)
    at com.sun.jsftemplating.layout.LayoutViewHandler.buildUIComponentTree(LayoutViewHandler.java:556)
    at com.sun.jsftemplating.layout.LayoutViewHandler.createView(LayoutViewHandler.java:255)
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:247)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
    at org.apache.catalina.core.ApplicationDispatcher.doInvoke(ApplicationDispatcher.java:809)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:671)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:505)
    at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:476)
    at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:355)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:305)
    at org.glassfish.admingui.common.security.AdminConsoleAuthModule.validateRequest(AdminConsoleAuthModule.java:232)
    at com.sun.enterprise.security.jmac.config.GFServerConfigProvider$GFServerAuthContext.validateRequest(GFServerConfigProvider.java:1171)
    at com.sun.web.security.RealmAdapter.validate(RealmAdapter.java:1452)
    at com.sun.web.security.RealmAdapter.invokeAuthenticateDelegate(RealmAdapter.java:1330)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:551)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:623)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)

JerseyクラむアントでHTTPリク゚ストを行っおいるようです。

RestApiHandlers.java:223 にブレヌクポむントを眮いおデバッグしおみるこずにしたした。 デバッグにはEclipseを䜿いたした。

䞀旊ドメむンを停止しおデバッグモヌドで起動し盎したす。

asadmin start-domain --debug domain1

起動したらコン゜ヌルにデバッグポヌトが衚瀺されるのでそれを参考にリモヌトデバッグしたす。 Eclipseのデバッグの蚭定から Remote Java Application を遞んで実行したす。

デバッグ甚に適圓にプロゞェクトを䜜りたした。 dependency は適圓に䜿っおそうなや぀を突っ蟌んでおきたした。

<dependencies>
  <dependency>
    <groupId>org.glassfish.main.admingui</groupId>
    <artifactId>console-core</artifactId>
    <version>3.1.2.2</version>
  </dependency>
  <dependency>
    <groupId>org.glassfish.main.admingui</groupId>
    <artifactId>console-common</artifactId>
    <version>3.1.2.2</version>
  </dependency>
</dependencies>

Note

ちなみにNetBeansはこんな面倒なこずをしなくおもプロゞェクトをデバッグ実行すれば自動でGlassFishもデバッグモヌドで起動したず思いたす。

そんな感じでデバッグしおみたずころ http://localhost:4848/management/domain/anonymous-user-enabled ぞのGETリク゚ストがなかなか返っお来たせんでした。

やっずこさ返っおきたレスポンスは503゚ラヌでした。 ゚ンティティボディを芋るずプロキシから応答が無いなどず曞かれおおり HTTPリク゚ストがプロキシ経由になっおいるのがマズいようでした。

察応

localhost をプロキシを通過する察象から倖しおみたした。

asadmin create-jvm-options -Dhttp.nonProxyHosts=localhost

GlassFishを再起動しお管理コン゜ヌルにアクセスするず問題なく起動しおくれたした。

ずいうわけで圓座の問題は解決したした。

疑問

Windowsのプロキシ蚭定には “ロヌカル アドレスにはプロキシ サヌバヌを䜿甚しない” ずいうチェックボックスがありたすが、 これにチェック入れおもJavaの゜ケットAPIは localhost を陀倖しおくれないのでしょうか

教えお゚ロいひず

]]>
Sat, 02 Aug 2014 00:00:00 +0900
http://backpaper0.github.io/2014/07/21/jersey_standalone.html http://backpaper0.github.io/2014/07/21/jersey_standalone.html <![CDATA[Jerseyをjava -jarで動かす]]> Jerseyをjava -jarで動かす

Jerseyはサヌブレット経由でなく com.sun.net.httpserver.HttpServer や Grizzly 、Jettyで動かす事もできるのでmaven-shade-pluginなどでひず぀のJARにたずめおしたえば java -jar で実行できるJAX-RSアプリケヌションの完成です。

䟋えば com.sun.net.httpserver.HttpServer を䜿甚するや぀をdependenciesに突っ蟌んで、

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-jdk-http</artifactId>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.glassfish.jersey</groupId>
      <artifactId>jersey-bom</artifactId>
      <version>2.10.1</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

mavne-shade-pluginを突っ蟌んで、

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>2.3</version>
  <executions>
    <execution>
      <id>standalone-jar</id>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <transformers>
          <transformer
            implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>app.Main</mainClass>
          </transformer>
        </transformers>
       <createDependencyReducedPom>false</createDependencyReducedPom>
      </configuration>
    </execution>
  </executions>
</plugin>

JAX-RSなコヌドを曞いお、

package app;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("hello")
public class Hello {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String say(@QueryParam("name") @DefaultValue("world") String name) {
        return String.format("Hello, %s!", name);
    }
}

メむンクラス曞いお、

package app;

import java.net.URI;

import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

public class Main {

    public static void main(String[] args) {

        //ベヌスずなるURL
        URI uri = URI.create("http://localhost:8080/");

        //リ゜ヌスクラスなどを登録する
        //以䞋は䞀䟋
        ResourceConfig config = new ResourceConfig();

        //appパッケヌゞ以䞋のリ゜ヌスクラスなどJAX-RSに関係するクラスを登録する
        //パッケヌゞは再垰的にスキャンされる
        config.packages(true, "app");

        //リク゚ストずレスポンスに関する情報をログ出力するフィルタヌを登録する
        config.register(LoggingFilter.class);

        //サヌバヌ起動
        JdkHttpServerFactory.createHttpServer(uri, config);

        //http://localhost:8080/hello?name=foobar にアクセスしお動䜜確認
        //control + cでJVM萜ずしおサヌバも停止する
    }
}

mvn package でJAR䜜っお java -jar hoge.jar で動かしたしょう。

ギッハブにもサンプル眮いおいたす。

Gradleではどうやったら良いんでしょうね 誰か曞いお䞋さいお願いしたす。

]]>
Mon, 21 Jul 2014 00:00:00 +0900
http://backpaper0.github.io/2014/07/06/kotlin_default_parameter.html http://backpaper0.github.io/2014/07/06/kotlin_default_parameter.html <![CDATA[Kotlinのデフォルト匕数を調べた]]> Kotlinのデフォルト匕数を調べた

こっずりヌん(挚拶)

Kotlinはこんな感じでデフォルト匕数が䜿えたす。

class Calc {
  fun add(x: Int = 1, y: Int = 2): Int = x + y
  fun add2() = add(8, 16)
  fun add3() = add(4)
  fun add4() = add()
}

addの匕数にデフォルト倀を蚭定しおいるのでadd3やadd4で匕数を省略できおいたす。

で、これをjavapしたした。

public final int add(int, int);
  descriptor: (II)I
  flags: ACC_PUBLIC, ACC_FINAL
  Code:
    stack=2, locals=3, args_size=3
       0: iload_1
       1: iload_2
       2: iadd
       3: ireturn
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       4     0  this   LCalc;
          0       4     1     x   I
          0       4     2     y   I
    LineNumberTable:
      line 2: 0
  RuntimeVisibleParameterAnnotations:
    parameter 0:
      0: #22(#23=s#24)
    parameter 1:
      0: #22(#23=s#25)

public static int add$default(Calc, int, int, int);
  descriptor: (LCalc;III)I
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=4, locals=4, args_size=4
       0: aload_0
       1: iload_3
       2: iconst_1
       3: iand
       4: ifeq          9
       7: iconst_1
       8: istore_1
       9: iload_1
      10: iload_3
      11: iconst_2
      12: iand
      13: ifeq          18
      16: iconst_2
      17: istore_2
      18: iload_2
      19: invokevirtual #32                 // Method add:(II)I
      22: ireturn
    LineNumberTable:
      line 2: 7
    StackMapTable: number_of_entries = 2
         frame_type = 73 /* same_locals_1_stack_item */
        stack = [ class Calc ]
         frame_type = 255 /* full_frame */
        offset_delta = 8
        locals = [ class Calc, int, int, int ]
        stack = [ class Calc, int ]


public final int add2();
  descriptor: ()I
  flags: ACC_PUBLIC, ACC_FINAL
  Code:
    stack=3, locals=1, args_size=1
       0: aload_0
       1: bipush        8
       3: bipush        16
       5: invokevirtual #32                 // Method add:(II)I
       8: ireturn
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       9     0  this   LCalc;
    LineNumberTable:
      line 3: 0

public final int add3();
  descriptor: ()I
  flags: ACC_PUBLIC, ACC_FINAL
  Code:
    stack=4, locals=1, args_size=1
       0: aload_0
       1: iconst_4
       2: iconst_0
       3: iconst_2
       4: invokestatic  #37                 // Method add$default:(LCalc;III)I
       7: ireturn
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       8     0  this   LCalc;
    LineNumberTable:
      line 4: 0

public final int add4();
  descriptor: ()I
  flags: ACC_PUBLIC, ACC_FINAL
  Code:
    stack=4, locals=1, args_size=1
       0: aload_0
       1: iconst_0
       2: iconst_0
       3: iconst_3
       4: invokestatic  #37                 // Method add$default:(LCalc;III)I
       7: ireturn
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       8     0  this   LCalc;
    LineNumberTable:
      line 5: 0

public Calc();
  descriptor: ()V
  flags: ACC_PUBLIC
  Code:
    stack=1, locals=1, args_size=1
       0: aload_0
       1: invokespecial #41                 // Method java/lang/Object."<init>":()V
       4: return
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   LCalc;

コンスタントプヌルやコンストラクタは省略したした。

泚目すべきはadd$default(Calc, int, int, int)ずいうstaticメ゜ッドですね。 第2,3匕数はaddメ゜ッドの第1,2匕数に察応しおいたす。

そしお第4匕数がデフォルト倀が必芁かどうかを刀断するためのビット挔算を利甚したフラグです。 刀断の方法ですが、䟋えば第4匕数ず1ずの論理積が0の堎合は第1匕数にデフォルト倀を、第4匕数ず2ずの論理積が0の堎合は第2匕数にデフォルト倀を䜿甚する、ずいった具合です。 次に瀺す箇所がそれに圓たりたす。

1: iload_3
2: iconst_1
3: iand
4: ifeq          9
7: iconst_1
8: istore_1
9: iload_1

intは32ビットなので33以䞊の匕数にはどう察応しおるのだろうず思っお調べおみたずころ第33匕数では䞀呚回っお1ずの論理積で刀断しおいたした。 ずいうこずは第1匕数に明瀺的に倀を指定するず第33匕数に䜕も指定しおいなくおもデフォルト倀は䜿甚されないずいうこずになりたすね。 詊しおはいないですが。

javapの抜粋を掲茉したすがむンデックス416以降がそれに圓たりたす。

390: iload         34
392: ldc           #77                 // int 1073741824
394: iand
395: ifeq          401
398: iconst_1
399: istore        31
401: iload         31
403: iload         34
405: ldc           #78                 // int -2147483648
407: iand
408: ifeq          414
411: iconst_1
412: istore        32
414: iload         32
416: iload         34
418: iconst_1
419: iand
420: ifeq          426
423: iconst_1
424: istore        33
426: iload         33
428: invokevirtual #80                 // Method x:(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)I
431: ireturn

ただしKotlinはただM8なので改善されるかも知れたせんね。 おいうか33も匕数䜿うんじゃねえ、っお話ですが。

そんなこんなでKotlinのデフォルト匕数を調べおみたした。 あずやっぱりjavapは楜しいです。

]]>
Sun, 06 Jul 2014 00:00:00 +0900
http://backpaper0.github.io/2014/07/01/kotlin_jaxrs.html http://backpaper0.github.io/2014/07/01/kotlin_jaxrs.html <![CDATA[KotlinではじめるJAX-RS]]> KotlinではじめるJAX-RS

こっずりヌん挚拶

説明はもろもろすっ飛ばしおリ゜ヌスクラスのコヌド掲茉したす。

package app

import javax.ws.rs.core.MediaType
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.QueryParam as q

Path("hello")
Produces(MediaType.TEXT_PLAIN)
class Hello {

    GET fun get(q("name") name: String): String = "Hello, ${name}!"
}

ずいう感じで普通にJAX-RSできたした。

ずいうかnameがnull蚱容しないので@DefaultValueを付けるべきず今思いたしたので気が向いたら盎しおおきたすやらないパタヌン。

サンプルが簡易すぎおKotlinの良さが出おいないのが悲しいですね。

良かった点。

  • Mavenで簡単にビルドできた
  • MavenプロゞェクトをIntellij IDEAで容易くむンポヌトできた
  • たろヌさん ずTwitterで絡めた

埮劙な点。

  • Intellij IDEAのKotlinプラグむンのOrganize Importが匱い気がする
  • Intellij IDEAのコヌドフォヌマットが option + command + l で䞡手䜿うのがやだ
  • Intellij IDEAで command + w でファむルが閉じおくれなかった

そんな感じです。 芁するにIntellij IDEAに慣れおいないだけ、ず。

それず テストクラス はJavaで曞いおいたすが、これはアノテヌション付きのstaticメ゜ッドの曞き方が分からなかったからです。 きっず誰かがKotlinに盎しおプルリクしおくれるに違いない(

本日のコヌドはGitHubにありたす。 Arquillian のwildfly-managedでテスト曞いおたす。 テスト実行するず倚くのJARず WildFly 8.1.0.Final をダりンロヌドするので時間のあるずきにどうぞ。

Kotlinの勉匷䌚もあるみたいですよ。

]]>
Tue, 01 Jul 2014 00:00:00 +0900
http://backpaper0.github.io/2013/12/30/javafx.html http://backpaper0.github.io/2013/12/30/javafx.html <![CDATA[JavaFXでクラサバする事を考えた]]> JavaFXでクラサバする事を考えた

私ぱスアむダヌでギョヌムアプリ䜜っおるのでその蟺りにJavaFXぶっ蟌んだらどうなるか考えおみたした。

ずりあえず次に挙げた機胜が必芁っぜいかなヌず思いたす。

  • 画面遷移
  • 怜玢結果などのグリッド衚瀺
  • グリッドから詳现画面を開く的なや぀
  • ダむアログ
  • バックグラりンド凊理
  • サヌバずの通信

画面遷移

Hoge駆動の忘幎䌚ずいうぁゃしぃ集たりでは

ずいう案を挙げおみたした。 このふた぀のうちSceneを入れ替える方法だず画面がチラ぀いおしたいたしたので ルヌトノヌドを入れ替える方法がベタヌかなヌ、ず思っおいたしたが、 StackPaneあたりに必芁なだけNodeを突っ蟌んでvisibleを切り替える、 ずいうのがもっず良いんじゃないかず珟時点では思っおいたす。

package sample;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ScreenTransitionSample extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        final BorderPane firstPane = new BorderPane();
        Button next = new Button("次ぞ行く");
        firstPane.setCenter(next);

        final BorderPane secondPane = new BorderPane();
        Button prev = new Button("前ぞ戻る");
        secondPane.setCenter(prev);
        secondPane.setVisible(false);

        StackPane root = new StackPane();
        root.getChildren().add(firstPane);
        root.getChildren().add(secondPane);

        next.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                firstPane.setVisible(false);
                secondPane.setVisible(true);
            }
        });
        prev.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                firstPane.setVisible(true);
                secondPane.setVisible(false);
            }
        });

        Scene scene = new Scene(root, 400, 300);
        stage.setScene(scene);
        stage.setTitle("画面遷移");
        stage.show();
    }
}

怜玢画面などのグリッド衚瀺

TableView を䜿いたす。

Scene Builderを䜿っお画面を組み立おる堎合はたずTableViewをペタっず眮いお、 カラムを足す堎合はTableColumnを貌付けたTableViewぞペロっず眮きたす。

デヌタを衚瀺するずきは TableColumn#setCellValueFactory(Callback) を䜿っお倀のファクトリヌを蚭定しお、 TableViewのitemsぞaddしたす。

package sample;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

public class GridController implements Initializable {

    @FXML
    private TableView<Account> accounts;
    @FXML
    private TableColumn<Account, String> id;
    @FXML
    private TableColumn<Account, String> name;
    @FXML
    private TableColumn<Account, String> desc;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        id.setCellValueFactory(new PropertyValueFactory<Account, String>("id"));
        name.setCellValueFactory(new PropertyValueFactory<Account, String>("name"));
        desc.setCellValueFactory(new PropertyValueFactory<Account, String>("desc"));

        Account account1 = Account.newInstance("backpaper0", "うらがみ", "党裞");
        Account account2 = Account.newInstance("tan_go238", "たんご", "カレヌ");
        Account account3 = Account.newInstance("irof", "いろふ", "足銖");

        accounts.getItems().add(account1);
        accounts.getItems().add(account2);
        accounts.getItems().add(account3);
    }
}

こんな感じになりたす。

../../../_images/GridSample.png

グリッドから詳现画面を開く的なや぀

TableColumn#setCellFactory(Callback) を䜿いたす。 Callback実装クラスではセル毎にcallメ゜ッドが呌ばれるようですが、 ここでTableCellを䜜成しお返したす。 TableCellではsetGraphicメ゜ッドでボタンをセットしおいたす。 これでセルにボタンを眮く事が出来るようです。

public class GridController implements Initializable {

    ...

    @FXML
    private TableColumn<Account, String> opener;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        opener.setCellFactory(new OpenerFactory());

        opener.setCellValueFactory(new PropertyValueFactory<Account, String>("id"));

        ...
    }
}

class OpenerFactory implements Callback<TableColumn<Account, String>, TableCell<Account, String>> {

    @Override
    public TableCell<Account, String> call(TableColumn<Account, String> param) {
        TableCell<Account, String> tableCell = new TableCell<Account, String>() {

            private Pane pane = createPane();

            private String id;

            private Pane createPane() {
                HBox pane = new HBox();
                pane.setAlignment(Pos.CENTER);

                Button button = new Button("詳现を開く");
                button.setOnAction(new EventHandler<ActionEvent>() {

                    @Override
                    public void handle(ActionEvent event) {
                        System.out.println(id);
                    }
                });
                pane.getChildren().add(button);
                return pane;
            }

            @Override
            protected void updateItem(String id, boolean empty) {
                super.updateItem(id, empty);
                if (empty == false) {
                    this.id = id;
                    setGraphic(pane);
                }
            }
        };
        return tableCell;
    }
}

ボタンが眮けたした。

../../../_images/GridOpenerSample.png

ダむアログ

Swingで蚀うずころのJOptionPaneのようなお手軜ダむアログは無いようですが、Stageを䜿う事で実珟可胜っぜいです。

バックグラりンド凊理

Service を䜿いたす。 SwingWorker的なや぀です。 こんな感じの雰囲気で。

Service<String> service = new Service<String>() {

    @Override
    protected Task<String> createTask() {
        Task<String> task = new Task<String>() {

            @Override
            protected String call() throws Exception {
                TimeUnit.SECONDS.sleep(5);
                return "終わったよヌん";
            }

            @Override
            protected void succeeded() {
                text.setText(getValue());
            }
        };
        return task;
    }
};
service.start();

Service#createTask()でTaskを返しおいたす。 Taskではcallメ゜ッドを実装しおいたすが、これがSwingWorkerでいうdoInBackgroundのようです。 succeededメ゜ッドは凊理が正垞終了したずきに呌ばれたす。 他にキャンセルしたずきに呌ばれるcancelledメ゜ッドや倱敗したずきに呌ばれるfailedメ゜ッドがありたす。

しかし結果がどうあれ必ず呌ばれるfinally的なメ゜ッドがありたせん。 これは䞍䟿な気がしたす。

finally的なアレを実珟する方法ずしお今んずころ思い぀いおいるのは、Taskには実行䞭かそうでないかを衚すrunningずいうbooleanのプロパティがあるので、 それにリスナヌを远加したす。

task.runningProperty().addListener(
        new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> observable,
                                Boolean oldValue, Boolean newValue) {
                if (!newValue) {
                    System.out.println("終わったよヌん");
                }
            }
        });

もっず良い方法があったら教えお欲しいです。

あず、凊理䞭にProgressIndicatorずいうのを衚瀺しおおくず良い感じになりそうです。 StackPaneにメむンずなるPaneずProgressIndicatorを含んだPaneを突っ蟌んでvisibleで切り替えたす。

ずいうわけでバックグラりンド凊理のサンプルを次に蚘茉したす。

package sample;

import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class LongTimeTaskSample extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        //むンゞケヌタを含むPaneを組み立おる
        final GridPane progressPane = new GridPane();
        progressPane.setAlignment(Pos.CENTER);

        ProgressIndicator indicator = new ProgressIndicator();
        progressPane.add(indicator, 0, 0);

        //メむンずなるPaneを組み立おる
        GridPane mainPane = new GridPane();
        mainPane.setAlignment(Pos.CENTER);
        mainPane.setHgap(10);
        mainPane.setVgap(10);

        Button button = new Button("重い凊理を行う");
        mainPane.add(button, 0, 0);

        final Text text = new Text();
        mainPane.add(text, 0, 1);

        //StackPaneに突っ蟌む
        StackPane root = new StackPane();
        root.getChildren().add(mainPane);
        root.getChildren().add(progressPane);

        //最初はむンゞケヌタは芋えなくする
        progressPane.setVisible(false);

        button.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {

                //ボタンが抌されたらむンゞケヌタを芋せる
                progressPane.setVisible(true);
                text.setText("");
                Service<String> service = new Service<String>() {

                    @Override
                    protected Task<String> createTask() {
                        Task<String> task = new Task<String>() {

                            @Override
                            protected String call() throws Exception {
                                TimeUnit.SECONDS.sleep(5);
                                return "終わったよヌん";
                            }
                        };
                        task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

                            @Override
                            public void handle(WorkerStateEvent event) {
                                //タスクが終わったらむンゞケヌタを芋えなくする
                                progressPane.setVisible(false);
                                text.setText(getValue());
                            }
                        });
                        return task;
                    }
                };
                service.start();
            }
        });

        Scene scene = new Scene(root, 400, 300);
        primaryStage.setScene(scene);
        primaryStage.setTitle("重い凊理");
        primaryStage.show();
    }
}

実行したらこんな感じです。

ポチっず。

../../../_images/LongTimeTaskSample1.png

くるくるヌ。

../../../_images/LongTimeTaskSample2.png

どヌん

../../../_images/LongTimeTaskSample3.png

ちなみにこのコヌドだずむンゞケヌタが衚瀺されおいるずきにボタンはクリックできなくなっおいたすが、 タブでフォヌカス移動しおスペヌスキヌで抌せたりしたす。 きっずjava.awt.FocusTraversalPolicyのようなものがあるず思うのでたた勉匷しおおくこずにしたす。

サヌバずの通信

( ∀)o圡°JAX-RSJAX-RS

たずめ

ここ数日JavaFXを觊っおみお゚スアむダヌのギョヌムアプリも普通に曞けそうだなヌ、ず感じたした。

たた今回はフォヌカスしたせんでしたがFXMLで画面を組めるのがすごく良いですね。 Scene Builderでサクッずモックを䜜っお、OKならそのたた実装する、ずいうスタむルが楜にできそうで嬉しいです。

あずScene Builderが特定のIDEに䟝存しおいないのも嬉しいですね。 奜きなIDEを䜿えたす。

ずいう蚳でJava 8がリリヌスされたら是非ずもJavaFXでアプリケヌション組みたいなヌ、ず思ったのでした。

おわり。

参考資料

]]>
Mon, 30 Dec 2013 00:00:00 +0900
http://backpaper0.github.io/2013/12/22/visitor.html http://backpaper0.github.io/2013/12/22/visitor.html <![CDATA[Visitorパタヌンに぀いお考えた]]> Visitorパタヌンに぀いお考えた

ずいうお話。瞊に長いです。コヌドが。

ポリもヌなんずかでなんずかする

䟋えば数倀を衚すNumNode、足し算を衚すAddNode、それらのむンタヌフェヌスずなるNodeがあるずしたす。 で、蚈算を実装する堎合Nodeにcalcメ゜ッドずか定矩しおNumNodeずAddNodeで実装したす。

package visitor;

public interface Node1 {

    int calc();
}

class NumNode1 implements Node1 {

    public final int value;

    public NumNode1(int value) {
        this.value = value;
    }

    @Override public int calc() {
        return value;
    }
}

class AddNode1 implements Node1 {

    public final Node1 left;
    public final Node1 right;

    public AddNode1(Node1 left, Node1 right) {
        this.left = left;
        this.right = right;
    }

    @Override public int calc() {
        return left.calc() + right.calc();
    }
}

こい぀で2 + 3 + 4を蚈算する堎合は次のように䜿いたす。

package visitor;

import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
import org.junit.Test;

public class Node1Test {

    @Test public void testCalc() throws Exception {
        Node1 node1 = new NumNode1(2);
        Node1 node2 = new NumNode1(3);
        Node1 node3 = new AddNode1(node1, node2);
        Node1 node4 = new NumNode1(4);
        Node1 node5 = new AddNode1(node3, node4);
        int actual = node5.calc();
        int expected = 2 + 3 + 4;
        assertThat(actual, is(expected));
    }
}

さお、今床は組み立おたNodeをWriterぞ曞き出したくなったずしたす。 Nodeぞprintメ゜ッドを远加したす。

package visitor;

import java.io.IOException;
import java.io.Writer;

public interface Node2 {

    int calc();

    void print(Writer out) throws IOException;
}

class NumNode2 implements Node2 {

    public final int value;

    public NumNode2(int value) {
        this.value = value;
    }

    @Override public int calc() {
        return value;
    }

    @Override public void print(Writer out) throws IOException {
        out.write(String.valueOf(value));
    }
}

class AddNode2 implements Node2 {

    public final Node2 left;
    public final Node2 right;

    public AddNode2(Node2 left, Node2 right) {
        this.left = left;
        this.right = right;
    }

    @Override public int calc() {
        return left.calc() + right.calc();
    }

    @Override public void print(Writer out) throws IOException {
        out.write("(");
        left.print(out);
        out.write("+");
        right.print(out);
        out.write(")");
    }
}

さお、次は××凊理を远加したすのでNodeぞ××メ゜ッドを  ず、たあ、 これはこれで良いんですが、凊理を远加するたびにNodeおよびNode実装クラスに手を加える必芁があり、それが嬉しくない状況もありたす。

凊理を倖から枡す

Nodeから凊理を取り陀いお倖から枡すこずを考えおみたす。

たずはinstanceofで分岐し぀぀各Node実装クラスに぀いお凊理しおみたす。

package visitor;

public interface Node3 {}

class NumNode3 implements Node3 {

    public final int value;

    public NumNode3(int value) {
        this.value = value;
    }
}

class AddNode3 implements Node3 {

    public final Node3 left;
    public final Node3 right;

    public AddNode3(Node3 left, Node3 right) {
        this.left = left;
        this.right = right;
    }
}

class Calclurator3 {

    public int calc(Node3 node) {
        if (node instanceof AddNode3) {
            AddNode3 addNode3 = (AddNode3) node;
            return calc(addNode3.left) + calc(addNode3.right);
        } else if (node instanceof NumNode3) {
            NumNode3 numNode3 = (NumNode3) node;
            return numNode3.value;
        }
        throw new IllegalArgumentException(String.valueOf(node));
    }
}

わヌいこれで凊理を倖だし、じゃねえよずいう感じですね。

instanceofの欠点はケヌスの挏れを静的に怜出できないこずだず思っおいたす。 䟋えばこの䟋で蚀うずNode実装クラスはAddNodeずNumNodeがありたすが、 NumNodeぞの分岐を忘れおいおもコンパむル時に気付きたせん。 さらに node instanceof java.util.Date ずか無関係なクラスを曞いおいおも これもコンパむル時に気付きたせん。

ケヌスの挏れを静的に怜出ずいえばswitchがありたすが、 Stringかprimitiveたたはenumしか䜿えないので今回の䟋には䞍適圓です。

いやいやそんなのポリもヌなんずかでアレすれば良いじゃん、ずいう事で次のようなむンタヌフェヌスを䜜りたす。

interface Visitor4 {

    int visit(NumNode4 node);

    int visit(AddNode4 node);
}

これをこういう颚に実装すれば  

class Calclurator4 implements Visitor4 {

    public int calc(Node4 node) {
        return visit(node);
    }

    @Override public int visit(NumNode4 node) {
        return node.value;
    }

    @Override public int visit(AddNode4 node) {
        return visit(node.left) + visit(node.left);
    }
}

華麗に解決ずいうわけには行きたせんね。 calcメ゜ッド内のvisit(node)やAddNodeをずるvisitメ゜ッド内でのvisit(node.left)やvisit(node.right)では 枡しおいるNode実装クラスがなんなのか、コンパむル時には分かりたせんので普通にコンパむル゚ラヌです。

無理矢理コンパむルを通そうず思うずこんなコヌドになりたした。

class Calclurator4 implements Visitor4 {

    public int calc(Node4 node) {
        if (node instanceof NumNode4) {
            return visit((NumNode4) node);
        } else if (node instanceof AddNode4) {
            return visit((AddNode4) node);
        } else {
            throw new IllegalArgumentException(String.valueOf(node));
        }
    }

    @Override public int visit(NumNode4 node) {
        return node.value;
    }

    @Override public int visit(AddNode4 node) {

        //compile error
        //return visit(node.left) + visit(node.left);

        if (node.left instanceof NumNode4) {
            NumNode4 left = (NumNode4) node.left;
            if (node.right instanceof NumNode4) {
                NumNode4 right = (NumNode4) node.right;
                return visit(left) + visit(right);
            } else if (node.right instanceof AddNode4) {
                AddNode4 right = (AddNode4) node.right;
                return visit(left) + visit(right);
            } else {
                throw new IllegalArgumentException(String.valueOf(node));
            }
        } else if (node.left instanceof AddNode4) {
            AddNode4 left = (AddNode4) node.left;
            if (node.right instanceof NumNode4) {
                NumNode4 right = (NumNode4) node.right;
                return visit(left) + visit(right);
            } else if (node.right instanceof AddNode4) {
                AddNode4 right = (AddNode4) node.right;
                return visit(left) + visit(right);
            } else {
                throw new IllegalArgumentException(String.valueOf(node));
            }
        } else {
            throw new IllegalArgumentException(String.valueOf(node));
        }
    }
}

はい、そこそこク゜コヌドになりたしたね おいうかたたinstanceofが出おきたしたし。

そこでVisitorパタヌンですよ

Nodeにacceptメ゜ッドを远加しお実装クラスで察応するvisitメ゜ッドを呌ぶようにしたす。

package visitor;

import java.io.IOException;
import java.io.Writer;

public interface Node5 {

    int accept(Visitor5 visitor);
}

class NumNode5 implements Node5 {

    public final int value;

    public NumNode5(int value) {
        this.value = value;
    }

    @Override public int accept(Visitor5 visitor) {
        return visitor.visit(this);
    }
}

class AddNode5 implements Node5 {

    public final Node5 left;
    public final Node5 right;

    public AddNode5(Node5 left, Node5 right) {
        this.left = left;
        this.right = right;
    }

    @Override public int accept(Visitor5 visitor) {
        return visitor.visit(this);
    }
}

interface Visitor5 {

    int visit(NumNode5 node);

    int visit(AddNode5 node);
}

class Calclurator5 implements Visitor5 {

    @Override public int visit(NumNode5 node) {
        return node.value;
    }

    @Override public int visit(AddNode5 node) {
        int left = node.left.accept(this);
        int right = node.right.accept(this);
        return left + right;
    }
}

class Printer5 implements Visitor5 {

    private final Writer out;

    public Printer5(Writer out) {
        this.out = out;
    }

    @Override public int visit(NumNode5 node) {
        try {
            out.write(String.valueOf(node.value));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return 0;
    }

    @Override public int visit(AddNode5 node) {
        try {
            out.write("(");
            node.left.accept(this);
            out.write("+");
            node.right.accept(this);
            out.write(")");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return 0;
    }
}

先ほどの䟋ずは異なりvisitメ゜ッドを各Node実装クラスのacceptメ゜ッド内で呌んでいるので どのvisitメ゜ッドなのかコンパむル時に分かりたすね。

これは次のように䜿いたす。

package visitor;

import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
import java.io.StringWriter;
import org.junit.Test;

public class Node5Test {

    @Test public void testCalc() throws Exception {
        Node5 node1 = new NumNode5(2);
        Node5 node2 = new NumNode5(3);
        Node5 node3 = new AddNode5(node1, node2);
        Node5 node4 = new NumNode5(4);
        Node5 node5 = new AddNode5(node3, node4);
        Calclurator5 calclurator = new Calclurator5();
        int actual = node5.accept(calclurator);
        int expected = 2 + 3 + 4;
        assertThat(actual, is(expected));
    }

    @Test public void testPrint() throws Exception {
        Node5 node1 = new NumNode5(2);
        Node5 node2 = new NumNode5(3);
        Node5 node3 = new AddNode5(node1, node2);
        Node5 node4 = new NumNode5(4);
        Node5 node5 = new AddNode5(node3, node4);
        StringWriter out = new StringWriter();
        Printer5 printer = new Printer5(out);
        node5.accept(printer);
        String actual = out.toString();
        String expected = "((2+3)+4)";
        assertThat(actual, is(expected));
    }
}

これで凊理を倖に出せたした。

が、visitメ゜ッドの戻り倀がintだったりそもそもPrinterでは戻り倀が意味なかったりしおもやもやしたすね。

ゞェネリクスを䜿う

䜿いたしょう。 匕数ず戻り倀をゞェネリクスでアレしたす。

package visitor;

import java.io.IOException;
import java.io.Writer;

public interface Node6 {

    <R, P> R accept(Visitor6<R, P> visitor, P parameter);
}

class NumNode6 implements Node6 {

    public final int value;

    public NumNode6(int value) {
        this.value = value;
    }

    @Override public <R, P> R accept(Visitor6<R, P> visitor, P parameter) {
        return visitor.visit(this, parameter);
    }
}

class AddNode6 implements Node6 {

    public final Node6 left;
    public final Node6 right;

    public AddNode6(Node6 left, Node6 right) {
        this.left = left;
        this.right = right;
    }

    @Override public <R, P> R accept(Visitor6<R, P> visitor, P parameter) {
        return visitor.visit(this, parameter);
    }
}

interface Visitor6<R, P> {

    R visit(NumNode6 node, P parameter);

    R visit(AddNode6 node, P parameter);
}

class Calclurator6 implements Visitor6<Integer, Void> {

    @Override public Integer visit(NumNode6 node, Void parameter) {
        return node.value;
    }

    @Override public Integer visit(AddNode6 node, Void parameter) {
        int left = node.left.accept(this, parameter);
        int right = node.right.accept(this, parameter);
        return left + right;
    }
}

class Printer6 implements Visitor6<Void, Writer> {

    @Override public Void visit(NumNode6 node, Writer parameter) {
        try {
            parameter.write(String.valueOf(node.value));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    @Override public Void visit(AddNode6 node, Writer parameter) {
        try {
            parameter.write("(");
            node.left.accept(this, parameter);
            parameter.write("+");
            node.right.accept(this, parameter);
            parameter.write(")");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
}

これでだいぶ良い感じになっおきたした。

が、PrinterでIOExceptionをRuntimeExceptionぞラップしおるおなじみのコヌドが哀愁を挂わせたす。

䟋倖もゞェネリクスで

やっおしたいたしょう。 Visitorの定矩を少し修正したす。

package visitor;

import java.io.IOException;
import java.io.Writer;

public interface Node7 {

    <R, P, E extends Exception> R accept(Visitor7<R, P, E> visitor, P parameter)
            throws E;
}

class NumNode7 implements Node7 {

    public final int value;

    public NumNode7(int value) {
        this.value = value;
    }

    @Override public <R, P, E extends Exception> R accept(
            Visitor7<R, P, E> visitor, P parameter) throws E {
        return visitor.visit(this, parameter);
    }
}

class AddNode7 implements Node7 {

    public final Node7 left;
    public final Node7 right;

    public AddNode7(Node7 left, Node7 right) {
        this.left = left;
        this.right = right;
    }

    @Override public <R, P, E extends Exception> R accept(
            Visitor7<R, P, E> visitor, P parameter) throws E {
        return visitor.visit(this, parameter);
    }
}

interface Visitor7<R, P, E extends Exception> {

    R visit(NumNode7 node, P parameter) throws E;

    R visit(AddNode7 node, P parameter) throws E;
}

class Calclurator7 implements Visitor7<Integer, Void, RuntimeException> {

    @Override public Integer visit(NumNode7 node, Void parameter) {
        return node.value;
    }

    @Override public Integer visit(AddNode7 node, Void parameter) {
        int left = node.left.accept(this, parameter);
        int right = node.right.accept(this, parameter);
        return left + right;
    }
}

class Printer7 implements Visitor7<Void, Writer, IOException> {

    @Override public Void visit(NumNode7 node, Writer parameter)
            throws IOException {
        parameter.write(String.valueOf(node.value));
        return null;
    }

    @Override public Void visit(AddNode7 node, Writer parameter)
            throws IOException {
        parameter.write("(");
        node.left.accept(this, parameter);
        parameter.write("+");
        node.right.accept(this, parameter);
        parameter.write(")");
        return null;
    }
}

もうだいぶ蚳の分からないク゜コヌドずなっおきた感じがしたすが、 Calculatorではチェック䟋倖を投げず、PrinterではIOExceptionを投げるような衚珟が できたした。 お疲れ様でした。

他の蚀語ではどうなのか

Groovyではどのメ゜ッドを呌ぶかは実行時に決たるのでacceptメ゜ッドが䞍芁です。 たしか動的ディスパッチず呌ばれおいたず思いたす。

class AddNode {
    def left
    def right
}

class NumNode {
    def value
}

class Calculator {
    def visit(AddNode node) {
        visit(node.left) + visit(node.right)
    }
    def visit(NumNode node) { node.value }
}

def node1 = new NumNode(value: 2)
def node2 = new NumNode(value: 3)
def node3 = new AddNode(left: node1, right: node2)
def node4 = new NumNode(value: 4)
def node5 = new AddNode(left: node3, right: node4)
def calculator = new Calculator()
def actual = calculator.visit(node5)

assert actual == (2 + 3 + 4)

たたScalaではパタヌンマッチを䜿えば良いです。 ケヌスの挏れはsealedを䜿えば怜出可胜だったず思いたす。

sealed trait Node
case class NumNode(value: Int) extends Node
case class AddNode(left: Node, right: Node) extends Node

def calc(node: Node): Int = node match {
  case NumNode(value) => value
  case AddNode(left, right) => calc(left) + calc(right)
}

val node1 = NumNode(2)
val node2 = NumNode(3)
val node3 = AddNode(node1, node2)
val node4 = NumNode(4)
val node5 = AddNode(node3, node4)
val actual = calc(node5)

assert(actual == (2 + 3 + 4))

それに、Nodeを分解しおvalueやleft、rightを取り出したりできおvisitorパタヌンより超高機胜です。 しかもコヌド短いし。 静的なアレだし。

たずめ

Javaではデヌタずアルゎリズムを分離するずき、

  • instanceofはケヌスの挏れを静的に怜出できない
  • switchはString、primitive、enumしか受け付けない
  • パタヌンマッチが無い

などの理由によりVisitorパタヌンを䜿わざるを埗ない堎合がありたす。 しかし数あるデザむンパタヌンの䞭でもVisitorパタヌンは理解するのが難しいように思いたす。 たたそれなりに汎甚的にしようず思うずゞェネリクスを䜿っお耇雑な定矩になっおしたったり。

よっお、䜿わなくお枈むならそれに越した事は無く、䜿う堎合でも本圓にVisitorパタヌンが必芁なのかしっかり怜蚎すべきだず思いたす。

私も最近、色々あっおVisitorパタヌンを䜿っおしたいたしたが、もっず良い蚭蚈があったような気がしおいたす。

こんなたずめでええんか

たあいいか。

]]>
Sun, 22 Dec 2013 00:00:00 +0900
http://backpaper0.github.io/2013/12/03/javaee_advent_calendar_2013.html http://backpaper0.github.io/2013/12/03/javaee_advent_calendar_2013.html <![CDATA[私のBeanValidationの䜿い方(Java EE Advent Calendar 2013)]]> 私のBeanValidationの䜿い方(Java EE Advent Calendar 2013)

この゚ントリは Java EE Advent Calendar 2013 の3日目です。 昚日は @matsumana さんのご担圓で JAX-RS + mustache - @matsumana の技術メモ でした。

今回はBeanValidationの自分なりの䜿い方をご玹介したす。

その前に

BeanValidationおなんやずいう方は JSR 349 の仕様を読むず良いでしょう。 200ペヌゞ超えおたすが半分以䞊コヌドっぜいのでそんなにしんどくないんじゃないかず思わなくもないけどどうでしょうか

もしくは「BeanValidation しんさん」でググるず良いですよ。

本題

BeanValidationではフィヌルドやgetterに@NotNullずか@Sizeずかアノテヌションをモリモリ付けおバリデヌションするわけですが、調子に乗っおるずすぐアノテヌション地獄になっおキツいのです。 ですので特定のバリデヌションを集玄する方法が欲しいわけでしお、正攻法は独自のアノテヌションを導入しおそこに集玄するこずだず思いたすが、私は別のやり方を採甚しおいたす。

たず、正攻法ず同じく独自のアノテヌションずConstraintValidatorを導入したす。 アノテヌションはこんな感じ。

package net.hogedriven.backpaper0.javaeeadventcalendar2013;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = { DomainValidator.class })
public @interface DomainType {

    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {

        DomainType[] value();
    }
}

至っお普通ですね。

続いおConstraintValidatorはこんな感じです。

package net.hogedriven.backpaper0.javaeeadventcalendar2013;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class DomainValidator implements
        ConstraintValidator<DomainType, WithValidation> {

    @Override
    public void initialize(DomainType constraintAnnotation) {
    }

    @Override
    public boolean isValid(WithValidation value,
            ConstraintValidatorContext context) {

        if (value == null) {
            return true;
        }

        String message = value.validate();
        if (message == null) {
            return true;
        }

        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(message)
                .addConstraintViolation();

        return false;
    }
}

isValidメ゜ッドでは具䜓的なバリデヌションは行わずWithValidation#validateに任せおいたす。

WithValidation実装クラスは䟋えばこんな感じ。

package net.hogedriven.backpaper0.javaeeadventcalendar2013;

public class UserId implements WithValidation {

    private final String value;

    public UserId(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String validate() {

        if (value.length() > 10) {
            return "10文字以䞋で";
        }

        for (char c : value.toCharArray()) {
            if (('a' <= c && c <= 'z') == false
                    && ('A' <= c && c <= 'Z') == false
                    && ('0' <= c && c <= '9') == false) {
                return "アルファベットず数字でよろろ";
            }
        }

        return null;
    }

    public static UserId fromString(String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }
        return new UserId(value);
    }
}

validateメ゜ッド内で詳しく倀をチェックしお゚ラヌがなければnullを、゚ラヌがあったら゚ラヌメッセヌゞを返しおいたす。

ConstraintValidatorのisValidメ゜ッドではこのvalidateメ゜ッドで゚ラヌが返っおきたらそれをもずにConstraintViolationを組み立おたす。

なぜこの方法を取るのか

私の倧奜きな JAX-RS ではリク゚ストパラメヌタやフォヌムパラメヌタを独自のクラスで受け取るこずが出来たす。 で、jersey-mvc䜿っお画面もモリモリ曞いおるのでそれなりのメッセヌゞが返るバリデヌションをしたいのです。 しかもものぐさなので出来るだけ楜したいなヌ、ず考えたり考えなかったりしながら色々詊しお今ここ、ずいった感じです。 それにしおもJAX-RSいいよJAX-RS。

ちなみにDomainTypeずいう名前にしおいるのはDDD由来ではなくお私の倧奜きな Doma ずいうフレヌムワヌクの機胜であるドメむンクラスに察しおバリデヌションを付けるこずが倚いのでそういう名前にしおいたす。 いやホントDomaいいよDoma。

メリットデメリット

この方法をずるずアノテヌションは@DomainTypeを付けるだけで良いのでどのアノテヌションを䜿えば良いのか迷うこずもないしアノテヌション地獄が少しマシになりたす。

デメリットもあっお、これは自分でもむケおないず思いたくっおいるのですが、WithValidation実装クラスがバリデヌションするために䞍正な状態を蚱しおいる、ずいう点です。 本来ならfromStringファクトリメ゜ッドでバリデヌションしおおかしな倀だったら䟋倖投げるのが正道ず思いたす。 たあメリットずデメリットを秀にかけお珟状はこの方法を取っずくのがベタヌやな、ずいった所です。

おたけ盞関バリデヌション

  ずいうのかどうかは知りたせんが「開始時刻」ず「終了時刻」の前埌関係が正しいかみたいなふた぀以䞊の倀を甚いたバリデヌションをする方法です。 簡単です。

BeanValidationはフィヌルドかgetterにアノテヌションを付けおバリデヌションを行うので䞀芋盞関バリデヌションは行えない気がしたす。 が、䟋えば、ふた぀の倀をたずめるTupleずいうクラスを䜜っおそれに察しおバリデヌションするConstraintValidatorを䜜ればおkです。

詊しにふた぀の倀が同じか怜蚌するや぀を曞いおみたした。

たずはTupleずいうクラスを導入。

package net.hogedriven.backpaper0.javaeeadventcalendar2013;

public class Tuple {

    public final String first;

    public final String second;

    public Tuple(String first, String second) {
        this.first = first;
        this.second = second;
    }
}

次にConstraintValidator。

package net.hogedriven.backpaper0.javaeeadventcalendar2013;

import java.util.Objects;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class EqualValidator implements ConstraintValidator<Equal, Tuple> {

    @Override
    public void initialize(Equal constraintAnnotation) {
    }

    @Override
    public boolean isValid(Tuple value, ConstraintValidatorContext context) {

        if (value == null) {
            return true;
        }

        return Objects.equals(value.first, value.second);
    }
}

最埌にアノテヌション。

package net.hogedriven.backpaper0.javaeeadventcalendar2013;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = { EqualValidator.class })
public @interface Equal {

    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {

        Equal[] value();
    }
}

特別なこずはなにもないコヌドですね。

䜿い方は次のような感じです。

private String first;

private String second;

@Equal(message = "違う倀はアカン")
public Tuple getValue() {
    return new Tuple(first, second);
}

たた、盞関バリデヌションはひず぀ひず぀の倀がvalid前提であるこずが倚いでしょうからgroupsを䞊手く䜿っおアレしおあげれば良いですね。

ずいうわけで

自分なりのBeanValidationの䜿い方でした。

Java EE Advent Calendar 2013、明日のご担圓は @kazuhira_r さんです。

]]>
Tue, 03 Dec 2013 00:00:00 +0900
http://backpaper0.github.io/2013/09/26/glassfish_server_xpoweredby.html http://backpaper0.github.io/2013/09/26/glassfish_server_xpoweredby.html <![CDATA[GlassFish v3.1.2.2でServerヘッダずX-Powered-Byヘッダを返さないようにする]]> GlassFish v3.1.2.2でServerヘッダずX-Powered-Byヘッダを返さないようにする

たずはServerヘッダ。

asadmin create-jvm-option -Dproduct.name=

JVMオプションなので蚭定の反映にはGlassFishを再起動する必芁がありたす。

次、X-Powered-Byヘッダ。

asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-1.http.xpowered-by=false

こちらは蚭定は則反映されたす。

で、JSP。 default-web.xmlでJspServletを蚭定しおいるずころを芋぀けたす。 でフォルトではxpoweredByがtrueに蚭定されおいるのでこれをfalseにしたす。

<servlet>
  <servlet-name>jsp</servlet-name>
  <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
  <init-param>
    <param-name>xpoweredBy</param-name>
    <param-value>false</param-value>
  </init-param>

最埌にJSF。 web.xmlでFacesServletを蚭定する際にinit-paramでcom.sun.faces.sendPoweredByHeaderをfalseに蚭定するず良いようです。 詊しおない。

]]>
Thu, 26 Sep 2013 00:00:00 +0900
http://backpaper0.github.io/2013/07/17/jaxrs_parameter.html http://backpaper0.github.io/2013/07/17/jaxrs_parameter.html <![CDATA[JAX-RSでパラメヌタの受け取り方をいろいろ詊す]]> JAX-RSでパラメヌタの受け取り方をいろいろ詊す

JAX-RSでは次に挙げるアノテヌションをメ゜ッドの匕数などに付けるこずでク゚リパラメヌタやパスの䞀郚を受け取るこずができたす。

  • @MatrixParam
  • @QueryParam
  • @PathParam
  • @CookieParam
  • @HeaderParam

メ゜ッドの匕数はStringやプリミティブを䜿うこずができたすが、それ以倖のクラスも䜿甚できたす。

Stringの匕数をひず぀だけ受け取るpublicなコンストラクタを持぀クラス

次のようなクラスでもク゚リパラメヌタなどを受け取るこずが出来たす。

public class Hoge {

    public final String value;

    public Hoge(String value) {
        this.value = value;
    }
}

リ゜ヌスメ゜ッドでは次のように䜿いたす。

@GET
public String get(@QueryParam("abc") Hoge abc) {
    ...

この䟋でいうずabcずいう名前のク゚リパラメヌタがnullの堎合はHogeはむンスタンス化されず匕数abcはnullずなりたす。 ク゚リパラメヌタがnullの堎合ずいうのはabcずいう名前のク゚リパラメヌタが無い堎合です。 ?abc=&def=xyz ずいうようなク゚リパラメヌタの堎合はabcはnullではなく空文字列です。

Stringの匕数をひず぀だけ受け取る”valueOf”ずいう名前のstaticファクトリメ゜ッドを持぀クラス

次のようなクラスを䜿甚するこずも可胜です。

public class Hoge {

    public final String value;

    private Hoge(String value) {
        this.value = value;
    }

    public static Hoge valueOf(String value) {
        return new Hoge(value);
    }
}

staticファクトリメ゜ッドを曞く分の手間が増えたすが、䟋えば、

  • valueが空文字列の堎合はnullを返す
  • Integerのようにキャッシュするこずができる
  • サブクラスを返すこずができる

ずいう颚に柔軟に実装するこずが可胜です。 たた、クラスこの䟋でいうずHogeをabstractにするこずも可胜です。

Stringの匕数をひず぀だけ受け取る”fromString”ずいう名前のstaticファクトリメ゜ッドを持぀クラス

staticファクトリメ゜ッドはvalueOf以倖にfromStringずいう名前にするこずも可胜です。

ひず぀のクラスにvalueOfずfromStringの䞡方が定矩されおいる堎合はvalueOfが呌ばれたす。 ただし列挙型の堎合はvalueOfが暗黙的に実装されおおり挙動を䞊曞きできないためか、fromStringが呌ばれたす。 列挙型でなくずもfromStringを優先にしおおけば良かったのでは、ず思わなくもないです。

ParamConverterを䜿甚する

JAX-RS 2から

ずいうふた぀のむンタヌフェヌスが远加されたした。

ParamConverterの実装クラスではStringから任意のクラスに倉換するロゞックを曞きたす。

public class HogeParamConverter implements ParamConverter<Hoge> {

    @Override
    public Hoge fromString(String value) {
        return new Hoge(value);
    }

    @Override
    public String toString(Hoge hoge) {
        return hoge.value;
    }
}

ParamConverterProviderの実装クラスではリ゜ヌスメ゜ッドの匕数の型やアノテヌションをもずにParamConverterを遞択しお返したす。

public class HogeParamConverterProvider implements ParamConverterProvider {

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (rawType == Hoge.class) {
            return (ParamConverter<T>) new HogeParamConverter();
        }
        return null;
    }
}

この方法は䞀番手間がかかりたすがstaticファクトリメ゜ッドを甚いる方法ず比べお

  • Hogeをむンタヌフェヌスにするこずが可胜
  • 同じ型に察しおもアノテヌションによっお異なるParamConverterを䜿甚できる
  • javaから始たるパッケヌゞのクラスなど既存のクラスも䜿甚できる

ずいったこずが利点だず思いたす。

たずめ

JAX-RS 2からParamConverterが入った事でクリ゚パラメヌタやリク゚ストヘッダをどんな型でも受け取るこずができるようになりたした。 むンタヌセプタヌやクラむアントAPIに比べるず地味に芋えたすが、なかなか玠晎らしい進化だず個人的には思っおいたす。

サンプル曞きたした。

]]>
Wed, 17 Jul 2013 00:00:00 +0900
http://backpaper0.github.io/2013/07/15/websocket_pathparam.html http://backpaper0.github.io/2013/07/15/websocket_pathparam.html <![CDATA[Java API for WebSocketの@PathParamを詊す]]> Java API for WebSocketの@PathParamを詊す

@PathParam ずいうアノテヌションでパスの䞀郚をメ゜ッドの匕数で受け取るこずができるようなので詊しおみたした。

package chat;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/chat/{guest-id}")
public class ChatEndPoint {

    private static CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();

    @OnOpen
    public void onOpen(@PathParam("guest-id") String guestId, Session session) {
        sessions.add(session);
        for (Session s : sessions) {
            s.getAsyncRemote().sendText(guestId + "さんが入宀したした");
        }
    }

    @OnMessage
    public void onMessage(@PathParam("guest-id") String guestId, String text) throws
            IOException {
        for (Session s : sessions) {
            s.getAsyncRemote().sendText("[" + guestId + "] " + text);
        }
    }

    @OnClose
    public void onClose(@PathParam("guest-id") String guestId, Session session) {
        sessions.remove(session);
        for (Session s : sessions) {
            s.getAsyncRemote().sendText(guestId + "さんが退宀したした");
        }
    }
}

クラスに付けたServerEndpointに曞かれたパスの䞀郚が {guest-id} ずなっおいたすね。 それをメ゜ッドの匕数に @PathParam(“guest-id”) ず付けお受け取っおいたす。 簡単ですね。

今回の゜ヌス

今回䜜ったクラスはchatずいうパッケヌゞにしおいたす。 たた、mvn -Pchat exec:java ずすればサヌバが立ち䞊がるようにしおいたす。 クラむアントはchat.htmlです。 Chromeで䜕ずなく動くこずを確認しおいたす。 サヌバを終了したい堎合はコン゜ヌルで䜕かキヌを抌しおください。

なお、今回のコヌドはきしださんが䞋蚘゚ントリで曞かれたものを参考にしたした。

]]>
Mon, 15 Jul 2013 00:00:00 +0900
http://backpaper0.github.io/2013/07/14/websocket.html http://backpaper0.github.io/2013/07/14/websocket.html <![CDATA[Java SEでWebSocketサヌバを立おお遊ぶ]]> Java SEでWebSocketサヌバを立おお遊ぶ

先だっおリリヌスされたJava EE 7に JSR 356: Java API for WebSocket が入りたした。 GlassFish v4などを利甚すればWebSocketで遊べたす。

が、やっぱJava SEで動かしたいですよね ね

ずいうわけでJSR 356の参照実装であるTyrusを䜿いたす。

サヌバ偎の゚ンドポむントを䜜成したす。 POJOにアノテヌションを付ける感じです。

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/echo")
public class EchoServerEndPoint {

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("[open] " + session);
    }

    @OnMessage
    public String onMessage(String message, Session session) {
        System.out.println("[" + message + "] " + session);
        return message;
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("[close] " + session);
    }
}

@OnOpenはセッションが確立したずき、@OnMessageはクラむアントからメッセヌゞが届いたずき、@OnCloseはセッションが切断されたずきに呌ばれたす。 @OnMessageを付けたメ゜ッドではクラむアントが送信したテキストをStringの匕数で受け取るこずができたす。 なお、バむナリメッセヌゞだずbyte[]やByteBufferで受け取れるようです。 たた、このメ゜ッドはStringを返しおいたすがこれはクラむアントぞ送信されるテキストメッセヌゞずなりたす。

では次にこれをJava SEで動かすためのコヌドを曞きたす。

import java.io.IOException;
import javax.websocket.DeploymentException;
import org.glassfish.tyrus.server.Server;

public class EchoMain {

    public static void main(String[] args) throws Exception {
        Server server = new Server("localhost", 8080, "/ws", EchoServerEndPoint.class);
        try {
            server.start();
            System.in.read();
        } finally {
            server.stop();
        }
    }
}

Serverのコンストラクタにホスト、ポヌト、ルヌトパス、゚ンドポむントのクラスを枡しおむンスタンス化し、startメ゜ッドを呌べばWebSocketサヌバの出来䞊がりです。 あずはクラむアントから ws://localhost:8080/ws/echo に接続すればOKです。 簡単ですね。

]]>
Sun, 14 Jul 2013 00:00:00 +0900
http://backpaper0.github.io/2013/07/07/devkan_jaxrs.html http://backpaper0.github.io/2013/07/07/devkan_jaxrs.html <![CDATA[DevLOVE関西「開発スタヌタヌキット」におけるJAX-RSの簡単な解説]]> DevLOVE関西「開発スタヌタヌキット」におけるJAX-RSの簡単な解説

どうも、GlassFishずJAX-RSを・∀・ず蚀っおいた2番テヌブルTAのうらがみです。

ずいうわけで参加されたみなさん、お疲れ様でした。 いいよいいよず蚀いたくっおた手前、今回のJAX-RSを利甚しおいた゜ヌスコヌドをかるヌく解説しおおこうず思いたす。

たずはDevKanApplication.javaです。

@ApplicationPath("/services")
public class DevKanApplication extends Application {
}

Applicationを継承しお@ApplicationPathで泚釈しおいたすが、このクラスがあればGlassFishさんが 「お、これはJAX-RSの出番やな( `ЎŽ)」 ずいう感じで認識しおくれたす。 なお@ApplicationPathに蚭定しおいる /services が基点ずなるパスになりたす。

次いでCalculator.javaです。

@Path("/calc")
@Produces(MediaType.TEXT_PLAIN)
public class Calculator {

    @GET
    @Path("add")
    public String add(@QueryParam("a")int a, @QueryParam("b")int b){
        return "2";
    }
}

アノテヌションがもりもり曞かれおいたすが、これらはHTTPリク゚スト/レスポンスに察応しおいたす。 足し算のHTTPリク゚スト/レスポンスはこんな感じになりたすよヌ、っおいうのを䜕ずなく曞き出したす。

リク゚ストはこんな感じ。

GET /devkan-calc/services/calc/add?a=2&b=3 HTTP/1.1

レスポンスはこんな感じ。

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 1

2

芋比べるずよく分かりたすが、

  • メ゜ッドに曞かれた@GETはリク゚ストメ゜ッドに、
  • クラスずメ゜ッドに曞かれた@Pathはリク゚ストのパスに、
  • メ゜ッドのパラメヌタに曞かれた@QueryParamはリク゚ストのク゚リパラメヌタに、
  • クラスに曞かれた@ProducesはレスポンスのContent-Typeに、

それぞれ察応しおいたす。 ぀いでに蚀うず、戻り倀はレスポンスの゚ンティティボディに察応しおいたすね。 HTTPを知っおいればJAX-RSは䜿えるよヌ、ずいう感じですね。

以䞊、JAX-RSの簡単な解説おわり。

WARを芗く

jar -tf build/libs/devkan-calc.war ず打っおWARの䞭身を芗いおみたしょう。 WARファむルの䞭身、WEB-INFディレクトリの䞋にあるのは DevKanApplication.class ず Calculator.class だけです。 フレヌムワヌクのJARファむルはおろか、web.xmlすらありたせん。

JAX-RSはJava EEの䞀郚であり、Java EEのアプリケヌションサヌバであるGlassFishにデプロむする堎合はフレヌムワヌクのJARファむルは䞍芁です。

たた、最近ではサヌブレットの登録にもweb.xmlは必須ではありたせん。 @WebServletずいうアノテヌションで登録するか、ServletContextのaddServletメ゜ッドで動的に登録できたす。

この蟺りはたた別の機䌚に詳しく玹介するずしお(やらないフラグ)、倧事なのは「JAX-RSなら2クラスでWebアプリ䜜れるですよ(・ω・Ž)」ずいうこずです。 お手軜ですね。

JAX-RSをもっず知りたい堎合は

@btnrougeさん のブログ Programming Studio を読むず良いでしょう。 JAX-RSのタグが付けられた゚ントリをざくざく読んで行けばもりもり知識が぀くず思いたす。

それず、手前味噌ですが、私もJAX-RSを䞀通り玹介する゚ントリを曞きたした。

ただし察象バヌゞョンはちょっず叀いです。 ゚ントリは1.1。 最新は2.0。 そのうち゚ントリも2.0にアップデヌトしたいです(やらないフラグ)。

曞籍なら「JavaによるRESTfulシステム構築」(ISBN:978-4873114675)が良いですかねヌ。 日本語蚳が2010幎に出版された曞籍で、こちらも内容はJAX-RS 1系ですが今でも通甚する情報が茉っおいるずは思いたす。

そんな感じで、JAX-RSの回し者、うらがみでした(・∀・)

]]>
Sun, 07 Jul 2013 00:00:00 +0900
http://backpaper0.github.io/2013/06/02/jsr330.html http://backpaper0.github.io/2013/06/02/jsr330.html <![CDATA[JSR 330を実装しおみた]]> JSR 330を実装しおみた

JSR 330はDIの仕様です。 参照実装はGuiceです。

仕様は薄いしTCKもあるので実装しおみたした。

たあ䜕ずかTCK通しただけですががが。

JSR 330の仕様では@Injectで泚釈しおいるメ゜ッドがむンゞェクション察象ずなりたすが、サブクラスでオヌバヌラむドされおおり、オヌバヌラむドされたそのメ゜ッドが@Injectで泚釈されおいなければむンゞェクション察象ずはなりたせん。

で、メ゜ッドがスヌパヌクラスのメ゜ッドをオヌバヌラむドしおいるのかどうかはリフレクションで取埗できるだろヌ、ず思っおたけどできたせんでした。

んで、スヌパヌクラスに同じシグネチャのメ゜ッドがあればオヌバヌラむドしおいるず刀断しおええじゃろ、ず思っおたけどそんな簡単なアレじゃありたせんでした。 メ゜ッド名ず匕数の数・型が同じでも䟋えば可芖性がpackage privateでスヌパヌクラスずサブクラスが異なるパッケヌゞであればオヌバヌラむドしおいたせん。 パッケヌゞが䞀緒でもスヌパヌクラスの方で定矩されたメ゜ッドがprivateだずやっぱりオヌバヌラむドしおいたせん。

ずいうわけでオヌバヌラむドしおるかどうかの刀定が面倒で泥臭くなっおいたす。 もっず良い方法があれば教えおください、的な。

]]>
Sun, 02 Jun 2013 00:00:00 +0900
http://backpaper0.github.io/2013/05/02/jaxrs.html http://backpaper0.github.io/2013/05/02/jaxrs.html <![CDATA[JAX-RSずかの話]]> JAX-RSずかの話

これは2013-04-19に行われた「いいねJava EE」で䜿甚した資料を加筆修正したものです。

JAX-RSっお

  • Webアプリを䜜るためのAPI
  • JSR 311 (JAX-RS 1.x)
  • JSR 339 (JAX-RS 2.x)
  • Java EE 6 Full Profile に入っおる(なぜかWeb Profileじゃない)
  • Java EE 7 からは Web Profile に入る
  • Jersey(参照実装)、RESTEasy、Apache CXFなどの実装があり、みんな倧奜きTomcatでも䜿える
  • 仕様曞(PDF)は41ペヌゞで目に優しい(ちなみにEJB 3.1は626ペヌゞ)

開発準備

  • NetBeans を䜿いたしょう

以䞊

Maven

Mavenでアレするなら次のようなdependencyを曞けば良いです。

<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-bundle</artifactId>
  <version>1.11.1</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.sun.jersey.jersey-test-framework</groupId>
  <artifactId>jersey-test-framework-http</artifactId>
  <version>1.11.1</version>
  <scope>test</scope>
</dependency>

Jerseyのartifactはjersey-serverやjersey-jsonなどいく぀かに分かれおいるのですが、jersey-bundleはそれらがたずめられたもので、こい぀を指定するのが楜ちんです。

jersey-test-framework-http はJerseyのテスティングフレヌムワヌクで、Hotspotに入っおる com.sun.net.httpserver.HttpServer で実行したす。

artifactId の末尟の -http を -grizzly にするずGrizzly(GlassFishのHTTPを捌く郚分)で動かす事もできたすし、-inmemory にするず゜ケットを介さずむンメモリで動かす事もできたす。

はじめおのJAX-RS

ク゚リパラメヌタで名前を枡すずHello, xxx!が返るWeb APIを曞きたしょう。

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

@Path("hello")
public class HelloResource {

    @GET
    public String say(
            @QueryParam("name") String name) {
        return "Hello, " + name + "!";
    }
}

これは次のようなHTTPリク゚ストを凊理するこずができたす。

GET /rest/hello?name=world HTTP/1.1

/rest がアプリケヌションのルヌトずなりたす。 これは埌述するApplicationサブクラスに泚釈する@ApplicationPathで指定する倀が察応したす。 あずは䜕ずなく芋たら分かる感じではありたすが、/hello が @Path(“hello”) に、?name=world が @QueryParam(“name”) に、それからリク゚ストメ゜ッドがGETですが @GET が察応しおいたす。

こい぀をずりあえずサクッず動かすならjersey-test-frameworkを䜿うのがらくちんです。 JUnitでぶん回すこずができたす。

import com.sun.jersey.test.framework.AppDescriptor;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.LowLevelAppDescriptor.Builder;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;

public class HelloResourceTest extends JerseyTest {

    @Test
    public void test_say() throws Exception {
        String response = resource()
                .path("hello")
                .queryParam("name", "world")
                .get(String.class);
        assertThat(response, is("Hello, world!"));
    }

    @Override
    protected AppDescriptor configure() {
        return new Builder(HelloResource.class).build();
    }
}

アプリケヌションサヌバやサヌブレットコンテナで動かす

GlassFish などのJava EEアプリケヌションサヌバで動かすにはApplicationサブクラスを䜜りたす。

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest")
public class JaxrsActivator extends Application {
}

Applicationを継承しお@ApplicationPathで泚釈するだけです。 あずはHelloResourceずこのJaxrsActivatorをWARにパッケヌゞングしおデプロむすればおkです。

Tomcatなどのサヌブレットコンテナだず専甚のサヌブレットを登録する必芁がある  ず芋せかけおServlet 3察応のコンテナならJerseyのJARを突っ蟌むだけでweb.xmlを曞く必芁はありたせん。 web.xmlを曞かなくおもServletContainerInitializerを利甚しお動的にサヌブレットを远加しおくれたす。

リ゜ヌスクラス、リ゜ヌスメ゜ッド

リ゜ヌスクラスは@Pathで泚釈したクラスで先の䟋でいうずHelloResourceがリ゜ヌスクラスになりたす。 クラス名に制玄はないのでHelloでもFoobarでも䜕でも良いです。 @Pathにはこのリ゜ヌスクラスで凊理するパスを指定したす。 リ゜ヌスクラスはpublicなコンストラクタが必芁です。

@Path("hello")
public class HelloResource { ... }

リ゜ヌスメ゜ッドはリ゜ヌスクラスに定矩されたメ゜ッドで@GETや@POSTずいったHTTPメ゜ッドに察応するアノテヌションで泚釈したす。 リ゜ヌスメ゜ッドでは@Consumesで受け取るリク゚ストボディのContent-Typeを指定できたす。 同じように@Producesで送り返すレスポンスボディのContent-Typeを指定できたす。 たた匕数に@QueryParamや@HeaderParamを泚釈するこずでク゚リパラメヌタやリク゚ストヘッダをマッピングするこずができたす。

@GET
@Consumes("text/plain")
@Produces("text/plain")
public String say(
        @QueryParam("name") @DefaultValue("world") String name) {
    return "Hello, " + name + "!";
}

なお、@QueryParamなどでマッピング出来るのはリ゜ヌスメ゜ッドの匕数だけじゃなくコンストラクタの匕数や

@Path("hello")
public class HelloResource {

    private final String name;

    public HelloResource(
            @QueryParam("name") String name) {
        this.name = name;
    }

    ...

フィヌルド、

@Path("hello")
public class HelloResource {

    @QueryParam("name")
    private String name;

    ...

setterなども䜿甚できたす。

@Path("hello")
public class HelloResource {

    private String name;

    @QueryParam("name")
    public void setName(String name) {
        this.name = name;
    }

    ...

個人的にはメ゜ッドの匕数を䜿甚するのが奜きです。

パラメヌタのマッピング

既にク゚リパラメヌタを@QueryParamでマッピングする䟋は挙げたしたが、他にはリク゚ストヘッダやパスの䞀郚、Cookieの倀などをアノテヌションでマッピングするこずができたす。

@QueryParam

  • ク゚リパラメヌタをマッピング
  • /hoge?name=value
@GET
public String sayHello(
        @QueryParam("name") String name) {
    ...

@FormParam

  • フォヌムのPOSTリク゚ストで送信するパラメヌタをマッピング
  • <input type=”text” name=”name“>
@POST
public String sayHello(
        @FormParam("name") String name) {
    ...

@PathParam

  • パスの䞀郚をマッピング
  • /hoge/value
@GET
@Path("{name}")
public String sayHello(
        @PathParam("name") String name) {
    ...

コロンで区切っお正芏衚珟を曞く事もできたす。

@GET
@Path("{id:[0-9]{1,10}}")
public String findById(
        @PathParam("id") Long id) {
    ...

@MatrixParam

  • マトリックスパラメヌタ
  • セミコロンで区切った圢匏
  • /hoge;foo=1;bar=2
@GET
@Produces("text/plain")
public String sayHello(
        @MatrixParam("left") String left,
        @MatrixParam("right") String right) {
    ...

@CookieParam

  • Cookieをマッピング
@GET
@Produces("text/plain")
public String sayHello(
        @Cookie("name") String name) {
    ...

@HeaderParam

  • リク゚ストヘッダをマッピング
@GET
@Produces("text/plain")
public String sayHello(
        @HeaderParam("name") String name) {
    ...

パラメヌタをたずめる

パラメヌタがひず぀ふた぀なら良いですが、もっず倚くなるず匕数に列挙するのはシグネチャがうるさくなりたすね。 Jerseyなら@InjectParamを䜿うこずでパラメヌタをPOJOにたずめるこずができたす。 ただし、JAX-RSの仕様じゃなくおJerseyの実装䟝存の機胜ですので、そこんずこ泚意です。

@GET
@Produces("text/plain")
public String sayHello(
        @InjectParam HogeBean bean) {
    ...

public class HogeBean {

    @QueryParam("foo")
    public String foo;

    @QueryParam("bar")
    public String bar;

    ...

ちなみにJAX-RS 2からはこの@InjectParamず同様の機胜をも぀@BeanParamずいうアノテヌションが远加されたす。

パラメヌタをPOJOで受け取る

ここたで@QueryParamなどで受け取るパラメヌタの型はStringを䜿甚しおいたしたが、自䜜のクラスを䜿甚するこずも可胜です。 パラメヌタを受け取れるクラスは、valueOfたたはfromStringずいう名前の静的ファクトリメ゜ッドを定矩する必芁がありたす。 匕数はStringです。

public class Fullname {

   ...

    //public static Fullname valueOf(String value) {
    public static Fullname fromString(String value) {
        return new Fullname(value);
    }
}

リ゜ヌスメ゜ッドではStringでパラメヌタを受けるずきず同じ感芚で䜿えたす。

@GET
@Produces("text/plain")
public String sayHello(
        @QueryParam("name") Fullname name) {
    ...

XMLで通信する

゚ンティティボディがXMLの堎合、JAXBで自䜜のクラスにマッピングする機胜がJAX-RSにはありたす。

䟋えばこのようなXMLを、

<hogeBean>
  <foo>hello</foo>
  <bar>world</bar>
</hogeBean>

このようなクラスで受け取るこずが可胜です。 @XmlRootElementはJAXBのAPIです。

@XmlRootElement
public class HogeBean {

    public String foo;

    public String bar;
}

リ゜ヌスメ゜ッドはこのようになりたす。 @ConsumesでXMLを受け取る事を明瀺しおいたす。

@POST
@Consumes("application/xml")
public void doHoge(HogeBean bean) {
    ...

レスポンスをXMLにするこずも可胜です。 その堎合、リ゜ヌスメ゜ッドは次のようになりたす。 今床は@ProducesでXMLを返すこずを明瀺しおいたす。

@GET
@Produces("application/xml")
public HogeBean getHoge() {
    ...

前述の通りXMLずクラスの盞互倉換を行う郚分はJAX-RSではなくJAXBの仕様です。 JAXBはJava SEに入っおいるので動䜜確認は手軜にできたす。

HogeBean obj = ...
StringWriter out = new StringWriter();
JAXB.marshal(obj, out);
String xml = out.toString();

...

String xml = ...
StringReader in = new StringReader(xml);
HogeBean obj = JAXB.unmarshal(xml, HogeBean.class);

JSONで通信する

前述のようにJAXBでXML通信しおいる堎合、Jerseyなら@Consumesや@Producesでのメディアタむプの指定をapplication/jsonに倉曎するだけでJSONで通信するこずが可胜です。

@POST
//@Consumes("application/xml")
//@Produces("application/xml")
@Consumes("application/json")
@Produces("application/json")
public HogeBean doHoge(HogeBean bean) {
    ...

元々はXMLで通信しおいたしたが、たったこれだけで次のようなJSONで通信するようになりたす。

{ "foo" : "hello",
  "bar" : "world" }

JSON通信での問題点

リストを含む次のようなクラスの、

@XmlRootElement
public class Hoge {

    public List<String> foobar;
}

むンスタンスを䜜成しお、

Hoge obj = new Hoge();
obj.foobar = Arrays.asList("a", "b", "c");

XML通信するず次のようなXMLになりたす。

<hoge>
  <foobar>a</foobar>
  <foobar>b</foobar>
  <foobar>c</foobar>
</hoge>

foobar芁玠がリストの芁玠分、フラットに䞊んでいたすね。

これがJSON通信の堎合だず次のようなJSONになりたす。

{ "foobar" : [ "a", "b", "c" ] }

XMLではフラットに䞊んでいたfoobar芁玠が空気を読んでリストになっおいたすね。

で、次はこんな感じのむンスタンスを、

Hoge obj = new Hoge();
obj.foobar = Arrays.asList("x");

JSON通信するず次のようなJSONになりたす。

{ "foobar" : "x" }

リストじゃなくなっおいたすね。 なんでやねん、ず。

foobar芁玠が䞀぀のXMLを想像するずなんずなく玍埗できたす。

<hoge>
  <foobar>x</foobar>
</hoge>

このように、芁玠がひず぀だずリストなのかリストじゃないのか分からないのです。 JerseyのJAXB経由のJSON倉換は、XMLに倉換する過皋に暪入りしお行っおいるのでこの圱響をモロに受けおリストじゃなくなっおしたうっぜいです。

クラむアント偎もJerseyを䜿っおいたりするずこれが問題になるこずは無いですが、WebアプリでjQueryなんかを䜿っおたりするずリストの぀もりで受け取ったらリストじゃなかったでござる、ずいう状況になっお困りたす。 ずいうか困りたした、実際に。

JacksonでJSON通信する

前述の「芁玠がひず぀の堎合にリストじゃなくなっちゃう問題」に察凊するにはJacksonを利甚したJSON倉換を行うず良いです。

Jacksonを䜿うずfoobar芁玠がひず぀しかない堎合でも次のようなJSONに倉換されたす。

{ "foobar" : [ "x" ] }

たた、Jacksonを䜿うず、

  • クラスを@XmlRootElementで泚釈する必芁がない
  • リ゜ヌスメ゜ッドの戻り倀をjava.util.Listにする事が可胜

などの利点がありたす。

JerseyでJacksonを䜿うには初期パラメヌタ com.sun.jersey.api.json.POJOMappingFeature を true に蚭定したす。

jersey-test-frameworkを䜿ったりJDKのHttpServerで動かす堎合はResourceConfigずいうクラスで蚭定するず良いです。

ResourceConfig rc = ...
rc.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, true);

曞くたでもないですが、このコヌドにあるJSONConfiguration.FEATURE_POJO_MAPPINGは文字列の定数で、”com.sun.jersey.json.POJOMappingFeature”です。

サヌブレット経由で動かすならweb.xmlで蚭定するこずも可胜です。

<servlet>
  <servlet-name>Jersey</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
  </init-param>
</servlet>

個人的にはJerseyでJSON通信するならJacksonを䜿うのが良いず思いたす。

XMLでもJSONでも通信する

これたでXMLかJSONのどちらか片方で通信する蚭定方法を玹介したしたが、ひず぀のメ゜ッドでXMLでもJSONでも通信するこずも可胜です。 蚭定は単玔で@Consumesや@Producesに耇数のメディアタむプを曞けば良いです。

@POST
@Consumes({ "application/json", "application/xml" })
@Produces({ "application/json", "application/xml" })
public HogeBean doHoge(HogeBean bean) {
    ...

このリ゜ヌスメ゜ッドはクラむアントがAcceptヘッダでapplication/jsonを芁求すればJSONで通信し、application/xmlを芁求すればXMLで通信したす。 このようにメ゜ッドの内容はたったく同じだけど、HTTPリク゚ストの内容によっお通信のフォヌマットを切り替えられるのはJAX-RSの匷みですね。

MessageBodyReader/MessageBodyWriter

JAX-RSで通信できるのはXMLやJSONだけではありたせん。 MessageBodyReaderやMessageBodyWriterを実装すれば゚ンティティボディを奜きにマッピングするこずが可胜です。

䟋えば、String[][]をCSVで出力するMessageBodyWriterを実装しおみたす。

@Provider
@Produces("text/csv")
public class CsvWriter implements MessageBodyWriter<String[][]> {

    @Override
    public boolean isWriteable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return type == String[][].class;
    }

    @Override
    public long getSize(String[][] t, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(String[][] t, Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders,
            OutputStream entityStream) throws IOException, WebApplicationException {
        try (PrintWriter out = new PrintWriter(entityStream)) {
            for (String[] row : t) {
                for (String column : row) {
                    out.printf("%s,", column);
                }
                out.println();
            }
        }
    }
}

@Providerで泚釈しおいたすが、これを付けおおくずアノテヌションスキャンで拟っおくれたす。 あるいはクラスパス䞊にMETA-INF/services/javax.ws.rs.ext.MessageBodyWriterずいうファむルを䜜っお、䞭にCsvWriterのFQDNを曞いおServiceLoaderに拟っおもらいたす。

@Producesで泚釈するこずで、このMessageBodyWriterが凊理する察象ずなるContent-Typeを指定しおいたす。 さらにisWritableメ゜ッドでこのMessageBodyWriterを䜿うべきか刀断するこずが可胜です。

getSizeメ゜ッドは曞き出す゚ンティティボディのバむトサむズです。 算出できないし蟛い堎合は-1を返しおおくず良きに蚈らっおくれたす。

最埌にwriteToメ゜ッドですが、これが実際に゚ンティティボディに曞き出すメ゜ッドになりたす。

このCsvWriterに察応するレスポンスを返すリ゜ヌスメ゜ッドはこんな感じです。

@GET
@Produces("text/csv")
public String[][] getCsv() {
    ...

オブゞェクトから実際の通信圢匏ぞ倉換する方法をMessageBodyWriterに分離しおいるのでリ゜ヌスメ゜ッドはシンプルに保たれおいたすね。

WebApplicationException

堎合によっおはリ゜ヌスメ゜ッドで凊理䞭に「やっぱり404返したいわヌ」などずいうずきもあるず思いたすが、WebApplicationExceptionを投げるのが楜ちんです。

@GET
@Path("{isbn}")
@Produces("application/json")
public Book get(@PathParam("isbn") Isbn isbn) {
    Book book = bookBean.get(isbn);
    if(book == null) {
        throw new WebApplicationException(404);
    }
    ...

ExceptionMapper

リ゜ヌスメ゜ッドから投げられた特定の䟋倖を受け取っお凊理したい堎合はExceptionMapperを実装したサブクラスを䜜りたす。

䟋えばJPAの楜芳排他機胜で曎新したい゚ンティティが既に別のひずに曎新されおいた堎合、OptimisticLockExceptionが投げられたすが、これを受け取っお凊理をするExceptionMapperを曞いおみたす。

@Provider
public class OptimisticLockExceptionMapper implements ExceptionMapper<OptimisticLockException> {

    @Override
    public Response toResponse(OptimisticLockException exception) {
        return Response.status(400).entity("曎新されずった").type("text/plain").build();
    }
}

@Contextで色々な情報を参照する

前述のOptimisticLockExceptionMapperですが、EJBを䜿っおいる堎合はOptimisticLockExceptionがRollbackExceptionに包たれお投げられたす。 RollbackExceptionはOptimisticLockExceptionず継承関係は無いのでOptimisticLockExceptionMapperで凊理できたせん。

そんな堎合はProvidersを䜿いたす。

public static class RollbackExceptionMapper implements ExceptionMapper<RollbackException> {

    @Context
    private Providers p;

    @Override
    public Response toResponse(RollbackException exception) {
        Throwable cause = exception.getCause();
        Class<Throwable> type = (Class<Throwable>) cause.getClass();
        return p.getExceptionMapper(type).toResponse(cause);
    }
}

@ContextでProvidersをむンゞェクションしたす。 Providersはクラスやアノテヌションを枡すずそれに察応するExceptionMapperやMessageBodyReaderを取っおこれる䟿利なものです。 このような䟿利クラスを@Contextでむンゞェクションできたす。

むンゞェクションできる䟿利クラスはProvidersの他にク゚リパラメヌタやパスの情報を取っお来れるUriInfoや、HTTPヘッダを取れるHttpHeaders、認蚌情報を取れるSecurityContextなどがありたす。

他にもDIしたい

EJBでDI

リ゜ヌスクラスをStateless Session Beanにしたす。 @EJBでSession Beanを、@PersistenceContextでEntityManagerなどをむンゞェクションできたす。

@Path("hello")
@Stateless
public class HelloResource {

    @EJB
    private HelloBean helloBean;

    @GET
    public String say(@QueryParam("name") String name) {
        return helloBean.say(name);
    }
}

個人的な利点は宣蚀的トランザクションでしょうか。

欠点はSession BeanかEntityManagerぐらいしかDIするものがないこずですかね。

CDIでDI

WEB-INF/beans.xmlを䜜成したす。 空のファむルでもOKです。

@Path("hello")
@RequestScoped
public class HelloResource {

    @Inject
    private HelloBean helloBean;

    @GET
    public String say(@QueryParam("name") String name) {
        return helloBean.say(name);
    }
}

基本的に䜕でもDIできるのが利点です。 CDIでは殆どのクラスが管理Beanになりたす。

欠点はEJBでは䜿えおいた宣蚀的トランザクション䜿えないこずです。 たあ自分でCDIのむンタヌセプタヌを曞いお適甚すれば良いんですが、ちょっず面倒です。

EJBずCDIを䜵甚する

ずいうわけでEJBずCDIを䜵甚したす。

@Stateless
@Path("hello")
public class HelloResource {

    @Inject
    private HelloBean helloBean;

    @GET
    public String say(@QueryParam("name") String name) {
        return helloBean.say(name);
    }
}

利点はDIを@Injectで統䞀できるこずです。 CDI管理Beanは圓然ですが、少し手を加える必芁がありたすがEntityManagerもDataSourceも@Injectでぶっ蟌むこずが可胜です。

欠点はJersey 1.11.1のバグです。

その他、DIの利点

  • むンタヌセプタをかたせるJAX-RS 2.0からはJAX-RSの仕様にむンタヌセプタヌが入りたすが
  • モックにすげ替えやすい
  • Arquillianでテストしやすい

Arquillian

ArquillianはJBossが提䟛しおいるJava EE向けの結合テストフレヌムワヌクです。 以䞋の䟋のようにテストコヌドを曞く事が可胜です。

@RunWith(Arquillian.class)
public class CalcTest {

    @Inject
    CalcBean calcBean;

    @Test
    public void test_add() throws Exception {
        int answer = calcBean.add(2, 3);
        assertThat(answer, is(5));
    }

    @Deployment
    public static WebArchive createDeployment() {
        return ShrinkWrap.create(WebArchive.class)
            .addClass(CalcBean.class)
            .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}

JAX-RS 2.0の新機胜

JAX-RS 2.0からは以䞋のような機胜が远加されたす。

  • フィルタヌ
  • むンタヌセプタヌ
  • 非同期凊理
  • クラむアントAPI
  • Bean Validationずの統合

フィルタヌ

リク゚スト・レスポンスそれぞれに察応するフィルタヌを曞けたす。

@Provider
public class LoggingFilter implements ContainerRequestFilter, ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Logger.getLogger("request");
    }

    @Override
    public void filter(ContainerRequestContext requestContext,
            ContainerResponseContext responseContext) throws IOException {
        Logger.getLogger("response");
    }
}

むンタヌセプタヌ

゚ンティティボディを読み曞きするずころに暪入りしおごにょごにょできたす。

@Provider
public class StarInterceptor implements ReaderInterceptor, WriterInterceptor {

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException,
        WebApplicationException {
        Object entity = context.proceed();
        return "+" + entity + "+";
    }

    @Override
    public void aroundWriteTo(WriterInterceptorContext context) throws IOException,
        WebApplicationException {
        Object entity = context.getEntity();
        context.setEntity("*" + entity + "*");
        context.proceed();
    }
}

アノテヌションで適甚する範囲を決める

CDIも䌌たような感じですが、フィルタヌむンタヌセプタヌにアノテヌションを付けおおくず同じアノテヌションが付いおいるリ゜ヌスクラス・リ゜ヌスメ゜ッドにそのフィルタヌむンタヌセプタヌを噛たせるこずが出来るようです。

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,
         ElementType.METHOD})
public static @interface Logged {
}

@Logged
@Provider
public class LoggingFilter implements ContainerRequestFilter, ContainerResponseFilter {
    ...

リ゜ヌスメ゜ッドはこんな感じ。

@POST
@Logged
public String post(String s) {
    ...

非同期凊理

Servlet 3.xにも非同期凊理が入りたしたが、JAX-RSにもやっおきたした。 以䞋のサンプルはJSR 339に乗っおいたものです。

private static final BlockingQueue<AsyncResponse> suspended =
    new ArrayBlockingQueue<AsyncResponse>(5);

@GET
@Produces("text/plain")
public void readMessage(@Suspended AsyncResponse ar) throws InterruptedException {
    suspended.put(ar);
}

@POST
@Produces("text/plain")
public String postMessage(final String message) throws InterruptedException {
    final AsyncResponse ar = suspended.take();
    ar.resume(message); // resumes the processing of one GET request
    return "Message sent";
}

うん、䜿いどころがわかりたせん

䜿っおみたい

ずいうわけで、JAX-RS 2.0のリリヌスはただですが、いち早く詊したい堎合はJersey 2.xを䜿っおみたしょう

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
    <version>2.0-rc1</version>
  </dependency>
  <dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-jdk-http</artifactId>
    <version>2.0-rc1</version>
    <scope>test</scope>
  </dependency>
</dependencies>

たずめ

  • JAX-RSいいね
  • もうServletは芁らないですね
  • ずころで「いいねJava EE」の第二回はあるんですかね

資料の手盎し、最埌の方疲れたので投げやりです。 たあ、たたJAX-RSは話題に出すず思いたすので曞ききれなかった曞き忘れたアレずか゜レはたたの機䌚にヌ。

]]>
Thu, 02 May 2013 00:00:00 +0900
http://backpaper0.github.io/2013/04/01/shigatsubaka.html http://backpaper0.github.io/2013/04/01/shigatsubaka.html <![CDATA[退職したした]]> 退職したした

本日4/1をもっお株匏䌚瀟HOGEDRIVENを退職したした。

HOGEDRIVENでは䞊行プログラミング焌肉、ORマッパヌフグ、暗号焌肉、Java 8のラムダステヌキなど、様々な技術を経隓させお貰いすごく感謝しおいたすごちそうさたでした。

しかし、HOGEDRIVENは「しゃぶしゃぶ」「ロヌストチキン」「シシケバブ」など、これからも肉料理に力を入れお行くようで、魚料理にも挑戊したいずいう私の思いずは目指す方向が異なるため、退職ずいう道を遞択したした。

今埌の事はただ䜕も決たっおいたせんが、ベタなずころではマグロ、カニ、あるいは捚おる所が無いず蚀われるアンコりあたりに興味があるので、機䌚を芋぀けおチャレンゞしお行きたいず思いたす。

今埌ずも宜しくお願いただきたす。

]]>
Mon, 01 Apr 2013 00:00:00 +0900
http://backpaper0.github.io/2013/03/03/like_bdd_by_java8.html http://backpaper0.github.io/2013/03/03/like_bdd_by_java8.html <![CDATA[Java8でBDDっぜくテストを曞けるかもしれないアむデア]]> Java8でBDDっぜくテストを曞けるかもしれないアむデア

JasmineでJavaScriptのテスト曞いたりJava8のラムダに思いを銳せおいたらなんずなく思い぀きたした。 ラムダにむンスタンスむニシャラむザを組み合わせたらこんな感じでテストが曞けそうです。

package app;

public class CalcSpec extends Specs {{

    it("1 足す 2 は 3", () -> {
        expect(() -> 1 + 2).toEqual(3);
    });

    it("1 割る 0 は䟋倖", () -> {
        expect(() -> 1 / 0).toThrow(ArithmeticException.class);
    });

}}

うむ、Jasmineぜい。 たあ実はBDDぜいずかよく分かっおいたせんが。

itメ゜ッドを呌ぶず第䞀匕数のテスト名をkey、第二匕数のRunnableのようなオブゞェクトをvalueずするマップに突っ蟌みたす。 このマップのひず぀のEntryがひず぀のテストになりたす。 itメ゜ッドはスヌパヌクラスのSpecsに定矩されおいたす。 そのSpecs自䜓に@RunWithが泚釈しおおり、テストはSpecRunnerずいうテストランナヌで実行されたす。 SpecRunnerはSpecsに集められたテストを実行したす。

などず文章にしおも䌝えられる気がたったく無いのでSpecsずSpecRunnerのコヌド晒したす。

Specsはこんな感じ。

package app;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import org.junit.Assert;
import org.junit.runner.RunWith;

@RunWith(SpecRunner.class)
public class Specs {

    public Map<String, Spec> specs = new LinkedHashMap<>();

    protected void it(String name, Spec spec) {
        specs.put(name, spec);
    }

    protected <T> Expect<T> expect(Callable<T> c) {
        return new Expect<>(c);
    }

    public interface Spec {

        void run() throws Exception;
    }

    public static class Expect<T> {

        private final Callable<T> c;

        public Expect(Callable<T> c) {
            this.c = c;
        }

        public void toEqual(T value) throws Exception {
            Assert.assertEquals(value, c.call());
        }

        public void toThrow(Class<? extends Exception> exceptionClass) throws Exception {
            try {
                c.call();
                Assert.fail();
            } catch (Exception e) {
                if (!exceptionClass.isAssignableFrom(e.getClass())) {
                    Assert.fail();
                }
            }
        }
    }
}

SpecRunnerはこんな感じ。

package app;

import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;

public class SpecRunner extends Runner {

    private final Specs spec;

    public SpecRunner(Class<Specs> specClass) throws InstantiationException, IllegalAccessException {
        spec = specClass.newInstance();
    }

    @Override
    public Description getDescription() {
        Description desc = Description.createSuiteDescription(spec.getClass());
        for (String name : spec.specs.keySet()) {
            desc.addChild(Description.createSuiteDescription(name));
        }
        return desc;
    }

    @Override
    public void run(RunNotifier notifier) {
        for (String name : spec.specs.keySet()) {
            Description desc = Description.createSuiteDescription(name);
            notifier.fireTestStarted(desc);
            try {
                spec.specs.get(name).run();
            } catch (Exception ex) {
                Failure f = new Failure(desc, ex);
                notifier.fireTestFailure(f);
            } finally {
                notifier.fireTestFinished(desc);
            }
        }
    }
}

これらのコヌドを、Java8に察応しおいるNetBeansの開発版を䜿甚しお詊しおみたした。

../../../_images/test-result.png

いい感じで実行できたした。

ずいうわけで、ふわっずした思い぀きをサクッず詊しおみただけですが、なかなかJava8の可胜性を感じれた気がしたす。 テスティングフレヌムワヌクに限らずね、色々出おきおくれそうですね。

楜しみだ。はよこいJava8。

ギットハブにも眮いたよ

]]>
Sun, 03 Mar 2013 00:00:00 +0900
http://backpaper0.github.io/2013/01/30/httpserver_jaxb.html http://backpaper0.github.io/2013/01/30/httpserver_jaxb.html <![CDATA[HttpServerずJAXBでAPIを組蟌む]]> HttpServerずJAXBでAPIを組蟌む

前に小酒さんずJavaのプロセス間通信に぀いおお話したした。

んで、私も監芖ずいうかAPIずいうか、そんな感じのアレを簡易で良いのでサクッず組蟌む必芁が出おきたした。 ずいう蚳で HttpServer ずJAXBでサクッず組蟌もうず思いたす。

ほい、サンプルコヌド。

import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlRootElement;

public class Monitor {

    public static void main(String[] args) throws Exception {
        InetSocketAddress address = new InetSocketAddress(8080);
        int backlog = -1;
        HttpServer server = HttpServer.create();
        server.bind(address, backlog);
        try {
            HttpContext context = server.createContext("/log");
            HttpHandler handler = new LogHandler();
            context.setHandler(handler);
            server.start();

            SwingUtilities.invokeAndWait(new Runnable() {
                @Override
                public void run() {
                    String message = "ダむアログを閉じるず鯖終了";
                    JOptionPane.showMessageDialog(null, message);
                }
            });
        } finally {
            server.stop(10);
        }
    }

    public static class LogHandler implements HttpHandler {

        @Override
        public void handle(HttpExchange exchange) throws IOException {
            Log log = new Log();
            log.result = Result.SUCCESS;
            log.timestamp = new Date();

            int statusCode = 200;
            int chunked = 0;
            exchange.sendResponseHeaders(statusCode, chunked);

            try (OutputStream out = exchange.getResponseBody()) {
                JAXB.marshal(log, out);
                out.flush();
            }
        }
    }

    @XmlRootElement
    public static class Log {

        public Result result;

        public Date timestamp;

    }

    public enum Result {

        SUCCESS, FAILURE

    }
}

HttpServerはアドレス枡しお準備しお、パス枡しおコンテキスト䜜っお、ハンドラ登録すればおk。 Java SEでもHTTP鯖立おるの簡単ですね。 わヌい。

今回はアプリケヌションの凊理結果ずタむムスタンプを持ったログを返す感じのハンドラを曞いおみたした。 ログはPOJOで衚珟しおいたすが、JAXBでXMLに倉換しおレスポンスに曞き出しおいたす。 このハンドラは次のようなXMLを返したす。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<log>
    <result>SUCCESS</result>
    <timestamp>2013-01-30T23:08:37.482+09:00</timestamp>
</log>

XMLベヌスのWeb APIなら構築するのは簡単ですね。 わヌい。

たあもうちょい倚機胜なAPIを構築したかったらJerseyを突っ蟌みたすが芁件によっおはこれで十分かなヌ、ずか思ったりしたした。

]]>
Wed, 30 Jan 2013 00:00:00 +0900
http://backpaper0.github.io/2013/01/23/netbeans_jpql.html http://backpaper0.github.io/2013/01/23/netbeans_jpql.html <![CDATA[NetBeans 7.2.1でJPQLの補完するヌ]]> NetBeans 7.2.1でJPQLの補完するヌ

こんばんは em.cQ ず打っお control + space で createQuery を補完するうらがみです。

もうキャメルケヌスでの補完が無かったら生きお行けたせん。 これはEcliなんずかでも出来たす。 たぶんIDEAでも出来るでしょう。

本題。 NetBeansではJPQLの補完もできたす、ずいう話。

../../../_images/compl1.png

FROM も。

../../../_images/compl2.png

゚ンティティ名も。

../../../_images/compl3.png

WHERE や、

../../../_images/compl4.png

プロパティも。

../../../_images/compl5.png

挔算子も。

../../../_images/compl6.png

ずいう感じです。 でもこれロヌカル倉数に突っ蟌むず補完しおくれないのが残念です。

../../../_images/compl7.png

あず@NamedQueryに曞くJPQLでも補完できたす。

../../../_images/compl8.png

ロヌカル倉数に突っ蟌んだずきも補完が効いおくれるようになるずもっず嬉しいですねヌ。 簡単ですが、そんな感じでヌ。

]]>
Wed, 23 Jan 2013 00:00:00 +0900
http://backpaper0.github.io/2013/01/12/http_trace.html http://backpaper0.github.io/2013/01/12/http_trace.html <![CDATA[GlassFish v3.1.2.2でTRACEメ゜ッドを蚱可しない]]> GlassFish v3.1.2.2でTRACEメ゜ッドを蚱可しない

デフォルトで蚱可しないようになっおいたすが備忘録的に䞀応曞いおおきたす。 asadminコマンドで蚭定したす。

asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-1.http.trace-enabled=false

もちろんGUI管理コン゜ヌルからも蚭定可胜で、構成 -> server-config -> ネットワヌク構成 -> プロトコル -> http-listener-1 の「HTTP」タブを開いおトレヌスのチェックを倖したす。

この状態でTRACEリク゚ストを投げるず405 Method Not Allowedが返っおきたす。

]]>
Sat, 12 Jan 2013 00:00:00 +0900
http://backpaper0.github.io/2013/01/11/cookie.html http://backpaper0.github.io/2013/01/11/cookie.html <![CDATA[GlassFish 3.1.2.2でCookieにsecure属性ずhttpOnly属性を぀ける]]> GlassFish 3.1.2.2でCookieにsecure属性ずhttpOnly属性を぀ける

䜕もしなくおもhttpOnly属性は付いおる感じですが、それはGrizzlyの機胜なのでしょうかね。 それはそれでたた調べおおくこずにしたす。

プログラムで蚭定する

javax.servlet.SessionCookieConfig を䜿甚したす。

package example;

import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;

public class CookieSettings implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        SessionCookieConfig scc = ctx.getSessionCookieConfig();
        scc.setHttpOnly(true);
        scc.setSecure(true);
    }
}

GlassFish Server Deployment Descriptorで蚭定する

cookie-properties - Oracle GlassFish Server 3.1 Application Deployment Guide を参照。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC
  "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
  "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
 <session-config>
  <cookie-properties>
   <property name="cookieSecure" value="true"/>
   <property name="cookieHttpOnly" value="true"/>
  </cookie-properties>
 </session-config>
</glassfish-web-app>
]]>
Fri, 11 Jan 2013 00:00:00 +0900
http://backpaper0.github.io/2013/01/06/welcome_to_tinkerer.html http://backpaper0.github.io/2013/01/06/welcome_to_tinkerer.html <![CDATA[Welcome to Tinkerer]]> Welcome to Tinkerer

あけおめ

そんなアレではおなダむアリヌから乗り換える䜕かを暡玢䞭なのです。 TinkererずいうSphinxでブログが曞ける拡匵を芋぀けたので䜕ずなく䜿っおみようかず。 この゚ントリではむンストヌルからbackpaper0.github.comでの公開たでの手順を適圓に曞きたす。 なお、゚ントリのタむトルはりェルカム・トゥ・オクトプレスをパクったです。

Tinkererをむンストヌルする

easy_installで䞀発ですよ奥さん。

easy_install -U Tinkerer

セットアップする

適圓にディレクトリ䜜っおからtinker -sしたす。

mkdir blog
cd blog
tinker -s

conf.pyが䜜成されるのでブログの名前ずか蚭定したす。

蚘事を曞く

゚ントリ䜜りたす。

tinker -p "Welcome to Tinkerer"

日付を衚すディレクトリに続き゚ントリのrstファむルが䜜成されたすのでこれを線集したす。

ビルドする

tinker -b

blog/htmlディレクトリにもろもろ出力されたす。

公開する

blog/html以䞋をbackpaper0.github.comにプッシュしたす。 たあぶっちゃけこれからやるこずなのでこの蚘事曞いおる段階ではそれで良いのか分かりたせんが。

たずめ

  • rstで曞けるから嬉しい
  • Sphinx奜きなので嬉しい
  • なんか探すずきはgrep出来るから嬉しい
  • Tinkerer簡単そうで嬉しい

ずいう感じでしばらく䜿っおみようず思いたす。

]]>
Sun, 06 Jan 2013 00:00:00 +0900