lundi 28 février 2022

ClassNotFoundException and NoClassDefFoundError trying to inspect Spring Boot jar file with java.lang.reflect

I am trying to build a tool that can inspect a specified Spring Boot application packaged as a jar. I am able to list the contents of the jar, and I am able to load and inspect some classes, but others, most importantly our own classes -- those that make up the actual application code -- I cannot inspect and get a ClassNotFoundException when trying to load them. Many, but not all, of those classes are located in BOOT-INF/classes and I have tried both with and without that path in the URLs provided, and with and without that as part of the class name. I also get many NoClassDefFoundError exceptions. If I expand the jar file, the "missing" classes are located where expected under BOOT-INF/classes/

I am not trying to run the application. That works fine with ./gradlew bootrun and I am not trying to create a custom launcher or anything like that, which is all I'm able to find for sample code. Even the SO suggestions are all related to issues running and deploying Spring Boot applications. I'm sure the causes are similar or related, but I don't know how to bridge the gap.

All I want to do is extract all the parameters that have the @Value annotation and report the values of those annotations, for both our code and any dependencies. Ultimately I want to be able to validate our yaml configurations and report on missing configuration values that are missing from those files.

Manifest (lightly redacted):

Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Start-Class: com.redacted.redacted.redacted.redacted.redactedApp
 lication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.5.8
Specification-Version: 1.0.0
Main-Class: org.springframework.boot.loader.JarLauncher

My class loader is created like this:

final URL url = jarFile.getUrl();
final URLClassLoader urlClassLoader = LaunchedURLClassLoader.newInstance(new URL[] {
    new URL(url.toString() + "BOOT-INF/classes!/"),
    url,
});

I get the class name and try to load (exception handling code not shown):

String name = jarEntry.getName();
int endIndex = name.lastIndexOf(".class");

String className = name.substring(0, endIndex)
        .replace('/', '.').replace("BOOT-INF.classes.", "");

Class<?> loadedClass = urlClassLoader.loadClass(className);

How can I fix the problem loading these classes, or, alternatively, is there another way to extract all parameters with the @Value annotation, for all code and dependencies?





Aucun commentaire:

Enregistrer un commentaire