Java - dynamic class loading

I am currently creating a plugin system (my first attempt) by looking at other people's code. I'm trying to build my own class loader and load plugins from the directory (these will be class files)

My problem is that whenever I try to load a class with my class loader, any import data in the plugin that references the program is not found by the class loader. (i.e. MyClass extends the plugin, com.mgmc.plugins noclassdeffound) Different namespace?

Code Example: Class Loader:

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.mcgm.game.provider; import com.mcgm.utils.Misc; import com.mcgm.utils.Paths; import java.awt.AWTPermission; import java.io.*; import java.net.MalformedURLException; import java.net.SocketPermission; import java.net.URL; import java.security.CodeSigner; import java.security.CodeSource; import java.security.Permissions; import java.security.ProtectionDomain; import java.util.PropertyPermission; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Tom */ public class GameClassLoader extends ClassLoader { private final ProtectionDomain domain; private final URL base; public GameClassLoader(final URL url) { base = url; final CodeSource codeSource = new CodeSource(base, (CodeSigner[]) null); domain = new ProtectionDomain(codeSource, getPermissions()); } public void loadGames() { for (File f : Paths.compiledFolder.listFiles()) { try { Class c = loadClass(f.getPath()); Misc.outPrint(c.getName()); } catch (ClassNotFoundException ex) { Logger.getLogger(GameClassLoader.class.getName()).log(Level.SEVERE, null, ex); } } } private Permissions getPermissions() { final Permissions ps = new Permissions(); ps.add(new AWTPermission("accessEventQueue")); ps.add(new PropertyPermission("user.home", "read")); ps.add(new PropertyPermission("java.vendor", "read")); ps.add(new PropertyPermission("java.version", "read")); ps.add(new PropertyPermission("os.name", "read")); ps.add(new PropertyPermission("os.arch", "read")); ps.add(new PropertyPermission("os.version", "read")); ps.add(new SocketPermission("*", "resolve")); ps.add(new FilePermission(Paths.compiledFolder.getPath(), "read,write,delete")); ps.setReadOnly(); return ps; } @Override @SuppressWarnings("rawtypes") public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException { Class clazz = findLoadedClass(name); if (clazz == null) { try { byte[] bytes = loadClassData(name); clazz = defineClass(name, bytes, 0, bytes.length, domain); if (resolve) { resolveClass(clazz); } } catch (final Exception e) { clazz = super.loadClass(name, resolve); } } return clazz; } public byte[] loadClassData(final String name) { try { final InputStream in = getResourceAsStream(name.replace('.', '/') + ".class"); final byte[] buffer = new byte[4096]; final ByteArrayOutputStream out = new ByteArrayOutputStream(); int n; while ((n = in.read(buffer, 0, 4096)) != -1) { out.write(buffer, 0, n); } return out.toByteArray(); } catch (IOException ex) { Logger.getLogger(GameClassLoader.class.getName()).log(Level.SEVERE, null, ex); } return null; } @Override public URL getResource(final String name) { try { return new URL(base, name); } catch (final MalformedURLException e) { return null; } } @Override public InputStream getResourceAsStream(final String name) { try { return new URL(base, name).openStream(); } catch (final IOException e) { return null; } } } 

Plugin that I download: (Annotations also not found)

 import com.mcgm.GameInfo; import com.mcgm.game.Minigame; @GameInfo(name = "RandomGame", description = "A really long and boring game.", authors = {"Tom", "Is", "The", "Greatest"}, version = 0.1, maxPlayers = 100, teamBased = false, teamAmount = -1, PvP = false) public class game extends Minigame { } 

How do I call the class to load:

  GameClassLoader classLoader = new GameClassLoader(Paths.compiledFolder.toURI().toURL()); classLoader.loadClass("game", true); 

I think this is trivial for those who know what they are doing!

+8
java plugins class dynamic classloader
source share
2 answers

FINALLY! After one and a half days of searching, Vulcan pointed me in the right direction: I changed GameClassLoader to:

 public GameClassLoader(final URL url, ClassLoader parent) { super(parent); 

and finally added the base url to getResourceAsStream ()

 final InputStream in = getResourceAsStream(base.getFile() + "/" + name.replace('.', '/') + ".class"); 

Thanks so much for helping the guys!

+4
source share

Try adding a leading slash to the resource path: final InputStream in = getResourceAsStream("/" + name.replace('.', '/') + ".class");

This is what I should try every time I call getResourceAsStream() . I just tried this for you again. The path here refers to the class package that is used to call getResourceAsStream() , so a leading slash is needed to say β€œstart with root”.

0
source share

All Articles