0

The purpose of my code below is to call the initialize() method all of the classes in a package that extend GsonLoader.

The error which I am receiving is:

java.lang.InstantiationException: com.salesy.utility.gson.impl.NPCSpawnsLoader
at java.lang.Class.newInstance(Unknown Source)
at com.salesy.utility.providers.FileClassLoader.getClassesInDirectory(FileClassLoader.java:22)
at com.salesy.utility.gson.GsonInitiator.initiate(GsonInitiator.java:18)
at com.salesy.Salesy.main(Salesy.java:43)

The error line has "ERROR LINE:" at the beginning of the line.

GsonLoader basic design (not all of the code):

public abstract class GsonLoader<T> {

/**
 * The child class must initialize to populate the hashmap of values.
 */
public abstract void initialize();


/**
 * The file location which data will be read from
 * 
 * @return The list of data
 */
public abstract String getFileLocation();

}

Example of a class extending GsonLoader:

public class NPCSpawnsLoader extends GsonLoader<NPCSpawnsLoader>{

@Override
public String getFileLocation() {
    return "data/loading/spawns.json";
}

@Override
public void initialize() {
    for (NPCSpawnsLoader spawns : load()) {
        hashmap.put(spawns.getId(), spawns);
    }
}

Loading of all the classes:

public class GsonInitiator {

/**
 * Loads all of the gson classes
 */
public static void initiate() {
    int count = 0;
    for (Object class1 : FileClassLoader.getClassesInDirectory(GsonLoader.class.getPackage().getName() + ".impl")) {
        GsonLoader<?> loader = (GsonLoader<?>) class1;
        loader.initialize();
        count++;
    }
    logger.info("Completely loaded " + count + " gson-loading classes.");
}

private static final Logger logger = Logger.getLogger(GsonLoader.class.getName());

}

Child class constructor:

public NPCSpawnsLoader(int x, int y, int z, int id, Direction direction) {
    this.id = id;
    this.x = x;
    this.y = y;
    this.z = z;
    this.direction = direction;
}

FileClassLoader#getClassesInDirectory:

public static List<Object> getClassesInDirectory(String directory) {
    List<Object> classes = new ArrayList<Object>();
    for (File file : new File("./src/" + directory.replace(".", "/")).listFiles()) {
        try {
            [ERROR LINE:]Object objectEvent = (Class.forName(directory + "." + file.getName().replace(".java", "")).newInstance());
            classes.add(objectEvent);
        } catch (InstantiationException | IllegalAccessException
                | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    return classes;
}

What am I to do?

rpax
  • 4,468
  • 7
  • 33
  • 57
Tyluur
  • 91
  • 1
  • 2
  • 9
  • Where do you call Class.newInstance? That's what is throwing the exception and I don't see it anywhere. Or maybe it's happening in the load method but I don't see that anywhere either. – Radiodef Oct 27 '13 at 00:52
  • getClassesDirectory calls it. The code for that method is the last block of code above "What am I to do"?. It's right above classes.add(objectEvent); – Tyluur Oct 27 '13 at 00:54
  • Okay I see it, thanks. Are you trying to instantiate at all any instances of GsonLoader (the abstract superclass)? I assume not deliberately but that's the only criteria I see that could throw the exception in your code. The problem is apparently this exception can be thrown for reasons that are not stated in the docs. My recommendation would be to try instantiating them with a Constructor object because the exceptions thrown don't have a vague case like Class.newInstance (that I know of). – Radiodef Oct 27 '13 at 01:05
  • Here's another question. Are you instantiating inner classes? This exception can also be thrown in that case if the inner classes aren't declared static. That would be one of the "undocumented" reasons. – Radiodef Oct 27 '13 at 01:21
  • What do you mean instantiating inner classes? I am initiating all of the classes in the "impl" package. – Tyluur Oct 27 '13 at 01:24
  • If any of the classes you try to instantiate are an inner class you'll get this exception thrown if they aren't declared as static. `class A { public A() { try { B b = B.class.newInstance(); } catch (Exception e) {} } class B {} }` will throw this exception, B needs to be declared as `static class B`. It's one of the reasons not listed in the doc (falls under the "not limited to" clause): http://docs.oracle.com/javase/7/docs/api/java/lang/InstantiationException.html – Radiodef Oct 27 '13 at 01:32
  • That is not similar to the problem I am having. This is due to the class GsonLoader { – Tyluur Oct 27 '13 at 01:49
  • If your subclasses of GsonLoader are inner classes (of any class) then it is. That's what I asked. If the answer is "no" then obviously it is not the problem. I don't otherwise see how this exception can be thrown because Class.forName should "guard" against the clause of the class not existing (due to whatever reason). The generics should not matter because your subclasses appear to declare the type. Otherwise, again, I'd recommend using a Constructor object for newInstance because the exceptions are a little more specific. – Radiodef Oct 27 '13 at 01:53
  • The child class has a constructor with predefined parameters which are set when the gson loader reads the file location and loads the data into the List. – Tyluur Oct 27 '13 at 02:23
  • Updated main post with child class constructor. – Tyluur Oct 27 '13 at 02:23
  • That must be your problem then. You have to use a Constructor object if you want to provide parameters to a constructor with newInstance. Class.newInstance only works for the no-argument constructor. – Radiodef Oct 27 '13 at 02:27
  • But that child constructor must be there for the gson loader to work. – Tyluur Oct 27 '13 at 02:36
  • You can invoke that constructor, you just have to use a Constructor object: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html Otherwise you have to explicitly provide a no-argument constructor for the subclasses or Class.newInstance throws the exception. – Radiodef Oct 27 '13 at 02:38
  • I do not understand how to use the Constructor object to generate a new instance of the child class. – Tyluur Oct 27 '13 at 02:43
  • 1
    Do you understand what you are doing when you call Class.newInstance? It's the same thing except you can invoke any constructor. Class.newInstance only invokes the no-argument constructor. You need to either call Class.getConstructors or Class.getConstructor and invoke newInstance on a returned Constructor object with the arguments of the subclass constructor. I would write an answer with a code example that shows how to use Constructor but the tutorial provides one. If you don't understand what Class.newInstance does I suggest you start at the beginning of the reflection tutorial. – Radiodef Oct 27 '13 at 02:53

0 Answers0