#Class loading

1 messages · Page 1 of 1 (latest)

dawn dove
#

I have a large project for which I have an API. The API is standalone and is shaded into my main project. I then load any addons with this code:

        try {
            URLClassLoader loader = new URLClassLoader(new URL[] { file.toURI().toURL() }, Helix.class.getClassLoader());
            try (loader) {
                YmlConfig yml = YmlConfig.parse(loader.getResourceAsStream("addon.yml"));
                if (!yml.contains("addon")) {
                    throw new AddonException("no 'addon' section for addon '" + file.getPath() + "'");
                }

                Class<?> main = loader.loadClass(yml.get("addon").getString("main"));
                return new Addon((HelixAddon) Reflections.getInstance(main));
            }
        } catch (Throwable e) {
            throw new AddonException(e);
        }

Though while loading this addon I get the following error

package com.sniskus.helix.addon;

import com.sniskus.helix.api.HelixAddon;
import com.sniskus.helix.api.attribute.Domain;
import com.sniskus.helix.api.attribute.element.Function;

public class Test implements HelixAddon {

    @Override
    public void onLoad() {
        HelixApi.getApi().getDomain(this).register(new Function<Void, Void>() {
                    // code (i've hit character limit lol)
        });
    }
}

error: ```
[15:46:53 WARN]: java.lang.NoClassDefFoundError: com/sniskus/helix/addon/Test$1
[15:46:53 WARN]: at com.sniskus.helix.addon.Test.onLoad(Test.java:34)
[15:46:53 WARN]: at Helix-3.2.1.jar//com.sniskus.helix.api.impl.ApiImpl.lambda$0(ApiImpl.java:31)
[15:46:53 WARN]: at java.base/java.util.HashMap$KeySet.forEach(HashMap.java:1016)
[15:46:53 WARN]: at Helix-3.2.1.jar//com.sniskus.helix.api.impl.ApiImpl.loadAddons(ApiImpl.java:29)
[15:46:53 WARN]: at Helix-3.2.1.jar//com.sniskus.helix.Helix.onPluginEnable(Helix.java:115)
[15:46:53 WARN]: at Yggdrasil-2.1.1.jar//com.sniskus.yggdrasil.plugin.YPlugin.onEnable(YPlugin.java:40)
[15:46:53 WARN]: at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:288)
[15:46:53 WARN]: at io.papermc.paper.plugin.manager.PaperPluginInstanceManager.enablePlugin(PaperPluginInstanceManager.java:202)
[15:46:53 WARN]: at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.enablePlugin(PaperPluginManagerImpl.java:109)
[15:46:53 WARN]: at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:520)
[15:46:53 WARN]: at org.bukkit.craftbukkit.CraftServer.enablePlugin(CraftServer.java:640)
[15:46:53 WARN]: at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:589)
[15:46:53 WARN]: at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:753)
[15:46:53 WARN]: at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:515)
[15:46:53 WARN]: at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:329)
[15:46:53 WARN]: at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1214)
[15:46:53 WARN]: at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:329)
[15:46:53 WARN]: at java.base/java.lang.Thread.run(Thread.java:1583)
[15:46:53 WARN]: Caused by: java.lang.ClassNotFoundException: com.sniskus.helix.addon.Test$1
[15:46:53 WARN]: at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
[15:46:53 WARN]: at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
[15:46:53 WARN]: at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
[15:46:53 WARN]: ... 18 more

stuck raptorBOT
#

<@&987246652869971988> please have a look, thanks.

dawn dove
#

The Function and HelixAddon are both in the same project. And since HelixAddon apparently exists I can't figure out why Function does not...

onyx socket
dawn dove
#

Ah ok. So I how’d I solve it? Do I have to load all classes in the addon manually?

#

That’s seems unresonable.

onyx socket
#

Where does the file variable point to?

dawn dove
#

To the addon .jar.

onyx socket
#

And all related classes are contained within it, right?

dawn dove
#

Correct.

onyx socket
#

Use URLClassLoader#loadClass(Class<?>, boolean) overload.

dawn dove
#

Where ’cls’ is what? The main class?

onyx socket
#

Just pass true to the loader.loadClass.

#

The second argument decides whether the class should be resolved or not. Resolution step is also responsible for ensuring all dependent classes are loaded as well

dawn dove
#

Ah ok, got it! I’ll give it a go!

rugged ivy
onyx socket
#

A fair question btw ☝️

#

Maybe using an SPI would be sufficient for your task?

#

Instead of manually loading jar files, you can simply add them to classpath. java.util.ServiceLoader will do the rest for you. Read its javadoc for more details

dawn dove
#

I don’t really know how else to go about doing it? Not familiar with SPI?
Also I know catching throwables is a big no no, but if an error is thrown in the constructor of the addon my entire software will crash etc.. I usually don’t catch throwables but since I don’t know what the addons do or what they throw I catch it all to save my plugin.

onyx socket
onyx socket
#

TBH you must never catch any Errors

dawn dove
dawn dove
lucid edge
#

or not maybe

#

hmm

onyx socket
#

I originally wanted to suggest using Class#forName, but since you were using a custom class loader, I thought it won't work. But it actually has an overload that does exactly what is required: Class#forName(String name, boolean initialize, ClassLoader loader).

dawn dove
#

omfg I'm dumb. I initially had that but came across another class error so tried ClassLoader#loadClass. Thank you :)

#

Problem solved!

onyx socket
#

Haha yeah :^)

#

You learn something new every day. You're welcome

dawn dove
#

Hold on. I'm back 💀

#

I messed around with SPIs a bit to see if I could use it, by mistake i disabled my Addon loading code so the addon was not loaded and consequently no exception was thrown lol. I'm still stuck xd

rugged ivy
dawn dove
#

I don’t really understand your question but think that was it?

dawn dove
stuck raptorBOT
#

Closed the thread.