Module not found if graalpy is packaged in Spring Boot Jar - spring-boot

I'm building a Spring Boot (3 RC1) application with some Python code (GraalVM 22.3). Running the application in dev mode works. After building Jar with Maven I get an error:
Caused by: org.graalvm.polyglot.PolyglotException: ModuleNotFoundError: No module named 'pystac'
at org.graalvm.sdk/org.graalvm.polyglot.Context.eval(Context.java:399) ~[org.graalvm.sdk:na]
at ch.so.agi.sodata.stac.ConfigService.readXml(ConfigService.java:116) ~[classes!/:0.0.1-SNAPSHOT]
at ch.so.agi.sodata.stac.SodataStacApplication.lambda$init$0(SodataStacApplication.java:60) ~[classes!/:0.0.1-SNAPSHOT]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:767) ~[spring-boot-3.0.0-RC1.jar!/:3.0.0-RC1]
... 13 common frames omitted
The python.Executable shows to the graalpy executable packaged in the Jar: file:/Users/stefan/sources/datenbezug/sodata-stac/target/sodata-stac-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/venv/bin/graalpy
Grepping the Jar shows the pystac module in the Jar file, e.g. BOOT-INF/classes/venv/lib/python3.8/site-packages/pystac/item.py
Creating the context with:
var VENV_EXECUTABLE = ConfigService.class.getClassLoader()
.getResource(Paths.get("venv", "bin", "graalpy").toString())
.getPath();
var context = Context.newBuilder("python")
.allowAllAccess(true)
.option("python.Executable", VENV_EXECUTABLE)
.option("python.ForceImportSite", "true")
.build()
Is it possible to put the whole python stuff including third party libs into the FatJar? Or did I just miss some packaging magic?

The issue is that the default Truffle filesystem, AFAIK, only supports the actual filesystem of your OS, i.e., it does not "see" resources in the jar file. This is why it works in dev mode when the resources are just files on the filesystem.
There are two options how to deal with this:
do not put the venv into resources, but deploy it separately, such that it ends up somewhere on the filesystem
implement custom Truffle filesystem, but I am not aware of anyone who tried this with virtual environments yet, so there may be some rough edges. Most notably GraalVM LLVM Toolchain that is used to build Python native extensions for execution with GraalVM LLVM engine produces system specific binaries, so your jar will not be as portable as one would expect from a jar. If you only use pure Python packages, it may be fine.

Related

Use Groovy app and test code in combination with jlink solution for bundling JavaFX

