Load a java Class During Runtime, from outside the .jar.

Hey guys, im trying to load a class from otuside the .jar during runtime, but im being unable to.
Yes Opiop, i googled it the whole day, tried several methods, read a bunch of topics, but i get the same error.

Can anyone me guide me or give me any tip of some sort?

i have this class inside my jar

public class Script {

    public void Script()
    {
        
    }
    
    public void script(Player player, BitmapFont simpleWhiteFont) {

        int playerPosX = (int) (player.getX() / 16);

        int playerPosY = (int) ((player.getY() + player.getHeight() / 2) / 16); //(getY() + getHeight() / 2) / 16

    }
}

I have this class below in D:\

public class test extend Script
{

public String className = "script";


  public void script(Player player, BitmapFont simpleWhiteFont) {

       int playerPosX = (int) (player.getX() / 16);

       System.out.println("Player X Position : " + playerPosX );

    }

}

I tried this below:

  private void loadScript(String scriptLocation) {

        // Create a File object on the root of the directory containing the class file
        File file = new File("D:/");

        try {
            // Convert File to a URL
            URL url = file.toURI().toURL();      // file:/c:/myclasses/
            URL[] urls = new URL[]{url};

            // Create a new class loader with the directory
            ClassLoader cl = new URLClassLoader(urls);

            // Load in the class; MyClass.class should be located in
            // the directory file:/c:/myclasses/com/mycompany
            Class cls = cl.loadClass("test");
            script = (Script) cls.newInstance();
            script.script(player, simpleWhiteFont);
            
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

[quote]java.lang.ClassNotFoundException: test
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at br.views.levels.Level_Loader.loadScript(Level_Loader.java:70)
at br.views.levels.Level_Loader.<init>(Level_Loader.java:51)
at br.views.MenuView$3.clicked(MenuView.java:169)
at com.badlogic.gdx.scenes.scene2d.utils.ClickListener.touchUp(ClickListener.java:85)
at com.badlogic.gdx.scenes.scene2d.InputListener.handle(InputListener.java:57)
at com.badlogic.gdx.scenes.scene2d.Stage.touchUp(Stage.java:345)
at com.badlogic.gdx.backends.lwjgl.LwjglInput.processEvents(LwjglInput.java:303)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:200)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
Java Result: -1
[/quote]

I’m not entirely sure how to do this, as I didn’t write the code (Longor1996 did), but here’s the code for loading Paint.JAVA plugins.

It only works with class files inside external .jars though, but there should be a way around that.
Maybe it’ll help.

::slight_smile:

(EDIT: You shouldn’t be using [icode]File(“D:”)[/icode] because that will only work on Windows, and only if you have permission for that folder/drive. Use something more cross-platform and security-compatible like [icode]System.getProperty(“user.home”)[/icode])

For the sake of order and easier usage, you should go and just use the same Code as Paint.JAVA uses, as the Plugin-Code itself (which I did write) is Open-Source under the “DoWhatTheF***YouWantToThePublic”-License. You may need to change the names of a couple of classes though.

Also, Java can’t simply access any file that lies on the root level of any storage device. (Security problems and Co.)
You are making it even harder because you are trying to load a no-package and no-jar-packed class-file.

Read the plugin-loader code, understand it, then copy/implement it in your application.

Have a nice day.

  • Longor1996

Offtopic (sort of) but don’t call me out for asking you to Google things first. I realize some issues (such as this) cannot be solved using Google, so that’s fine. But some issues can be solved via Google. Don’t call me out on that.

Oh and by the way, I see what the problem with you code is.

You aren’t providing the actual path to load the class from.
You’re just pointing it at ‘D:’ when the files you need are in a subdirectory.

But that is irrelevant as it’s much easier just to take the Paint.JAVA code and adapt it for your purpose.

(Note: To clear things up, the code is licensed under the GPL, but that only applies if you directly use it. The ideas behind it are free for obvious reasons)

Hi guys, thanks for the replies.
Well Opiop, i understand.

Hero,
The class must be inside a .jar to be loaded? I was planning to load the .class directly.

It doesn’t have to be, AFAIK, but the code I pointed you to only works with .jar files, and when Longor tried to implement it for classes directly it didn’t work.
If you want more info, you’ll have to ask him.

But anyway, making a jar from a class file is easy:

jar -cfM [jarname] [list of class files]

Well it worked.
Kinda.
If i use reflection, it works, but if i try to cast it, it fails.

  private void loadScript() {

        //D:\resources\jarTest\dist
        // Create a File object on the root of the directory containing the class file
        File file = new File("D:\\resources\\jarTest\\dist\\ArcherScript0.1.jar");

        try {
            // Convert File to a URL
            URL url = file.toURI().toURL();      // file:/c:/myclasses/
            URL[] urls = new URL[]{url};

            // Create a new class loader with the directory
            ClassLoader cl = new URLClassLoader(urls);

            Class scriptLoaded = Class.forName("br.scripts.LevelScript", true, cl);

            Class<? extends Script> scriptClass = scriptLoaded.asSubclass(Script.class);
            
            script = scriptClass.newInstance();
            
            
//            Object[] paramObject = new Object[]{file};
//            Class<?>[] paramType = new Class[]{};
//
//            Method method = scriptLoaded.getMethod("test", paramType);
//            method.invoke(scriptLoaded.newInstance(), null);

            script.script(player, simpleWhiteFont);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

java.lang.ClassCastException: class br.scripts.LevelScript

In the outside jar, i mean , ArcherScript0.1.jar i have this classes :

package br.scripts;

/**
 *
 * @author André Vinícius Lopes
 */
public class LevelScript extends Script {

    
    
    public void test() {
        System.out.println("Test!");
    }
}

package br.scripts;

import com.badlogic.gdx.graphics.g2d.Sprite;

/**
 *
 * @author André Vinícius Lopes
 */
class Player extends Sprite{
}

package br.scripts;

import com.badlogic.gdx.graphics.g2d.BitmapFont;

/**
 *
 * @author André Vinícius Lopes
 */
public class Script {

    public void Script() {

    }

    public void script(Player player, BitmapFont simpleWhiteFont) {

    }

}

In my game .jar, the one im loading the class, i have this :

package br.views.levels.scripts;

import br.player.Player;
import com.badlogic.gdx.graphics.g2d.BitmapFont;

/**
 *
 * @author André Vinícius Lopes
 */
public class Script {

    public void Script()
    {
        
    }
    
    public void script(Player player, BitmapFont simpleWhiteFont) {

        int playerPosX = (int) (player.getX() / 16);

        int playerPosY = (int) ((player.getY() + player.getHeight() / 2) / 16); //(getY() + getHeight() / 2) / 16

    }
}


What am i doing wrong!?

I’ve provided an example of working code already.

I have limited knowledge of this stuff anyway, so if you’re not going to have a look at the code and try to adapt it for your purposes, then I can’t really help you with any problems you have.

I don’t know exactly what you’re doing wrong, but I can tell you that it’s most likely still in you script-loading code.

 // Try to load the class!
                                try
                                {
                                        //Load
                                        Class<?> c = cl.loadClass(className);
                                        
                                        // Check if the class is assignable from PluginBase (Is it a plugin?)
                                        if(Plugin.class.isAssignableFrom(c))
                                        {
                                                // The class is a Plugin main-class!
                                                // Cast it into the right type now...
                                                Class<? extends Plugin> pluginClass = c.asSubclass(Plugin.class);
                                                
                                                // Then try to instantiate it...
                                                try
                                                {
                                                        Plugin newPluginInstance = pluginClass.newInstance();
                                                        this.loadedPlugins.add(newPluginInstance);
 try {
            // Convert File to a URL
            URL url = file.toURI().toURL();      // file:/c:/myclasses/
            URL[] urls = new URL[]{url};

            // Create a new class loader with the directory
            ClassLoader cl = new URLClassLoader(urls);

            Class scriptLoaded = Class.forName("br.scripts.LevelScript", true, cl);

            Class<? extends Script> scriptClass = scriptLoaded.asSubclass(Script.class);
            
            script = scriptClass.newInstance();

I did read the code.
Some articles claims i must use an interface instead of extend.
Still i just wanted a 2nd opinion.
I can use Reflection but i will keep trying find a solution.

What about the bit before it:


// List Entries
			Enumeration<JarEntry> e = jarFile.entries();
			
			// Load JAR?
			URL[] urls = {new URL("jar:file:" + possiblePluginRoot.getAbsolutePath() + "!/")};
			
			// This should not be closed (or should it?)
			URLClassLoader cl = new URLClassLoader(urls);
			
			while(e.hasMoreElements())
			{
				JarEntry je = e.nextElement();
				
				if(je.isDirectory() || !je.getName().endsWith(".class"))
				{
					continue;
				}
				
				// Get the actual class-name!
				String className = je.getName().replace(".class", "");
				className = className.replace('/', '.');
				
				// Try to load the class! (the start of the bit you pasted)