spring-boot: Can not load class in classpath when package a executable jar

Hi, I use Guava ClassPath class to scan and load some class in my project. It works fine when I run application in my IDE, but when I package it in a executable jar, it cannot load class. Spring boot package use a separate catelog ‘lib’ to setup dependency jars, is it not in classpath? How can I load these classes?

my code below:

   private static final ImmutableSet<Class<?>> REQUEST_CLASSES;

static {
    try {
        REQUEST_CLASSES = from(
                from(currentThread().getContextClassLoader()).getTopLevelClassesRecursive(
                        OSS_REQUEST_PACKAGE)).transform(
                new Function<ClassPath.ClassInfo, Class<?>>() {
                    @Override
                    public Class<?> apply(ClassPath.ClassInfo input) {
                        return input.load();
                    }
                }).toSet();
    }
    catch (IOException e) {
        LOGGER.error("Load OSS request classes exception", e);
        throw new RuntimeException(e);
    }

}

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 22 (7 by maintainers)

Most upvoted comments

Hi @GrapeBaBa

I have had this same problem as you described, to solve it I had to package the executable JAR as ZIP type.

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Cheers,

Take a look at SpringPackageScanClassResolver for an example. This was how we got Liquibase to play nicely with fat jars.

Specifically:

private Resource[] scan(ClassLoader loader, String packageName) throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
                loader);
        String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                + ClassUtils.convertClassNameToResourcePath(packageName) + "/**/*.class";
        Resource[] resources = resolver.getResources(pattern);
        return resources;
    }

Which finds all classes in a given package.

Is your project a web module? If yes, you may need to change the code to load resources using Classpath.getResourceAsStream().

Just to tell you on IDE I have got many successful cases, but when I move to create executable jars I am suffering about many issues like yours. It seems the class loader from jar is working different.