こちらの資料を見て、以下の2枚が気になりまして。
Kotlin + JAX-RS
http://backpaper0.github.io/ghosts/kotlin-jaxrs.html#/9
http://backpaper0.github.io/ghosts/kotlin-jaxrs.html#/10
元ネタはKotlinですが、コンストラクタインジェクションをしようとしてうまくいかないという話。
これ、Scalaなら普通に動くんじゃ?と思い、簡単に実装。
src/main/scala/org/littlewings/javaee7/rest/HelloResource.scala
package org.littlewings.javaee7.rest import javax.ws.rs.{DefaultValue, GET, Path, Produces, QueryParam} import javax.ws.rs.core.{Context, MediaType, UriInfo} @Path("hello") class HelloResource(@Context uriInfo: UriInfo) { @GET @Produces(Array(MediaType.TEXT_PLAIN)) def sayHello(@QueryParam("name") @DefaultValue("world") name: String): String = s"Hello, $name!" @GET @Path("path") @Produces(Array(MediaType.TEXT_PLAIN)) def path: String = uriInfo.getPath } @Path("hello-val") class HelloValResource(@Context val uriInfo: UriInfo) { @GET @Produces(Array(MediaType.TEXT_PLAIN)) def sayHello(@QueryParam("name") @DefaultValue("world") name: String): String = s"Hello, $name!" @GET @Path("path") @Produces(Array(MediaType.TEXT_PLAIN)) def path: String = uriInfo.getPath }
まあ、val付けようが付けまいが動きますよね。
このように展開されますし。
*コンパイルオプションに「-Xprint:jvm」を追加
@javax.ws.rs.Path(value = "hello") class HelloResource extends Object { @javax.ws.rs.core.Context <paramaccessor> private[this] val uriInfo: javax.ws.rs.core.UriInfo = _; @javax.ws.rs.GET @javax.ws.rs.Produces(value = ["text/plain"]) def sayHello(@javax.ws.rs.QueryParam(value = "name") @javax.ws.rs.DefaultValue(value = "world") name: String): String = new StringContext(scala.this.Predef.wrapRefArray(Array[String]{"Hello, ", "!"}.$asInstanceOf[Array[Object]]())).s(scala.this.Predef.genericWrapArray(Array[Object]{name})); @javax.ws.rs.GET @javax.ws.rs.Path(value = "path") @javax.ws.rs.Produces(value = ["text/plain"]) def path(): String = HelloResource.this.uriInfo.getPath(); def <init>(@javax.ws.rs.core.Context uriInfo: javax.ws.rs.core.UriInfo): org.littlewings.javaee7.rest.HelloResource = { HelloResource.this.uriInfo = uriInfo; HelloResource.super.<init>(); () } }; @javax.ws.rs.Path(value = "hello-val") class HelloValResource extends Object { <paramaccessor> private[this] val uriInfo: javax.ws.rs.core.UriInfo = _; <stable> <accessor> <paramaccessor> def uriInfo(): javax.ws.rs.core.UriInfo = HelloValResource.this.uriInfo; @javax.ws.rs.GET @javax.ws.rs.Produces(value = ["text/plain"]) def sayHello(@javax.ws.rs.QueryParam(value = "name") @javax.ws.rs.DefaultValue(value = "world") name: String): String = new StringContext(scala.this.Predef.wrapRefArray(Array[String]{"Hello, ", "!"}.$asInstanceOf[Array[Object]]())).s(scala.this.Predef.genericWrapArray(Array[Object]{name})); @javax.ws.rs.GET @javax.ws.rs.Path(value = "path") @javax.ws.rs.Produces(value = ["text/plain"]) def path(): String = HelloValResource.this.uriInfo().getPath(); def <init>(@javax.ws.rs.core.Context uriInfo: javax.ws.rs.core.UriInfo): org.littlewings.javaee7.rest.HelloValResource = { HelloValResource.this.uriInfo = uriInfo; HelloValResource.super.<init>(); () } } }
// HelloResource def <init>(@javax.ws.rs.core.Context uriInfo: javax.ws.rs.core.UriInfo): org.littlewings.javaee7.rest.HelloResource = { HelloResource.this.uriInfo = uriInfo; HelloResource.super.<init>(); () } // HelloValResource def <init>(@javax.ws.rs.core.Context uriInfo: javax.ws.rs.core.UriInfo): org.littlewings.javaee7.rest.HelloValResource = { HelloValResource.this.uriInfo = uriInfo; HelloValResource.super.<init>(); () }
フィールドには…あれ?valが無い方は付いてますね。
// HelloResource @javax.ws.rs.core.Context <paramaccessor> private[this] val uriInfo: javax.ws.rs.core.UriInfo = _; // HelloValResource <paramaccessor> private[this] val uriInfo: javax.ws.rs.core.UriInfo = _; <stable> <accessor> <paramaccessor> def uriInfo(): javax.ws.rs.core.UriInfo = HelloValResource.this.uriInfo;
それでも動くんですね。
JDでデコンパイルしてみました。
package org.littlewings.javaee7.rest; 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.Context; import javax.ws.rs.core.UriInfo; import scala.Predef.; import scala.StringContext; import scala.reflect.ScalaSignature; @Path("hello") @ScalaSignature(bytes="\006\001u3A!\001\002\001\027\ti\001*\0327m_J+7o\\;sG\026T!a\001\003\002\tI,7\017\036\006\003\013\031\tqA[1wC\026,wG\003\002\b\021\005YA.\033;uY\026<\030N\\4t\025\005I\021aA8sO\016\0011C\001\001\r!\ti\001#D\001\017\025\005y\021!B:dC2\f\027BA\t\017\005\031\te.\037*fM\"A1\003\001B\001B\003%A#A\004ve&LeNZ8\021\005UqR\"\001\f\013\005]A\022\001B2pe\026T!!\007\016\002\005I\034(BA\016\035\003\t98OC\001\036\003\025Q\027M^1y\023\tybCA\004Ve&LeNZ8)\005I\t\003CA\013#\023\t\031cCA\004D_:$X\r\037;\t\013\025\002A\021\001\024\002\rqJg.\033;?)\t9\023\006\005\002)\0015\t!\001C\003\024I\001\007A\003\013\002*C!)A\006\001C\001[\005A1/Y=IK2dw\016\006\002/kA\021qF\r\b\003\033AJ!!\r\b\002\rA\023X\rZ3g\023\t\031DG\001\004TiJLgn\032\006\003c9AQAN\026A\0029\nAA\\1nK\"\"Q\007\017\037>!\tI$(D\001\031\023\tY\004D\001\007EK\032\fW\017\034;WC2,X-A\003wC2,X-I\001?\003\0259xN\0357eQ\021)\004\tP\"\021\005e\n\025B\001\"\031\005)\tV/\032:z!\006\024\030-\\\021\002m!\"1&\022\037I!\tId)\003\002H1\tA\001K]8ek\016,7\017L\001JC\005Q\025A\003;fqR|\003\017\\1j]\"\0221\006\024\t\003s5K!A\024\r\003\007\035+E\013C\003Q\001\021\005\021+\001\003qCRDW#\001\030)\t=+Eh\025\027\002\023\"\"q*\026\037Y!\tId+\003\002X1\t!\001+\031;iC\005\001\006FA(MQ\021\001Q\013P.\"\003q\013Q\001[3mY>\004") public class HelloResource { @Context private final UriInfo uriInfo; @GET @Produces({"text/plain"}) public String sayHello(@QueryParam("name") @DefaultValue("world") String name) { return new StringContext(Predef..MODULE$.wrapRefArray((Object[])new String[] { "Hello, ", "!" })).s(Predef..MODULE$.genericWrapArray(new Object[] { name })); } @GET @Path("path") @Produces({"text/plain"}) public String path() { return this.uriInfo.getPath(); } public HelloResource(@Context UriInfo uriInfo) {} }
やっぱり、両方に@Contextアノテーション付いてますね…。
それでも動くのかな。って、あれ??
一応、作成したソース。
https://github.com/kazuhira-r/javaee7-scala-examples/tree/master/jaxrs-constructor-inject
追記)
結果が妙なことになったので、Kotlin&GlassFishで確認してみました。結果は、こちら。
KotlinでJAX-RSのコンストラクタインジェクションがうまくいかないという話について
http://d.hatena.ne.jp/Kazuhira/20140917/1410976731
なんと、GlassFishだと動かなかったというオチが。しかも、Scalaの方でもGlassFishにするとvalを付与しなかった方は動作しませんでした。