This follows on from this excellent solution to the question of how to get Gradle to bundle up JavaFX with your distributions.
NB specs: Linux Mint 18.3, Java 11, JavaFX 13.
That stuff, involving jlink and a module-info.java, is beyond my pay grade (although I'm trying to read up on these things).
I want to move to using Groovy in my app and test code (i.e. Spock) rather than Java. The trouble is, the minute I include the "normal" dependency in my build.gradle i.e.
implementation 'org.codehaus.groovy:groovy-all:2.5.9'
and try to build, I get multiple errors:
mike#M17A ~/IdeaProjects/TestProj $ ./gradlew build
> Configure project :
Found module name 'javafx.jlink.example.main'
> Task :compileTestJava FAILED
error: the unnamed module reads package org.codehaus.groovy.tools.shell.util from both org.codehaus.groovy.groovysh and org.codehaus.groovy
[...]
error: the unnamed module reads package groovy.xml from both org.codehaus.groovy and org.codehaus.groovy.xml
[...]
error: module org.codehaus.groovy.ant reads package groovy.lang from both org.codehaus.groovy and org.codehaus.groovy.test
error: module org.codehaus.groovy.ant reads package groovy.util from both org.codehaus.groovy.xml and org.codehaus.groovy.ant
100 errors
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileTestJava'.
Yes, 100 errors... probably more! By commenting out various things I think I've come to the conclusion that some Groovy dependency is being injected by the jlink stuff. Fine, I can live with that (although it'd be nice to know what version of Groovy it is).
The trouble is, even if I omit the Groovy dependency line, the same errors occur when I try to introduce the Spock dependency:
testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5'
Has anyone got any idea what's going on here and what to do about it?
I searched for an answer. I didn't find a good solution.
According to this, it seems that Groovy is currently not really compatible with Java modules. It is due to the fact that some packages are contained by multiple jars of the library (not compatible with modules). You will have to wait for Groovy 4 for a compatible version.
I discovered that the JavaFX plugin use this plugin internally. This plugin seems to consider that all dependencies are modules (it is not the default Gradle behaviour).
To make your application works, it seems that you have to:
force Gradle to put Groovy in the classpath instead of the modulepath (it will not be considerered as a module, but seems impossible if you use the javafx plugin)
use the "patch-module" system: it allows Gradle to make a fusion of the library jars into a single module, to prevent the problem of packages that are in different jars
I searched the Groovy jars with IDEA (Project structure/Libraries), and I tried to use the syntax offered by the plugin to use "patch-module":
patchModules.config = [
"org.codehaus.groovy=groovy-ant-3.0.1.jar",
"org.codehaus.groovy=groovy-cli-picocli-3.0.1.jar",
"org.codehaus.groovy=groovy-console-3.0.1.jar",
"org.codehaus.groovy=groovy-datetime-3.0.1.jar",
"org.codehaus.groovy=groovy-docgenerator-3.0.1.jar",
"org.codehaus.groovy=groovy-groovydoc-3.0.1.jar",
"org.codehaus.groovy=groovy-groovysh-3.0.1.jar",
"org.codehaus.groovy=groovy-jmx-3.0.1.jar",
"org.codehaus.groovy=groovy-json-3.0.1.jar",
"org.codehaus.groovy=groovy-jsr-3.0.1.jar",
"org.codehaus.groovy=groovy-macro-3.0.1.jar",
"org.codehaus.groovy=groovy-nio-3.0.1.jar",
"org.codehaus.groovy=groovy-servlet-3.0.1.jar",
"org.codehaus.groovy=groovy-sql-3.0.1.jar",
"org.codehaus.groovy=groovy-swing-3.0.1.jar",
"org.codehaus.groovy=groovy-templates-3.0.1.jar",
"org.codehaus.groovy=groovy-test-junit-3.0.1.jar",
"org.codehaus.groovy=groovy-test-3.0.1.jar",
"org.codehaus.groovy=groovy-testng-3.0.1.jar",
"org.codehaus.groovy=groovy-xml-3.0.1.jar"
]
It only works with a single line "org.codehaus.groovy=X.jar", but a bug prevents it to work with all of the library jars (Look at this issue on Github).
So you have multiple choices:
Use Java instead of Groovy
Wait for a new Groovy release, or new releases of plugins (modules-plugin, and a version of javafx-plugin that use this one internally)
Use old javafx configuration: dependencies are not module by default, and you have to specify manually in build.gradle that JavaFX dependencies should be considered as a module (check my "obsolete" answer to this question)

Neo4j-Ogm with Spring Boot: Classpath scanning doesn't find DomainEntities when deployed as runnable jar

I am in the process of migrating an existing app from Spring-Data-Neo4j 3.x to 4.1 using neo4j-ogm 2.0.4.
After overcoming some obstacles, it is now running fine when launched directly from IDE.
However it doesn't find any DomainEntities when I run it via a Spring Boot runnable jar:
(ClassPathScanner.java:132) Classpath elements:
(ClassPathScanner.java:134) D:\Programme\Project\myProject.jar
(DomainInfo.java:108) Starting Post-processing phase
(DomainInfo.java:74) Building annotation class map
(DomainInfo.java:87) Building interface class map for 0 classes
(DomainInfo.java:136) Checking for #Transient classes....
(DomainInfo.java:155) Registering converters and deregistering transient fields and methods....
(DomainInfo.java:159) Post-processing complete
(DomainInfo.java:69) 0 classes loaded in 40179 milliseconds
The executable jar is built using the Spring Boot Gradle Plugin which allows to make a jar executable:
springBoot {
executable = true
}
I've attached to the app via remote debugging when the jar starts and found that org.neo4j.ogm.scanner.ClassPathScanner#scan only contains my jar as classPathElement. According to the code, this should now be scanned as a zip/jar file. When classPathElement.isFile() is executed however, this evaluates to false and the jar is skipped.
Why is that the case? Is an executable jar not a file?
What steps can I take to get this running? I could probably use some other deployment mechanism, but I found this fairly simple and well working.
I did some additional investigation and it turned out that this was not related to the runnable jar at all. This was actually caused by having a space in the path to the jar file.
I think that is a perfectly valid case and am not sure why this doesn't work. In my case it was ok though to simply rename the respective folder and remove the space.

How to provide additional class for a package on OSGi system classpath for J2SE 1.8 profile

