Javaのログ出力ライブラリメモ
知識がlog4jで止まっていたので調査。
Javaのログ出力: 道具と考え方
javaのロガーが多すぎて訳が解らないので整理してみました - 文系プログラマによるTIPSブログ
・・・迷路で遊ぶ暇は無いんだけどな、、、
とりあえず「SLF4J+Logback」でそんなに問題にはならんだろう。
JAX-RS 返却用クラスはデフォルトコンストラクタ必須
タイトルの通り。JAXBの仕様?らしい。
@GET @Produces(MediaType.APPLICATION_JSON) public User getIt() { return new User(1); }
この場合、Userクラスが以下だとダメ。
public class User { public User(int id) {} }
ちゃんとデフォルトコンストラクタ作るべし。
public class User { public User() {} public User(int id){} }
JSON・XMLを返すけどエラー時はステータスコードやメッセージを選びたい
JAX-RSで200とか404とか返すだけなら、メソッド戻り値にResponseを指定してResponseを操作すればいい。
@RequestScoped @Path("myresource") public class MyResource { @GET public Response getIt() { return Response.ok().build(); // 200が返る } }
JSONとかXMLとか返したいなら、戻り値にオブジェクトを指定して@ProducesでMIME(MediaType)を指定する。
@GET @Produces(MediaType.APPLICATION_JSON) public User getIt() { User user = userService.getUser(1); return user; // JSONが返る }
本題。
通常はJSONやXMLを返したいけど、データベースなどにデータが無い場合は404にしたい。
参考:Chapter 7. Representations and Responses
@GET @Produces(MediaType.APPLICATION_JSON) public User getIt() { try { User user = userService.getUser(1); return user; // JSONが返る(ステータスコード:200) } catch (NoResultException e) { throw new WebApplicationException(404); // 404が返る } }
WebApplicationExceptionをthrowする。ステータスコード返すだけならコード番号を渡す。
メッセージも変えたいならResponseを渡す。
throw new WebApplicationException( Response.status(Status.NOT_FOUND).entity("error. error. error.").build() );
長すぎるし。。。
多分、WebApplicationExceptionを継承したクラス作るほうが幸せになれる。
public class CustomException extends WebApplicationException { public CustomException() { super(Response.status(Status.NOT_FOUND).build()); } public CustomException(String message) { this(Status.NOT_FOUND, message); } public CustomException(Status status, String message) { this(status.getStatusCode(), message); } public CustomException(int code, String message) { super( Response.status(code).entity(message).build() ); } }
他にもExceptionMapperを使ってExceptionとレスポンスをマッピングさせる方法もある。
NoResultException -> 404 とかやってもいいけど、エラーの切り分けが面倒になりそう
(データが無いのか、単純にパスが間違っているのか、etc...)
なのでやめておく。
余談
このままだとtext/plainだけど、JSON(XML)返すサービスならエラーもJSON(XML)で返すべき?
まあMediaType指定するだけでいいから何とでもなるんだけど。
DeltaSpike(Data)を諦める
DeltaSpikeもひと通り調べ終わり、実際にコーディングを進めていたがDeltaSpike Dataを使うのを諦めることにした。
理由は原因不明のOutOfMemoryError (heap space)が発生して、どうしても発生源が突き止められなかったから。
JAX-RSの1リクエストでRepositoryでデータを取得してデータを返す分には問題無いが、せいぜい同時5リクエスト程度でOutOfMemoryになる。
テストデータは20件程度でメモリを食う要素も無いはず。
Tomcatのヒープを増やそうが、あらゆる場所にEntityManager.clear()を入れようが解決せず。
Repositoryを使わずEntityManagerからDtoデータを引っ張ってくるようにコードを書き直すと問題なく動いたので、仕方なくEntityManagerを使ってカリカリ書くことにする。
とりあえずJSONを返せればいいので、膨大に手間が増えることはないだろうし、一週間以上やっているので正直これ以上深入りする時間が無い。
(し、これ以上精神が持たない。ほんとにツラい。)
Tomcat8 + Java8 + DeltaSpike1.5.1
Jersey + CDIで@Contextが動かない
Jersey + CDIの構成で、ContainerRequestFilterの中でUriInfoを使おうとしてハマった。
構成は JAX-RS(Jersey) + JPA (on CDI) / on Tomcat - edgegram がベースでDeltaspikeを少々追加。
public class FormTypeFilter implements ContainerRequestFilter { @Context private UriInfo uriInfo; public void filter(ContainerRequestContext requestContext) throws IOException { System.out.println(uriInfo); } }
UriInfoがnullにしかならない。ResourceInfoも試したが同様。
調べてもそんな事例なさそうだし(そもそもJersey + CDI自体情報少ないし)。
他のライブラリが影響しているのかと、色々抜き差しした結果、
という所まで何とかこぎつける。
ただ、jersey-cdi1xがダメとなるとCDIが使えなくなる。
何か無いのか? とmarvenリポジトリを検索してみると、jersey-cdi1x-servletというのを発見。
jersey-cdi1xの代わりにjersey-cdi1x-servletを入れて試すと
・・・
UriInfo入った。ちゃんとInjectされている。
他の自前クラスも@Injectできているし、CDIコンテナも問題なく動いている様子。
正解かどうか分からないが、とりあえず動くのでいいことにする。
ハマり時間:8時間
PostgreSQLのbyteaカラムに手動でデータを入れる
初期データ用にbyteaデータを入れようと調べてみたが、psqlからのINSERTはできない?
仕方なくJDBCで放り込むことにした。(その時点で既に手動ではないが)
Chapter 7. Storing Binary Data
Class.forName("org.postgresql.Driver"); Connection con = DriverManager.getConnection("jdbc:postgresql://dbhost:5432/test", "test", "test"); File file = new File("C:/image.png"); FileInputStream fis = new FileInputStream(file); PreparedStatement ps = con.prepareStatement("INSERT INTO binary_tbl (value) VALUES (?)"); ps.setBinaryStream(1, fis, (int)file.length()); ps.executeUpdate(); ps.close(); fis.close(); con.close();
JDBCなんて使うの数年前に研修で教えて以来だわ。
余談だけど、今時の開発者の中にはJDBC学ばずに、O/Rとかライブラリ使うしか分からない人もいたりするのかなぁ。