javacpp-presets icon indicating copy to clipboard operation
javacpp-presets copied to clipboard

JAR entry org/bytedeco/cpython/linux-x86_64/lib/pkgconfig/libssl.pc not found

Open CristianPi opened this issue 2 years ago • 6 comments

Spring boot 3.0.2 app. build with spring-boot-maven-plugin.

stack

app_1         | java.io.FileNotFoundException: JAR entry org/bytedeco/cpython/linux-x86_64/lib/pkgconfig/libssl.pc not found in /opt/target/dist.jar
app_1         |         at org.springframework.boot.loader.jar.JarURLConnection.throwFileNotFound(JarURLConnection.java:175)
app_1         |         at org.springframework.boot.loader.jar.JarURLConnection.connect(JarURLConnection.java:98)
app_1         |         at org.springframework.boot.loader.jar.JarURLConnection.getJarFile(JarURLConnection.java:106)
app_1         |         at org.bytedeco.javacpp.Loader.extractResource(Loader.java:777)
app_1         |         at org.bytedeco.javacpp.Loader.extractResource(Loader.java:756)
app_1         |         at org.bytedeco.javacpp.Loader.extractResource(Loader.java:803)
app_1         |         at org.bytedeco.javacpp.Loader.cacheResource(Loader.java:684)
app_1         |         at org.bytedeco.javacpp.Loader.cacheResource(Loader.java:477)
app_1         |         at org.bytedeco.javacpp.Loader.cacheResource(Loader.java:444)
app_1         |         at org.bytedeco.javacpp.Loader.cacheResource(Loader.java:432)
app_1         |         at org.bytedeco.cpython.presets.python.cachePackage(python.java:222)
app_1         |         at org.bytedeco.cpython.presets.python.cachePackages(python.java:264)
app_1         |         at com.moveo.analysis.utils.Python.configpkg(Python.java:90)
app_1         |         at com.moveo.analysis.utils.Python.<clinit>(Python.java:25)

I imagine this is a config problem, as it works locally without building the jar.

Any direction?

CristianPi avatar Jan 31 '23 20:01 CristianPi

Sounds like it's just not getting bundled in dist.jar for some reason? Someone's going to need to figure out why Spring Boot doesn't want to bundle that file...

saudet avatar Jan 31 '23 23:01 saudet

@saudet it's strange, because that file exists.. the jar is like 1.5GB /BOOT-INF/lib/

image

So it must be a spring problem?

Maybe related to this spring issue

CristianPi avatar Feb 01 '23 18:02 CristianPi

Sprint Boot does override the default JAR handler as you saw per https://github.com/spring-projects/spring-boot/issues/14011. So I guess this means we can't call JarURLConnection.getJarFile() on nested jar files. Hum, how should we be getting the name of the JAR file? @wilkinsona

saudet avatar Feb 01 '23 23:02 saudet

Actually, we should be able to get the name from JarURLConnection.getJarFileURL(), but then JavaCPP also needs to list the entries in the file. I don't see an equivalent to JarFile.entries() that doesn't require JarFile... I'm starting to think that this is the same kind of issue as with jlink, GraalVM Native Image, and OSGi that offer no standard way to list resources, see https://github.com/bytedeco/javacpp/issues/506#issuecomment-883796393. If Spring Boot offers some way to list resources though, we can integrate that into JavaCPP. Contributions are welcome!

saudet avatar Feb 01 '23 23:02 saudet

I'm not sure that I fully understand what the Loader code intends to do. Hopefully the following will show how to find a particular "directory" on the classpath (from within a jar or nested jar) and then list all of its entries:

package com.example.demo;

import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarContentsApplication {

	public static void main(String[] args) throws IOException {
		String location = "org/bytedeco/cpython/linux-x86_64/";
		URL classResource = JarContentsApplication.class.getClassLoader().getResource(location);
		URLConnection connection = classResource.openConnection();
		JarFile jarFile = ((JarURLConnection)connection).getJarFile();
		String name = jarFile.getName().substring(jarFile.getName().lastIndexOf("/") + 1);
		System.out.println(name);
		Enumeration<JarEntry> entries = jarFile.entries();
		while (entries.hasMoreElements()) {
			JarEntry entry = entries.nextElement();
			if (entry.getName().startsWith(location)) {
				System.out.println("  " + entry.getName());
			}
		}
	}

}

Here's a zip of a complete application containing the above code. ./gradlew bootRun will run the application with cpython-3.10.8-1.5.8-linux-x86_64.jar directly on the classpath as a file on the filesystem. ./gradlew bootJar will produce an executable jar file with cpython-3.10.8-1.5.8-linux-x86_64.jar nested within. You can run the application using java -jar build/libs/jar-contents-0.0.1-SNAPSHOT.jar. You should see the same output for each run, i.e. the code works irrespective of the structure of the classpath.

wilkinsona avatar Feb 02 '23 10:02 wilkinsona

This should be fixed with pull https://github.com/bytedeco/javacpp/pull/685.

@CristianPi Please give it a try with the snapshots: http://bytedeco.org/builds/

Thanks @huazai023!!

saudet avatar May 30 '23 10:05 saudet