Inside ee.j2se-1.8 the package org.w3c.dom is included.
org.osgi.framework.system.packages = \
...
org.w3c.dom,\
...
org.osgi.framework.bootdelegation = \
...
org.w3c.*,\
org.xml.*,\
....
The bundle xml-apis_1.4.1.20140905-131237.jar contains the same package org.w3c.dom, but with one important class more ... ElementTraversal.class more.
So here my questions...
How can I provide the missing class inside my Equinox OSGi runtime?
You are suffering from the fact that people do not take packages seriously. We have a similar problem in the jta API. The version delivered by the VM is not identical to the version that is delivered as a special package.
The solution is to include the JAR with the extra packages on the class path where the framework resides. It looks like you're using bnd (good!) so this would look like:
-runpath: xml-apis__xml-apis;version="[1.4.1,2.0.0)"
If this had been a bundle with proper exports then you would have automatically gotten its exports as system packages. Looking at the packages in this bundle it seems all packages are already in the standard exports of the VM. However, if you have packages int his JAR that are not exported by the VM then you can add them as follows:
-runsystempackages: javax.xml.foo

using cxf in osgi: Provider org.apache.cxf.jaxws.spi.ProviderImpl not found

I am trying to publish some web services (using EndpointImpl.publish()) but I am gettings this error:
Provider org.apache.cxf.jaxws.spi.ProviderImpl not found
the cxf-bundle is installed:
[ 79] [Active ] [Created ] [ 50] Apache CXF Bundle Jar (2.4.3.fuse-01-02)
an extract of the osgi:headers shows the imported package
Import-Package =
javax.jws,
javax.persistence;version="[1.1,2)",
javax.servlet;version="[2.5,3)",
javax.xml.bind,
javax.xml.bind.annotation,
javax.xml.bind.annotation.adapters,
javax.xml.datatype,
javax.xml.namespace,
javax.xml.parsers,
javax.xml.transform,
javax.xml.transform.stream,
javax.xml.validation,
javax.xml.ws;version="[2.2,3)",
javax.xml.ws.soap;version="[2.2,3)",
javax.xml.ws.wsaddressing;version="[2.2,3)",
org.apache.commons.lang;version="[2.5,3)",
org.apache.commons.logging;version="[1.1,2)",
org.apache.cxf.jaxws;version="[2.4,3)",
org.apache.cxf.jaxws.spi;version="[2.4,3)", <--- imported
org.apache.cxf.ws.addressing;version="[2.4,3)",
org.apache.felix.gogo.commands;version="[0.10,1)",
org.apache.openjpa.enhance;version="[2.2,3)",
org.apache.openjpa.util;version="[2.2,3)",
org.osgi.framework;version="[1.5,2)",
org.osgi.service.blueprint;version="[1.0.0,2.0.0)",
org.springframework.beans.factory.xml;version="[3.0,4)",
org.springframework.context;version="[3.0,4)",
org.springframework.context.support;version="[3.0,4)",
org.w3c.dom,
org.xml.sax
Require-Bundle =
org.apache.cxf.bundle
I am not sure what else I need to do.
in case it is important. the container is a karaf 2.2.7
to address pooh's answer:
1- cxf-bundle is exporting this package: org.apache.cxf.jaxws.spi;version="2.4.3.fuse-01-02"
2- bundle was started. the error was during runtime.
3- the manifest was created using maven-bundle-plugin which should create the entire list
4- the error happen while creating a webservice endpoint:
TopologyIFPortType impl = new TopologyWS();
String addressTopology = "http://localhost:" + port
+ "/nsp/webservice/topology";
topologyEndpoint = (EndpointImpl) Endpoint.create(impl);
topologyEndpoint.getFeatures().add(new WSAddressingFeature());
topologyEndpoint.publish(addressTopology);
the complete trace:
javax.xml.ws.spi.FactoryFinder$ConfigurationError: Provider org.apache.cxf.jaxws.spi.ProviderImpl not found
at javax.xml.ws.spi.FactoryFinder$2.run(FactoryFinder.java:130)
at javax.xml.ws.spi.FactoryFinder.doPrivileged(FactoryFinder.java:220)
at javax.xml.ws.spi.FactoryFinder.newInstance(FactoryFinder.java:124)
at javax.xml.ws.spi.FactoryFinder.access$200(FactoryFinder.java:44)
at javax.xml.ws.spi.FactoryFinder$3.run(FactoryFinder.java:211)
at javax.xml.ws.spi.FactoryFinder.doPrivileged(FactoryFinder.java:220)
at javax.xml.ws.spi.FactoryFinder.find(FactoryFinder.java:160)
at javax.xml.ws.spi.Provider.provider(Provider.java:43)
at javax.xml.ws.Endpoint.create(Endpoint.java:41)
at javax.xml.ws.Endpoint.create(Endpoint.java:37)
at org.opennaas.extensions.idb.webservice.WebServiceHolder.startTopology(WebserviceControl.java:78)
at org.opennaas.extensions.idb.webservice.WebServiceHolder.start(WebserviceControl.java:60)
at org.opennaas.extensions.idb.webservice.WebserviceControl.startWebservices(WebserviceControl.java:32)
at org.opennaas.extensions.idb.shell.StartWebservices.doExecute(StartWebservices.java:16)
at org.apache.karaf.shell.console.OsgiCommandSupport.execute(OsgiCommandSupport.java:38)
at org.apache.felix.gogo.commands.basic.AbstractCommand.execute(AbstractCommand.java:35)
at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:78)
at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:474)
at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:400)
at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)
at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183)
at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120)
at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89)
at org.apache.karaf.shell.console.jline.Console.run(Console.java:240)
at java.lang.Thread.run(Thread.java:679)
The version of CXF you use seem to be quite old. You should try with the current release 2.6.1. In 2.6 a lot of OSGi improvements were introduced.
You can install it using:
features:chooseurl cxf 2.6.1
features:install cxf
Don't worry, OSGi gives you full access to the information which bundle uses which package etc. You only have to know how to ask the system to give you the info you need for debugging the problem.
Unfortunately I am not familiar with karaf console commands, I am working more with ProSyst's mBeddedServer OSGi framework, but since all this is standard in OSGi, I can tell you what to look for and you can find the needed commands in karaf.
So, check the following:
1. Is Apache cxf bundle successfully installed? Is it in the "active" state?
(from your posting it seems that it is)
What is the version of the org.apache.cxf.jaxws.spi package that it exports?
This is different from the cxf bundle version!!!
In order to see the package version, look inside the manifest of the cxf bundle, and look for the Export-package header.
Is your bundle installed and started successfully? Is it in the active state?
If the error "Provider not found" appears during starting of your bundle, then your dependencies are not matching the provided packages from the cxf bundle, see point 2.
If, however, the error appears during runtime, it could have several causes:
You haven't imported all needed packages in your manifest. Try using analysis tools which can generate the manifest for you based on your source code.
or:
The code which does the publishing is located e.g. on the system classpath and uses the system classloader, which in OSGI due to modularity and security reasons doesn't have access to the bundle classloaders.
Check what is provided by the system classpath instead of as OSGi bundles. Anything there which uses Class.forName or other reflection methods won't work in the modular OSGi framework.
There are also other possibilites, but you'll need to provide more info. Was there an exception stack trace? What classes are involved in this piece of code and where on the classpath are they located? etc.

