Play Framework Migration (2.1 -> 2.2)
SBT version
build.properties
sbt.version 값을 수정한다.
sbt.version=0.13.0
plugins.sbt
sbt plugin 의 groupId 와 version 값을 수정한다.
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.2-SNAPSHOT")
library version
기존 사용하고 있던 play framework 관련 library 들의 version 을 2.2 버전에 호환되는 버전으로 변경한다.
이 때, 해당 라이브러리가 여전히 scala 2.10.0 이나 play 2.1 에 의존하고 있다면 제외한다.
"info.schleichardt" %% "play-2-mailplugin" % "0.9.1" exclude("org.scala-lang", "scala-library") exclude("play", "play_2.10")
"com.github.julienrf" %% "play-jsmessages" % "1.5.1" exclude("org.scala-lang", "scala-library") exclude("play", "play_2.10")
akka migration
http://doc.akka.io/docs/akka/2.2.0/project/migration-guide-2.1.x-2.2.x.html
applicafion.default.conf, application.conf
event-handlers 설정은 deprecated 되었다. 대신 loggers 를 사용한다.
loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"]
akka.actor.Props 를 사용하는 class
Props 의 construcor 가 deprecated 되었다. 대신 create 를 사용한다.
Akka.system().actorOf(Props.create(MyActor.class)).tell(message, null);
jackson
jackson library 의 version 이 변경되면서 package 구성이 변경됨.
기존 org.codehaus.jackson.node.ObjectNode
와 org.codehaus.jackson.JsonNode
대신 아래를 사용한다.
com.fasterxml.jackson.databind.node.ObjectNode
com.fasterxml.jackson.databind.JsonNode
변경된 API 적용
play.mvc.Action
action composition 을 위해 사용되고 있는 class 들의 상위 class 인 play.mvc.Action
의 interface 가 변경됨.
call method 의 return type 을 play.mvc.Result
에서 play.libs.F.Promise
로 바꿔 주어야 한다.
public abstract class Action<T> extends Results {
...
public abstract Promise<SimpleResult> call(Context ctx) throws Throwable;
...
}
example
AS-IS
return forbidden();
TO-BE
return Promise.pure((SimpleResult) forbidden()));
play.GlobalSettings
onBadRequest, onError, onHandlerNotFound method 들의 return type 이 play.mvc.Result
에서 play.libs.F.Promise
로 변경됨.
play.api.mvc.PlainResult
deprecated. play 2.2 에서부터는 SimpleResult 만을 사용한다.
jackson
기존의 node 값을 얻어 오는 method 이름이 변경됨.
- get[data-type]Value 형태의 method 들에서 get 이 삭제
- jsonNode.getTextValue() -> jsonNode.textValue()
- jsonNode.getBooleanValue() -> jsonNode.booleanValue()
jsmessage
JsMessages class 의 generate method 는 더 이상 static method 가 아니다.
따라서 JsMessages 의 객체를 만들어서 사용해야 한다.
public class Application extends Controller {
...
static final JsMessages messages = new JsMessages(play.Play.application());
public static Result jsMessages() {
return ok(messages.generate("Messages")).as("application/javascript");
}
...
}
Known Issues
현상
play 2.1 에서 사용하던 코드 중, 아래와 같은 구조의 코드는 play 2.2 에서 정상적으로 compile 은 되지만, runtime 시 java.lang.VerifyError
를 발생시킨다.
TestObject object = new TestObject();
object.name = "test"; // get or set string value
try { // in try
object.id = 100L; // get or set long value
String name = object.name; // get or set string value
} catch (Throwable t) {
t.printStackTrace();
}
- member variable 에 대한 접근이 꼭 하나의 object 에 대한 것이 아니어도 동일한 문제가 발생한다.
- string - long 이 아니더라도 서로 cast 할 수 없는 Object 에 대해서도 문제가 발생한다.
- member variable 에 대한 접근을 getter/setter 를 통해서 할 경우 문제가 발생하지 않는다.
- 위 코드에서 try-catch 가 없을 경우 문제가 발생하지 않는다.
원인
- play framework 는 javassist 를 이용해서 public member variable 에 대한 직접적인 accesss 를 getter/setter 로 변경한다.
- v2.1 에선 javassist 3.16 을 사용, v2.2 에선 javassist 3.18을 사용
- javassist 3.17 version 이후부터 class file 의 stackmap 을 구성하는 코드가 변경되었고,
이로 인해서 변조된 class file 이 JAVA7 이상에서 사용되는 class verifier 의 검증을 통과하지 못하는 경우가 발생한다.
workaround
이 문제는 javassist 의 bug 로 3.18.2 version 에서 해결되었다. 아래와 같이 plugin.sbt 에서 javassist 의 version 을 변경해야 한다.
libraryDependencies += "org.javassist" % "javassist" % "3.18.2-GA"
play framework 에 근본적인 해결을 위한 커밋 이 작성 되었지만, 아직 릴리즈 계획을 알 수 없다.