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:
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; 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!