Glassfish4でlambda式を使ってみた、の続き
前のメモが中途半端な感じで終わってしまったので、もうちょっと試してみました。
Glassfish4.0.1 buid4つかってラムダ式を書いて実行すると
起動時にこういうエラーが出たけど、なんか動いているっぽい。という話。
重大: Exception while visiting WEB-INF/classes/demo/DemoAction.class of size 2189 java.lang.ArrayIndexOutOfBoundsException: 52264 at org.objectweb.asm.ClassReader.readClass(ClassReader.java:2015) at org.objectweb.asm.ClassReader.accept(ClassReader.java:469) at org.objectweb.asm.ClassReader.accept(ClassReader.java:425) at org.glassfish.hk2.classmodel.reflect.Parser$5.on(Parser.java:359) at com.sun.enterprise.v3.server.ReadableArchiveScannerAdapter.handleEntry(ReadableArchiveScannerAdapter.java:165) at com.sun.enterprise.v3.server.ReadableArchiveScannerAdapter.onSelectedEntries(ReadableArchiveScannerAdapter.java:127) at org.glassfish.hk2.classmodel.reflect.Parser.doJob(Parser.java:344) at org.glassfish.hk2.classmodel.reflect.Parser.access$300(Parser.java:67) at org.glassfish.hk2.classmodel.reflect.Parser$3.call(Parser.java:303) at org.glassfish.hk2.classmodel.reflect.Parser$3.call(Parser.java:292) 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:744)
で、ここからが本題。
このhk2というのはDIフレームワークです。
https://hk2.java.net/
なのでDIでこけているというのが推測できます。
でASMというのはJavaバイトコードの操作や分析を行うフレームワーク。
http://asm.ow2.org/
ちゃんと見てないので間違ってるかもしれませんが、DIするときにそのままコンパイルするのではなく前後処理等を追加した形でバイトコードを生成してる処理(@ASM)でラムダ式が対応できてない、って感じのエラーな気がします(うまく説明できない、、、)。
なので、このコードと一緒にCDIでインジェクションを使おうとすると実行時にもこけました。(DIされずにヌルポになる)
@PersistenceContext(unitName = "demo") EntityManager em; @javax.ws.rs.GET @javax.ws.rs.Produces("text/plain") public String demo() { List<Customer> customers = em.createQuery("select s from customer s", Customer.class).getResultList(); long count = customers.stream().filter(customer -> customer.getId() > 3).collect(java.util.stream.Collectors.counting()); return "this is demo! count=" + count; }
このあたりはGlassfishのチケットとしてもあがっているようで、修正されるのは時間の問題の気がします。
https://java.net/jira/browse/GLASSFISH-20972
どうしてもラムダ式で書きたいという時は、DIの対象外クラスに定義すればいいみたいです。
今回はユーティリティクラスっぽいクラスを作ってstaticメソッド内にラムダ式を書くようにしてそのクラスに@Vetoedアノテーションをつけることでエラーを解消できました。
まあ、実際はこれだけのためにこんな風にクラスを分けることはしないと思いますが。
http://yoshio3.com/2014/01/29/cdi-1-1-vetoed-annotation/
@javax.enterprise.inject.Vetoed public class CustomerUtils { public static long filterCount(java.util.List<Customer> customers, int base) { return customers.stream().filter(customer -> customer.getId() > base).collect(java.util.stream.Collectors.counting()); } }
public String demo() { List<Customer> customers = em.createQuery("select s from customer s", Customer.class).getResultList(); long count = CustomerUtils.filterCount(customers, 3); return "this is demo! count=" + count; }
正直、まだこの辺の動きがよく分からないんですが、
http://d.hatena.ne.jp/gloryof/20131205/1386170095
@Vetoedアノテーションを使わない場合、
beans.xmlのbean-discovery-modeが"all"でも"annotated"でもエラーが発生してて直感的には"annotated"ではエラーにならないでほしかった。
ここはscan.excludeで除外対象の設定をすべきようです。(1個上の寺田さんのブログへのリンク参照)
以上。