Instantiate one class inside another using a third

Hello again!

I can’t figure out how to use reflection to instantiate one class inside another using a third class. I feel like I’m close…

The goal in this example is to instantiate A.b inside C.

import java.lang.reflect.*;

void setup(){
  A a = new A();
  a.hello();
}

class A {
  String s;
  B b;
  
  A(){
    C c = new C(this);
  }
  
  void hello(){
    println("hello from A!");
    println("s:",s);
    b.hello();
  }
}

class B {
  B(){}
  
  void hello(){
    println("hello from B!");
  }
}

class C {
  
  <T> C ( T obj ){
    
    Class someClass = obj.getClass();
    println("setting fields for instance of class:",someClass.getSimpleName());
    
    Field[] allFields = someClass.getDeclaredFields();
    
    for (Field field : allFields){
      Class type = field.getType();
      print("field",field.getName(),"is type:",type);
      
      switch(type.getSimpleName()){
        
        case "String"    : println(" is a String");
                           try {
                             field.set(obj, "A happy little string");
                           } catch (Exception e) { }
                           break;
                           
        default           : println(" is custom class:",type.getSimpleName());
                            // somehow magically instantiate A.b = new B();
                            try {
                              Class<?> c = Class.forName( type.getName() );
                              println("c:",c);
                              field.set(obj, c);
                            } catch (ClassNotFoundException e){ println(e);
                            } catch (Exception e) { println(e); }
                            break;
      }
    }
  }
}

You’re over-complicating this.

void setup() {
  size(200,200);
  A a = new A();
  a.hello();
}

void draw(){
  background(0);
}

class A {
  String s;
  B b;
  
  A() {
    C c = new C(this);
    c.snakes();
  }

  void hello() {
    println("hello from A!");
    b.hello();
    println(s);
  }
}

class B {
  B() {
  }

  void hello() {
    println("hello from B!");
  }
}

class C {
  A parent;
  C ( A in_a ) {
    parent = in_a;
    parent.b = new B();
  }
  void snakes(){
    parent.s = "Snakes! Argh!";
  }
}

Please don’t make me explain this…

Please don’t make me explain this…

I won’t.

My example is simplified for what I’m attempting to do. I do need to use reflection, so your example doesn’t pertain.

(Disclaimer: I’m not familiar with this but researched out of curiosity. What I explain is just gathered from online resources, mostly stackoverflow…)

so the first problem is that

Class<?> c = Class.forName( type.getName() );

is just a Class and not an instance. So usually you have to do this to instantiate:

c.newInstance();

but you will get InstantiationException error, which seems to happen when you don’t have a default constructor. But B does, and here comes the second problem - Processing wraps the code in PApplet, so you need to use .java extension so that the interpreter won’t wrap your code in there.

I ended up with two files, first the main pde file

void setup(){
  A a = new A();
  a.hello();
}

and abc.java

import java.lang.reflect.*;

class A {
  String s;
  B b;
  
  A(){
    C c = new C(this);
  }
  
  void hello(){
    //println("hello from A!");
    //println("s:",s);
    b.hello();
  }
}

class B {
  B(){}
  
  void hello(){
    System.out.println("hello from B!");
  }
}

class C {
  
  <T> C ( T obj ){
    
    Class someClass = obj.getClass();
    //println("setting fields for instance of class:",someClass.getSimpleName());
    
    Field[] allFields = someClass.getDeclaredFields();
    
    for (Field field : allFields){
      Class type = field.getType();
      //print("field",field.getName(),"is type:",type);
      
      switch(type.getSimpleName()){
        
        case "String"    : //println(" is a String");
                           try {
                             field.set(obj, "A happy little string");
                           } catch (Exception e) { }
                           break;
                           
        default           : //println(" is custom class:",type.getSimpleName());
                            // somehow magically instantiate A.b = new B();
                            try {
                              Class<?> c = Class.forName( type.getName() );
                              //println("c:",c.getClass());
                              field.set(obj, c.newInstance());
                            } catch (ClassNotFoundException e){ //println(e);
                            } catch (Exception e) { //println(e);
                          }
                            break;
      }
    }
  }
}

note that in .java file you cannot use Processing specific functions like println!

Thank you for the reply, micaut.

I had forgotten about c.newInstance();

It would seem, then, as you suggest, that this should work:

Class<?> c = Class.forName( type.getName() );
field.set(obj, c.newInstance());

…but it doesn’t… :frowning:

Did you read the second part, which I wrote about .java extension?

Yes… but not very carefully, admittedly.

It may be foolhardy, but I’m not giving up (yet)…

sorry I don’t understand what you mean. I gave you a full answer. Did it work for you?

Hi. Sorry for my confusing answer.

I just got it working. Thank you for your suggestions – it helped.

I forgot that I needed separate tabs for the PApplet inner classes. So I created separate tabs for each A,B,C.

Here’s the setup:

import java.lang.reflect.*;

final String THISPROC = this.getClass().getCanonicalName();
public final PApplet PAPPLET = this;

void setup(){
  A a = new A();
  a.hello();
}

And here’s the switch command inside C:

      switch(type.getSimpleName()){
        
        case "String"    : println(" is a String");
                           try {
                             field.set(obj, "A happy little string");
                           } catch (Exception e) { }
                           break;
                           
        default           : println(" is custom class:",type.getSimpleName());
                            // somehow magically instantiate A.b = new B();
                            try {
                              Class<?> innerClass = Class.forName(THISPROC + "$" + type.getSimpleName() );
                              Constructor<?> ctor = innerClass.getDeclaredConstructor( PAPPLET.getClass() );
                              Object o = ctor.newInstance(PAPPLET);
                              field.set(obj, o);
                            } catch (InstantiationException e) { println(e);
                            } catch (IllegalAccessException e) { println(e);
                            } catch (ClassNotFoundException e){ println(e);
                            } catch (Exception e) { println(e); }
                            break;
      }
    }

I’m getting a ClassNotFoundException from somewhere, and yet I nevertheless get the string hello from B! in stdout.

So it seems to be working, yet I’m a little mystified that it is…

Update1: Oh, I just figured out why I was getting the exception… The class A itself – ie: this$0 – enters the default switch case… I’ll just ignore it so I don’t get the exception…

Update 2:
Class<?> innerClass = Class.forName(someClass.getTypeName().split("\\$")[0] + "$" + type.getSimpleName() );
can be used instead of
Class<?> innerClass = Class.forName(THISPROC + "$" + type.getSimpleName() );
This eliminates the need for the global variable THISPROC (thus making it easier to compile).

glad that you figured it out! (and yes, it’s trying to instantiate this as well, which I should have mentioned…)

By the way if anyone else came here, the code can potentially do very wrong things so if you don’t know what you’re doing I advise not to use the code above :slight_smile: In that case perhaps you are misunderstanding something (instead, TfGuy44’s answer is perhaps something you want)