scala - Play 2.4 WebSocket throws InstantiationException when using compile-time dependency injection -


websockets in play 2.4 doesn't seem work when using compile-time dependency injection. i'm using latest version 2.4.2. specifically, throws following exception upon connecting:

play.api.http.httperrorhandlerexceptions$$anon$1: execution exception[[instantiationexception: null]]     @ play.api.http.httperrorhandlerexceptions$.throwabletousefulexception(httperrorhandler.scala:254) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.api.http.defaulthttperrorhandler.onservererror(httperrorhandler.scala:180) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.core.server.netty.playdefaultupstreamhandler$$anonfun$messagereceived$1.applyorelse(playdefaultupstreamhandler.scala:182) [play-netty-server_2.11-2.4.0.jar:2.4.0]     @ play.core.server.netty.playdefaultupstreamhandler$$anonfun$messagereceived$1.applyorelse(playdefaultupstreamhandler.scala:180) [play-netty-server_2.11-2.4.0.jar:2.4.0]     @ scala.runtime.abstractpartialfunction.apply(abstractpartialfunction.scala:36) [scala-library-2.11.6.jar:na]     @ scala.util.failure$$anonfun$recover$1.apply(try.scala:215) [scala-library-2.11.6.jar:na]     @ scala.util.try$.apply(try.scala:191) [scala-library-2.11.6.jar:na]     @ scala.util.failure.recover(try.scala:215) [scala-library-2.11.6.jar:na]     @ scala.concurrent.future$$anonfun$recover$1.apply(future.scala:324) [scala-library-2.11.6.jar:na]     @ scala.concurrent.future$$anonfun$recover$1.apply(future.scala:324) [scala-library-2.11.6.jar:na]     @ scala.concurrent.impl.callbackrunnable.run(promise.scala:32) [scala-library-2.11.6.jar:na]     ... caused by: java.lang.instantiationexception: null     @ sun.reflect.instantiationexceptionconstructoraccessorimpl.newinstance(instantiationexceptionconstructoraccessorimpl.java:48) ~[na:1.8.0_45]     @ java.lang.reflect.constructor.newinstance(constructor.java:422) ~[na:1.8.0_45]     @ java.lang.class.newinstance(class.java:442) ~[na:1.8.0_45]     @ play.api.inject.newinstanceinjector$.instanceof(injector.scala:49) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.api.inject.simpleinjector$$anonfun$instanceof$1.apply(injector.scala:85) ~[play_2.11-2.4.0.jar:2.4.0]     @ scala.collection.maplike$class.getorelse(maplike.scala:128) ~[scala-library-2.11.6.jar:na]     @ scala.collection.abstractmap.getorelse(map.scala:59) ~[scala-library-2.11.6.jar:na]     @ play.api.inject.simpleinjector.instanceof(injector.scala:85) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.api.inject.simpleinjector.instanceof(injector.scala:80) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.api.application$$anonfun$instancecache$1.apply(application.scala:234) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.api.application$$anonfun$instancecache$1.apply(application.scala:234) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.utils.inlinecache.fresh(inlinecache.scala:69) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.utils.inlinecache.apply(inlinecache.scala:62) ~[play_2.11-2.4.0.jar:2.4.0]     @ play.api.libs.concurrent.akka$.system(akka.scala:37) ~[play_2.11-2.4.0.jar:2.4.0]     ... 

here's how controller looks like:

class application extends controller {   import play.api.play.current   def socket = websocket.acceptwithactor[string, string] { request => out =>     websocketactor.props(out)   } }  object websocketactor {   def props(out: actorref) = props(new websocketactor(out)) }  class websocketactor(out: actorref) extends actor {   def receive = {     case msg: string =>       out ! ("received message: " + msg)   } } 

and here's how applicationloader looks like:

class apploader extends applicationloader {   override def load(context: context): application = new appcomponents(context).application }  class appcomponents(context: context) extends builtincomponentsfromcontext(context) {   lazy val appcontroller = new controllers.application   lazy val router = new routes(httperrorhandler, appcontroller, assets)   lazy val assets = new controllers.assets(httperrorhandler) } 

turns out bug in play 2.4.2. there's pull request fix it.

until it's fixed, worked around overriding injector of appcomponents include actorsystem. appcomponents becomes:

class appcomponents(context: context) extends builtincomponentsfromcontext(context) {   lazy val appcontroller = new controllers.application   lazy val router = new routes(httperrorhandler, appcontroller, assets)   lazy val assets = new controllers.assets(httperrorhandler)    // temporary workaround until issue #4614 in playframework fixed. see https://github.com/playframework/playframework/issues/4614   override lazy val injector = new simpleinjector(newinstanceinjector) + router.asinstanceof[play.api.routing.router] + crypto + httpconfiguration + actorsystem } 

Comments