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;
}
}
}
}
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!";
}
}
(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!
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();
}
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 In that case perhaps you are misunderstanding something (instead, TfGuy44’s answer is perhaps something you want)