Thijs Dalhuijsen
Thijs Dalhuijsen

Reputation: 778

Unhandled exception type: InstantiationException in processing.org

I'm trying to do a simple Class.newInstance() from within processing, but I'm failing :(

EDIT: as below instructed, the reason it didn't work was that Processing wraps all code into a class making all declared classes internal classes. The java language specification states that newInstance() for internal classes should be passed a reference to the container class, so after changing the call to newInstance to newInstance(this); it worked as intended.

code sample below of where it throws an InstantiationException.

Docs said to have a public constructor and that everything would be fine, but alas.

running processing 2.2.1

Codeflow: it fills up a list of all classes that implement an interface. then we go through state.runnableTypes and try (but fail) to instantiate a new instance of that type.

Please help?

(apologies for the clunky state variable, has to do with an even clunkier ryo unit test system ;))

    State state;
/* It nicely finds the Wtf class and inserts that into its classes array, 
 * but when i try to instantiate a new one, whatever I try, it throws :(
 */
void setup() {
  size(1024, 768, P3D);
  noLoop(); 
//get all the classes
  state = new State();
  Class[] types = this.getClass().getDeclaredClasses();
  state.allTypes = types;

  //enumerate castable types
  for (int i = 0, l = types.length; i<l; i++) { 
    Class c = types[i];
    if ( !c.isInterface() && IMenuRunnable.class.isAssignableFrom(c) ) { 
      println("adding "+c.toString());
      state.runnableTypes.put(c.getSimpleName(), c);
    }
  }

  //loop through the list and create some instances //FIXME: Exception handling ;p
  for ( String s : state.runnableTypes.keySet () ) { 
    Class c = state.runnableTypes.get(s);
    IMenuRunnable u = (IMenuRunnable) c.newInstance(); // ERR: calling Class.newInstance() here throws an error??
    java.lang.reflect.Constructor[] ctors = c.getConstructors();
    for ( java.lang.reflect.Constructor ctor : ctors ) { 
      ctor.setAccessible(true);
      Object o = ctor.newInstance(); // ERR: going via constructor array, same error :(
    }
  }
}




void draw() { 
  background(0);
}




class State {
  Class[] allTypes;
  HashMap<String, Class> runnableTypes = new HashMap<String, Class>();
}



interface IMenuRunnable {
}



public class Wtf implements IMenuRunnable { 
  public Wtf() {
  }
}

Upvotes: 5

Views: 3568

Answers (1)

Kevin Workman
Kevin Workman

Reputation: 42176

First of all, your code does not compile, because you need to wrap newInstance() in a try/catch block. The newInstance() function can throw an InstantiationException or an IllegalAccessException, so you have to catch those Exceptions. That's what your error is telling you.

You'll have better luck if you post an MCVE, such as this one:

void setup() {
  try {
    Class<Wtf> c = Wtf.class;
    IMenuRunnable u = (IMenuRunnable) c.newInstance();
    println(u.toString());
  }
  catch(Exception e) {
    e.printStackTrace();
  }
}

interface IMenuRunnable {}

public class Wtf implements IMenuRunnable{ 
  public Wtf() {
  }
}

But even after you fix that, you'll get a runtime exception because behind the scenes, classes you declare in your sketch are inner classes of your sketch class. You can't use reflection on inner classes the way you're trying to.

So you either need to change the way you're declaring those classes, or you need to change the way you're doing reflection.

To make sure that Processing does not turn those classes into inner classes of your sketch, you have to define them in their own .java tabs. Use the name of the class followed by .java, so Processing knows that it's a Java class, not a "Processing class", which gets converted into an inner class. Your setup would look like this:

screenshot of pde

With that approach, you'd have to pass in an instance of your sketch to the java classes in order to access any Processing methods. Instead, you might want to just change how you're doing your reflection. Since the classes are inner classes of your sketch class, you have to go through the sketch class to get to them:

void setup() {
  try {

    Class<?> sketchClass = Class.forName("sketch_150702a");
    Class<?> innerClass = Class.forName("sketch_150702a$Wtf");

    java.lang.reflect.Constructor constructor = innerClass.getDeclaredConstructor(sketchClass);

    IMenuRunnable u = (IMenuRunnable)constructor.newInstance(this);
    println(u.toString());
  }
  catch(Exception e) {
    e.printStackTrace();
  }
}

interface IMenuRunnable {
}

public class Wtf implements IMenuRunnable { 
  public Wtf() {
  }
}

Alternatively, you could just declare your Wtf class as static:

void setup() {
  try {
    Class<Wtf> c = Wtf.class;
    IMenuRunnable u = (IMenuRunnable) c.newInstance();
    println(u.toString());
  }
  catch(Exception e) {
    e.printStackTrace();
  }
}

interface IMenuRunnable {}

static public class Wtf implements IMenuRunnable{ 
  public Wtf() {
  }
}

Of course, then you wouldn't be able to access non-static members of your sketch class, so which approach you take really depends on exactly what you need to do.

Upvotes: 3

Related Questions