Uploaded image for project: 'Spigot'
  1. Spigot
  2. SPIGOT-4255

JavaPlugins cannot find classes loaded by custom classloaders.

XMLWordPrintable

    • Icon: New Feature New Feature
    • Resolution: Unresolved
    • Icon: Minor Minor
    • None
    • None
    • Windows:
      Windows 10 Enterprise 64 bits (10.0, build 17134)

      Java:
      java version "10" 2018-03-20
      Java(TM) SE Runtime Environment 18.3 (build 10+46)
      Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)

    • git-Spigot-0b44fa0-49a2604
    • ScalaLoader
    • Yes

      Related to https://hub.spigotmc.org/jira/browse/SPIGOT-3723.

      I have a pluginloader that loads classes from jar files through a custom classloader. When other plugins use those classes a NoClassDefFoundError is thrown. I implemented a hacky workaround to inject the classes in the JavaPluginLoader using reflection but this is obviously not a good solution.

      PluginLoaders that generate classes at runtime will suffer from the same issue.

      The cause:
      JavaPlugins are loaded by the PluginClassLoader. This classloader can find classes from the plugin itself, classes from other JavaPlugins (through JavaPluginLoader) and it can find classes from the parent classloader.

      Proposed solutions:
      1. Make PluginClassLoader an interface with two abstract methods: Class<?> find(String className, boolean global) and Set<Class<?>> getClasses(). The current PluginClassLoader can be refactored to JavaPluginClassLoader because really, it only loads JavaPlugins. Other plugins that provide custom pluginloaders can register those classloaders with the JavaPluginLoader. In addition JavaPluginClassLoader no longer has to extend URLClassLoader as mentioned in the other issue.
      2. (my preferred solution) Make the constructor of PluginClassLoader protected so that it can be extended. The JavaPluginLoader may search in the plugin.yml which PluginClassLoader implementation it should use to load the plugin. PluginClassLoaders still create the Plugin instances. The default should be the existing PluginClassLoader of course.

      I prefer the second solution because

      1. Custom PluginClassLoaders can use already-existing singleton instances of plugins such as generated by Scala and Kotlin object keywords. No need for a public NoArgsConstructor in the plugin's main class.
      2. No need to overwrite the default "
        .jar$" file assiation with a custom pluginloader as I'm doing now in my ScalaLoader plugin.
      3. Benefit from the built-in api-version check and classbytes transformations.

        1. 2018-08-07-15.log
          17 kB
        2. DummyPlugin.java
          0.7 kB
        3. ExamplePlugin.scala
          2 kB
        4. Home.scala
          0.6 kB
        5. plugin.yml
          0.2 kB

            Unassigned Unassigned
            Jannyboy11 Jan Boerman
            Votes:
            10 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: