I'm making a game engine and an integral part of the game is that it populates worlds based on maps loaded from a XML file, a method "Actor load(Map<String, String> code)" in a class ActorLoader takes a map and returns an actor based on this map. When you make a game using this engine you have a main package and a subpackage called actors that has the classes for the actors.

Before, ActorLoader was abstract and was subclassed with load overloaded in the main project to something like this

String role = code.get("Role");
        if(role.equals("Wulf")){
            return new Wulf(code);
        }else if(role.equals("Obstacle")){
            return new Obstacle(code);
        }else if(role.equals("Bullit")){
            return new Bullit(code);
        }else if(role.equals("Switch")){
            return new Switch(code);
        }else if(role.equals("Spikes")){
            return new Spikes(code);
        }else if(role.equals("Exit")){
            return new Exit(code);
        }else if(role.equals("Camera")){
            return new Camera(code);
        }else if(role.equals("Door")){
            return new Door(code);
        }else if(role.equals("Scenery")){
            return new Scenery(code);
        }else if(role.equals("Physics")){
            return new Physics(code);
        }else if(role.equals("RobotBunny")){
            return new RobotBunny(code);
        }else{
            throw new NoSuchRoleException();
        }

Basically, each actor you add to the game needs a new branch in the if statement. But somebody looked at my code and suggested I use reflection instead and now I've got this, it doesn't do anything yet beside getting a class, I'm just experimenting.

try {
            Class c = Class.forName(nameOfMainPackage + ".actors." + code.get("Role"));
        } catch (ClassNotFoundException ex) {}

Now, this gets the correct class, and from here I can get get a constructor from that class to make the actor, so I was planning to put this code in the base ActorLoader class so it doesn't needed to be overloaded. But there is one small thing, would I have to tell the ActorLoader what the main package is or is there a way I can "ask" Java what it is?

I don't think that's quite what I'm looking for, but almost immediately after posting this I thought to myself, "The program starts in the main class, so if I could get a stack trace the main class would be at the top of the stack trace, and of course the main class would be in the package I'm looking for."

So far the following code works for me so far.

public Actor load(Map<String, String> code) throws IOException, NoSuchRoleException{
        try {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            String mainClass = stackTrace[stackTrace.length-1].getClassName();
            Class theClass = Class.forName(mainClass.substring(0, mainClass.indexOf(".")) + ".actors." + code.get("Role"));
            Class []parameters = {Map.class};
            Constructor constructor = theClass.getConstructor(parameters);
            Actor a = (Actor)constructor.newInstance(code);
            return a;
        } catch (InstantiationException ex) {
            Logger.getLogger(ActorLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ActorLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(ActorLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(ActorLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchMethodException ex) {
            Logger.getLogger(ActorLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Logger.getLogger(ActorLoader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
        }
        return null;
    }

Edited 6 Years Ago by OffbeatPatriot: n/a

It seems as though a better solution to your problem might be using the Type Object pattern. Creating new classes for new actors created which basically end up doing almost the same thing is pretty bad from a maintenance view point. Not to mention that your previous code snippets abuse the stack trace in the awesomest possible way. :)

This article has been dead for over six months. Start a new discussion instead.