Thread overview
How to use nested class with arsd.jni
Mar 04, 2020
fp
Mar 05, 2020
Adam D. Ruppe
Mar 05, 2020
fp
March 04, 2020
Hello,

I have a problem using nested class with arsd.jni. Here is the java class :

//
// File Outer.java
//
public class Outer {
    public class Inner {
      void printHello() {
          System.out.println("inner class");
      }
    }
}

//
// D code
//
import std.stdio;
import arsd.jni;
final class Outer : JavaClass!("", Outer) {
	@Import this();
	final class Inner : JavaClass!("", Inner)
	{
           // if thoses 2 imports are removed it compiles
           // but this() and printHello() cannot be called
	   @Import this();
	   @Import void printHello();
	}
}
void main()
{
	auto jvm = createJvm();
	auto o = new Outer();
	Outer.Inner inner = o.Inner();
        inner.printHello();
}

The compiler ends with an error: "source\app.d(44,8): Error: class app.Outer.Inner is forward referenced when looking for __ctor". If we remove the 2 @Imports inside Inner, it compiles but the methods are unreachable !
What is the correct way to declare/use the nested Inner class ?

Thanks.
March 05, 2020
On Wednesday, 4 March 2020 at 09:35:31 UTC, fp wrote:
> What is the correct way to declare/use the nested Inner class ?

Lemme hsow you the code first:

---
import std.stdio;
import arsd.jni;

final class Outer : JavaClass!("", Outer) {
	@Import this();
}

@JavaName("Outer$Inner") // the name here has teh separator dot replaced with a $. note it is the same  as the .class file if you need help figuring it out
final class Inner : JavaClass!("", Inner)
{
   @Import this(Outer); // then add a constructor taking the outer class as an arg
   @Import void printHello();
}


void main()
{
	auto jvm = createJvm();
	auto o = new Outer();
	// and then construct it like this
	Inner inner = new Inner(o);
        inner.printHello();
}
---



Basically, direct inner classes hit a bunch of compiler bugs, so the way to make it work is to flatten it, taking the inner class out and declaring as if it was a top-level thing. Which is what the JVM does internally and that's why it works btw.

If you try to add a convenience method in Outer for it, you're liable to hit a "forward reference" error, which is again a compiler bug brought on by the recursive reflection done inside jni.d (I hit more compiler bugs working on this project than I have in the last 5 years of writing D combined).

As seen above, you don't need to declare them together, but if you do want to try, just be sure Inner is declared before Outer in the file. Then you can do a `final` method (not @Import) that just `return new .Inner(this);` or something like that.

But I think you'll probably have better luck keeping it simple and flattening like this.
March 05, 2020
Ah, I was almost sure @JavaName had to be used for declaring Inner (I have made many trials !). But what I missed was the use of "Outer" as an argument of this(Outer) !
And also I was not sure about where to declare Inner.

Now it works. Thanks very much for your detailed answer and your general advice about the use of inner class.