开发者

Force initialization of Scala singleton object

开发者 https://www.devze.com 2023-03-10 10:20 出处:网络
I\'m working on an automatic mapping framework built on top of Dozer. I won\'t go into specifics as it\'s not relevant to the question but in general it\'s supposed to allow easy transformation from c

I'm working on an automatic mapping framework built on top of Dozer. I won't go into specifics as it's not relevant to the question but in general it's supposed to allow easy transformation from class A to class B. I'd like to register the projections from a class's companion object.

Below is a (simplified) example of how I want this to work, and a Specs test that assures that the projection is being registered properly.

Unfortunately, this does开发者_Python百科n't work. From what I can gather, this is because nothing initializes the A companion object. And indeed, if I call any method on the A object (like the commented-out hashCode call, the projection is being registered correctly.

My question is - how can I cause the A object to be initialized automatically, as soon as the JVM starts? I don't mind extending a Trait or something, if necessary.

Thanks.

class A {
  var data: String = _
}

class B {
  var data: String = _
}

object A {
  projekt[A].to[B]

}

"dozer projektor" should {
  "transform a simple bean" in {
//    A.hashCode
      val a = new A
      a.data = "text"
      val b = a.-->[B]

      b.data must_== a.data
  }
}


Short answer: You can't. Scala objects are lazy, and are not initialized until first reference. You could reference the object, but then you need a way of ensuring the executing code gets executed, reducing the problem back to the original problem.


In ended up doing this:

trait ProjektionAware with DelayedInit
{
  private val initCode = new ListBuffer[() => Unit]

  override def delayedInit(body: => Unit)
  {
    initCode += (() => body)
  }


  def registerProjektions()
  {
    for (proc <- initCode) proc()
  }
}

object A extends ProjektionAware {
  projekt[A].to[B]

}

Now I can use a classpath scanning library to initialize all instances of ProjektionAware on application bootstrap. Not ideal, but works for me.


You can force the instantiation of A to involve the companion object by using an apply() method or some other sort of factory method defined in the object instead of directly using the new A() constructor.

This does not cause the object to be initialized when the JVM starts, which I think as noted in another answer can't generally be done.


As Dave Griffith and Don Roby already noted, it cannot be done at JVM startup in general. However maybe this initialization could wait until first use of your framework? If so, and if you don't mind resorting to fragile reflection tricks, in your --> method you could obtain reference to the companion object and get it initialize itself.

You can start at Getting object instance by string name in scala.


We could use this sort of a way to ensure that companion object gets initialized first and then the class gets instantiated.

object B {
    val i = 0
    def apply(): B = new B()
}
class B {
    // some method that uses i from Object B
    def show = println(B.i)
}

// b first references Object B which calls apply()
// then class B is instantiated
val b = B()
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号