I've already added tools.jar in classpath, why still java.lang.NoClassDefFoundError: com.sun.jdi.Bootstrap thrown?

I'm using the HotSwap function of javassist, it requires tools.jar in classpath, so I added -cp tools.jar when start my OSGi appliction. But when I new HotSwap() in the code of one of the bundles,
java.lang.NoClassDefFoundError: com.sun.jdi.Bootstrap
was thrown. com.sun.jdi.Bootstrap is in the tools.jar and I've already added it in classpath and also I verified it worked because if not, the following code will not work:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
The Classloader of HotSwapper cannot load classcom.sun.jdi.Bootstrap? Then why it works properly in my Eclipse environment?(I added tools.jar into the libraries of Build path)
On why NoClassDefFoundError, any clue is appreciated.
You have to make sure the system bundle exports this package. For example in Felix the file jre.properties defines what packages are exported by the system bundle. Add the package com.sun.jdi there and it should work.
In eclipse this is done in config.ini. You can use org.osgi.framework.system.packages.extra= to define additional packages to export. I would rather not use boodelegation=* as it might export unwanted packages too. See:
http://www.eclipse.org/forums/index.php/m/734358/
http://wiki.eclipse.org/Equinox_Boot_Delegation
In Equinox, you can set Boot Delegation to * to gain acess to all class in bootclass, see this wiki for details. In 3.2, it was osgi.compatibility.bootdelegation=true in config.ini.

Resources