You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Jar运行Weka报错:找不到weka.clusterers.Canopy类

Fixing Weka ClassNotFoundError in Spring Boot Uber-Jar

Hey there, let's break down why you're hitting that Can't find a permissible class called: weka.clusterers.Canopy error when running your Spring Boot uber-jar, even though everything works smoothly in Eclipse.

The Root Cause

Spring Boot builds an uber-jar with nested JARs (your weka-stable jar is packaged inside the main Spring Boot jar). Eclipse uses a flat classpath setup, so its classloader can easily locate Weka classes. But when running the uber-jar, Spring Boot uses its own LaunchedURLClassLoader to load resources from nested JARs. The problem is that Weka's Utils.forName() method (used under the hood in AbstractClusterer.forName() and AddCluster.setOptions()) defaults to using the system classloader—which can't access classes inside nested JARs, hence the error even though the Canopy class is present.

Solutions to Try

1. Switch the Context ClassLoader Before Weka Code Runs

A quick, code-based fix is to set the current thread's context classloader to the one that loaded your application classes (which has access to nested Weka resources). Add this line right before your Weka-related logic executes:

// Place this in ClusterDetector.calculateClusterCentroids() or PredictiveController.getClusterCentroids()
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// Then run your Weka code (like AddCluster.setOptions())

This tells Weka's classloading logic to use the correct classloader that can see the nested Weka classes.

2. Configure Spring Boot Maven Plugin to Unpack Weka JAR

If you prefer a configuration-only fix, you can tell the Spring Boot Maven plugin to unpack the Weka JAR into the uber-jar instead of nesting it. This makes Weka classes available to the system classloader directly.

Add this to your pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <requiresUnpack>
                    <dependency>
                        <groupId>nz.ac.waikato.cms.weka</groupId>
                        <artifactId>weka-stable</artifactId>
                        <version>3.8.1</version> <!-- Match your Weka version -->
                    </dependency>
                </requiresUnpack>
            </configuration>
        </plugin>
    </plugins>
</build>

Rebuild your uber-jar, and Weka's classes will be stored flat in the classes directory of the jar, making them visible to the system classloader.

3. Use Weka's Overloaded Utils.forName() Method (If Applicable)

If you're directly calling Utils.forName() in your own code, Weka offers an overload that lets you specify a custom classloader. Replace the default call with:

// Instead of Utils.forName("weka.clusterers.Canopy")
Class<?> canopyClass = Utils.forName(
    "weka.clusterers.Canopy", 
    getClass().getClassLoader(), 
    null
);

This bypasses the default classloader lookup and uses your application's classloader directly. Note: This only works if you're invoking Utils.forName() yourself—if the call is buried inside Weka's own code (like AddCluster.setOptions()), stick to solutions 1 or 2.

Which Solution to Choose?

  • Start with Solution 1 for minimal code changes.
  • Use Solution 2 if you prefer a configuration-only fix (it will make your uber-jar slightly larger, but no code tweaks needed).
  • Go with Solution 3 only if you're directly calling Utils.forName() in your codebase.

内容的提问来源于stack exchange,提问作者Vadim Yarovoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:41:31