0
votes

Before Scala 2.10 I had

class A {
    class B(b: Int) {
    }
}

and somewhere in code recreate class B with

val bCtor = bInstance.getClass.getConstructor(classOf[Int])
bCtor.newInstance ...

and everything was fine. It was with signature public A$B(Int)

Now constructor have 2!!! arguments. It has a new signature public A$B(A,Int). What is argument with type A? I don't have access to A class from my function. It there any workaround?

For example newInstance with arguments - It doesn't work anymore for inner class

4
Note that adding A as the first constructor argument is also the way it works in Java (jroller.com/tomdz/entry/reflection_inner_classes). - Alexey Romanov

4 Answers

3
votes

Be carful not to confuse java inner class with scala path-dependent type (from the Programming In ScalaBook) :

A path-dependent type resembles the syntax for an inner class type in Java, but there is a crucial difference: a path-dependent type names an outer object, whereas an inner class type names an outer class

So in your case bInstance is related to an aInstance.

My assumption is that aInstance is the object passed as the first parameter to this constructor.

1
votes

You can use an unconstrained self-type annotation to have a way to refer to the A's version of this even from within B (where this now refers to the B instance).

package rrs.scribble

object  OuterInner {
  class Outer { oThis =>
    class Inner {
      def identify { printf("I am %s; I'm inside of %s%n", this, oThis) }
    }
    val inner = new Inner
  }

  def oiTest {
    val o1 = new Outer
    o1.inner.identify
  }
}

In the REPL:

Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).

scala> import rrs.scribble.OuterInner._
import rrs.scribble.OuterInner._

scala> oiTest
I am rrs.scribble.OuterInner$Outer$Inner@63d0d313; I'm inside of rrs.scribble.OuterInner$Outer@22d1b797
1
votes

First, adding A as the first constructor argument is also the way it works in Java:

If this Class object represents an inner class declared in a non-static context, the formal parameter types include the explicit enclosing instance as the first parameter.

Second,

What is argument with type A? I don't have access to A class from my function.

If you have a B (as seems from your example), then you can access its enclosing instance (it doesn't seem to be documented officially, and so may change in the future versions of Java):

val aInstance = bInstance.getClass.getDeclaredField("this$0").get(bInstance)
bCtor.newInstance(aInstance, ...)

If you don't, then you can't create a B (without an A), but you shouldn't be able to. What would you expect this code to return?

class A(foo: Int) {
  class B {
    def bar = foo
  }
}

classOf[A#B].getConstructor().newInstance().bar
0
votes

@evantill is right, the only constructor of B is A$B.<init>(A, Int). So bInstance.getClass.getConstructor(classOf[A], classOf[Int]) works.