0

I tried to change a classname by overriding the loadClass(String, Boolean) method.

I am creating a BukkitPlugin. The Bukkitsource can be found here

The classloader itself is working fine, i tested it and all the classes worked fine, the error started to occur after i started to change the classnames.

Here is the Method:

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;

import org.bukkit.plugin.java.JavaPlugin;

public class PluginClassLoader extends URLClassLoader {

    private final HashMap<String, String> replace;

    public PluginClassLoader(JavaPlugin p, HashMap<String, String> replace) throws Exception {
        super(new URL[0], p.getClass().getClassLoader());
        this.replace = replace;
        File f = null;
        Field file = JavaPlugin.class.getDeclaredField("file");
        file.setAccessible(true);
        f = (File) file.get(p);
        addURL(f.toURI().toURL());
    }

    private final HashMap<String, Class<?>> classes = new HashMap<>();

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        String s = replace.get(name);
        if(s != null)
            name = s;
        Class<?> c;
        try {
            c = findClass(name);
        } catch (Exception e) {
            c = super.loadClass(name);
        }
        return c;
    }




    @Override
    protected Class<?> loadClass(String name, boolean b)
        throws ClassNotFoundException {
        String s = replace.get(name);
        if(s != null)
            name = s;
        Class<?> c;
        try {
            c = findClass(name);
        } catch (ClassNotFoundException e) {
            c = super.loadClass(name, b);
        }
        return c;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if ((name.startsWith("org.bukkit."))
                || (name.startsWith("net.minecraft."))) {
            throw new ClassNotFoundException(name);
        }

        Class<?> result = classes.get(name);

        if (result == null) {
            result = super.findClass(name);
            classes.put(name, result);
        }
        return result;

    }
}

And when i use the classloader i get a NoClassDefFoundError everytime i use one of the replaced classes. My best guess is that i have to override another method, but I dont know what it could be.

The ErrorLog:

java.lang.NoClassDefFoundError: org/bukkit/craftbukkit/v1_5_R3/CraftServer
at me.leo.itemeffects.IEPlugin.onEnable(IEPlugin.java:25)
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:217)
at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:457)
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:381)
at org.bukkit.craftbukkit.v1_6_R2.CraftServer.loadPlugin(CraftServer.java:282)
at org.bukkit.craftbukkit.v1_6_R2.CraftServer.enablePlugins(CraftServer.java:264)
at net.minecraft.server.v1_6_R2.MinecraftServer.l(MinecraftServer.java:313)
at net.minecraft.server.v1_6_R2.MinecraftServer.f(MinecraftServer.java:290)
at net.minecraft.server.v1_6_R2.MinecraftServer.a(MinecraftServer.java:250)
at net.minecraft.server.v1_6_R2.DedicatedServer.init(DedicatedServer.java:151)
at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java:391)
at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:582)

IEPlugin.java:25 is this:

CraftServer server = (CraftServer) Bukkit.getServer();

The jvm is searching for the wrong classDefinition, it looks for the one with package 'v1_5_R3', but I replaced the name of the class in loadClass() with 'v1_6_R2'

I am replacing the classname 'org.bukkit.craftbukkit.v1_5_R3.CraftServer with 'org.bukkit.craftbukkit.v1_6_R2.CraftServer'

The class in the package with v1_5_R3 does not exist, that why i change it to v1_6_R2 in the loadClass(String, Boolean) Method

Thanks for reading and for your hopefully forthcoming solutions.

Leo
  • 11
  • 2
  • 7
  • First, show us your `NoClasDefFoundError`. Second, trying to rename a class like this is very stupid. – tbodt Jul 25 '13 at 19:53
  • Please share the error message, also instead of overriding the method why dont you change the class name which is String and then pass it to this method. – Sachin Thapa Jul 25 '13 at 20:18

2 Answers2

0

To start with, when you override a method it is preffered to write before it "@Override". Some programs like Eclipse, will tell you if the overriding is not corrent (if you ommited to obay some of the overriding rules)

Second of all, your class is protected, which means that it will be seen only in the package it is implemented. Are you sure the overriden class is in the same package as this one? It maybe that the reason for which you get such an error.

It is more likely to get help if you post a bigger part of your code. In that way, maybe someone will be able to tell you exactly where the problem is.

miha1908
  • 157
  • 1
  • 1
  • 6
0

Typically ClassNotFoundException means the current class is not found and NoClassDefFoundError means a dependent class for the currently loaded class is not found (See this stackoverflow thread). Probably your replaced class has a dependency which is not present in the classpath.

Community
  • 1
  • 1
Raji
  • 527
  • 3
  • 6
  • The jvm is searching for the wrong classDefinition, but the whole error is not printed in the console. The errorloag dosent show the 'real' cause. – Leo Jul 25 '13 at 22:40
  • Though you have replaced the class to be v1_6_R2, the classloader still started out loading v1_5_R3 class. So, I believe the error reported is still going to say v1_5_R3. You may want to replace the byte stream of v1_5_R3 with the bytestream of v1_6_R2, and call the defineClass instead of redirecting to loadClass again with the new class name. – Raji Jul 26 '13 at 02:15
  • The CraftServer class is found and returned without error, the error occures after the class is returned, i printed the class that the loader searches for and the class that the loader returns, and the serverclass is returned correctly. That means that the error is not thrown in loadclass, but somewhere else. – Leo Jul 26 '13 at 11:08