Why does .getConstructor fail with a NoSuchMethodException despite zero-arg constructors existing for the class?

PeterAmbos
Wed, 12 Feb 2025 15:14:08 +0000
Coding Questions

I’m programming a game for a programming course in college, and I’ve run into some trouble with the .getConstructor method. What I’m trying to do is pass a class that has to be a subclass of another class as an argument into a method and create a new instance of that class there to do some other stuff with it. This is the code for the method:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;

class PlayerCharacter extends GameCharacter
{

  // other methods...

  class Inventory {

    // constructor

    void add(Class<? extends Ingredient> ingredientClass) {
      try {
        Constructor<? extends Ingredient> ingredientConstructor = ingredientClass.getConstructor();
        ingredientConstructor.setAccessible(true);
        Ingredient ingredient = ingredientConstructor.newInstance();

        // do stuff with ingredient

      }
      catch (NoSuchMethodException e) {
        e.printStackTrace();
        println("Constructor not available: " + e.getMessage());
      }
      catch (IllegalAccessException e) {
        println("Constructor can not be accessed: " + e.getMessage());
      }
      catch (InvocationTargetException e) {
        println("Exception in constructor: " + e.getCause().getMessage());
      }
      catch (InstantiationException e) {
        println("Class cannot be instantiated: " + e.getMessage());
      }
    }
  }
}

When running this though, I get the following exception:

java.lang.NoSuchMethodException: ice_creamillionaire$VanillaIceCream.<init>()
    at java.base/java.lang.Class.getConstructorO(Class.java:3585)
    at java.base/java.lang.Class.getConstructor(Class.java:2271)
    at ice_creamillionaire$PlayerCharacter$Inventory.add(ice_creamillionaire.java:800)
    at ice_creamillionaire$PlayerCharacter.interact(ice_creamillionaire.java:769)
    at ice_creamillionaire.keyPressed(ice_creamillionaire.java:55)
    at processing.core.PApplet.keyPressed(PApplet.java:2772)
    at processing.core.PApplet.handleKeyEvent(PApplet.java:2636)
    at processing.core.PApplet.dequeueEvents(PApplet.java:2262)
    at processing.core.PApplet.handleDraw(PApplet.java:2104)
    at processing.awt.PSurfaceAWT$9.callDraw(PSurfaceAWT.java:1388)
    at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:356)
Constructor not available: ice_creamillionaire$VanillaIceCream.<init>()

All the classes involved here (the subclass that is passed as an argument and all of its superclasses) have zero-argument constructors, though:

class Ingredient {
    PImage sprite;
    Class[] validBases;

    Ingredient() {
    }

    // other methods
}

class IceCream extends Ingredient {
    Class[] validBases = new Class[] {Waffle.class};

    IceCream() {
    }
}

class VanillaIceCream extends IceCream {
    PImage sprite = loadImage(IngredientSpriteRoot + "vanilla.png");

    VanillaIceCream() {
    }
}

I’ve done quite a bit of research on how .getConstructor should work, including the Java Documentation and topics that seem to handle similar code structures in Java. I’ve also tried .getDeclaredConstructor, but got the same exception. Following the research, I’ve also tried to make the constructors accessible using the public keyword, but that didn’t work either. My assumption is at this point that this might just not work in Processing due to all the code being wrapped in the PApplet, or (more likely), that I just missed something about how to use .getConstructor correctly. So I’d like to ask if someone can help me figure out what is going wrong here. I’d be very grateful for any help with this.

Note: this question, shortened due to platform restrictions, has also been posted by me to the #code-review channel of the Pirate Software Discord server.

11 posts - 4 participants