-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The generated runnable jar is not a fat jar (dependencies not included) #204
Comments
Hi @salmonb! JavaPackager doesn't generate FAT JARs ... only a runnable JAR with your code. You can set Here you can find an example. I hope it helps! |
Hi @fvarrui Thanks for your quick reply. I'm happy with a thin jar and copied dependencies, but it doesn't work in my case.
If I generate a fat jar myself and give it to javapackager through the I finally made a reproducer here: https://github.com/salmonb/javapackager-issue Thanks |
I forgot to tell (and I realise now that it's probably the cause of the problem) that my application is a Java >= 9 app, so it uses the Java module system. It looks like the runnable Jar generated by javapackager is not compatible with the module system. A quick search and I found that the MANIFEST file should have a section like this for Java 9 apps:
So the solution is probably to add this section when javapackager is called in a module where there is a module-info.class. |
JavaPackager runs apps in legacy mode (non modular way) ... this should not be a problem, as if you run a Java app using "classpath" instead of "modulepath", all ASAP, I'll have a look into your project (https://github.com/salmonb/javapackager-issue) ... but I haven't seen where you specify the main class ???
Sorry, I didn't understand this point. |
I was referring to https://stackoverflow.com/questions/43606502/can-i-require-java-9-module-via-manifest-mf (my quick search) but maybe that's not the point... My main class is actually defined in the parent pom (which is on a Maven repository and not directly in the repository). When I call your plugin in the xxx-openjfx module, it takes the default configuration which is defined in that parent pom. When I try to run the generated runnableJar beside the libs folder, it should work, isn't it? But I'm still getting the |
Ok, this is the
And this is the content of this JAR: Main class |
What if you add a require statement for the module // File managed by WebFX (DO NOT EDIT MANUALLY)
module webfx.example.application.openjfx {
// Direct dependencies modules
requires webfx.example.application;
requires webfx.kit.openjfx;
requires webfx.platform.java.boot.impl;
requires webfx.platform.java.scheduler.impl;
requires webfx.platform.java.shutdown.impl;
requires webfx.platform.shared.log.impl.simple;
requires webfx.platform.shared.boot; // <----------------------------
} then create the class package org.example.webfxexample.openjfk;
import dev.webfx.platform.shared.services.boot.ApplicationBooter;
public class Main {
public static void main(String[] args) {
ApplicationBooter.main(args);
}
} and finally set this new class as |
I know it's a bit unusual to not have the main class in the jar, but this is because I'm using a little framework (I'm actually the author of it) with a plugin architecture (my app is started through a Java Service). So the entry point is not directly my app, but that framework, which is located in the dependencies. It's still a quite standard Java application IMO. Your suggestion would probably work, but many files are automatically generated as you probably noticed with the DO NOT EDIT MANUALLY comments, and the framework is maintaining these files. If there is no other solution, I would prefer in the end to generate the fat jar of my app and pass it to JavaPackager rather than modifying the sources. Do you know if that limitation (not being able to run a thin jar if the main class is not inside) is coming from Java or JavaPackager? |
I made some further investigation and it appears that it is possible to make a thin jar with a main class outside of it (but in the dependencies), so this is not a limitation coming from Java. I have maybe another explanation of what goes wrong: the list of jars listed in Could you please have a look at this? |
According to https://stackoverflow.com/questions/41982167/maven-jar-plugin-wrong-class-path-entry-for-snapshot-dependency, the problem is coming from the Maven Jar plugin (which generates the MANIFEST file), and can be resolved by setting the configuration parameter Could you please test if setting useUniqueVersions to false within your plugin when calling the Jar plugin solves that Class-Path problem in the MANIFEST file, and make my app running? |
Its seems that your suggestion fixed the problem!! 👏 👏 I'm not releasing SNAPSHOT versions to Maven Central, so you have to package and install manually the plugin in your local Maven repo (JavaPackager version in branch issue-204: There's a problem analyzing dependencies with |
Hi @fvarrui That's great news, thank you! I will use your SNAPSHOT version for the time being. As you noticed, there is a warning message from JavaFX because the application is not launched with the Java Platform Module System. I managed to start it with the thin jar and dependencies in the JPMS way like this (and the warning was removed):
Do you think you can provide an option in your plugin to start modularised application in this way? |
Yes, I plan to add JPMS support in JavaPackager, but I've kept the legacy mode ( |
Great that you plan the JPMS support, and I think you can achieve this without making any change on the generated jars, so they work both in legacy mode or JPMS mode. It will just be the command line to start the application that will differ between the 2 modes. Starting the application in legacy mode is done wiith
and in JPMS mode with
So for people wanting the final executable to start in JPMS mode, you would need to offer an additional parameter in your plugin to pass the starting module and main class ( |
Hi @salmonb, It's a bit more complicated, since I have to adapt the generation of the different native executables, those of each platform, as they are the ones that actually execute the JVM. e.g.: launch4j for Windows or universalJavaApplicagtionStub for MacOS only accept the "--class-path" (-cp) argument, not supporting "--module-path" nor "--module" arguments. Any help would be appreciated! 😃 |
I see, and so you don't have a direct control on how the application is started... Maybe while these third-party tools are not yet ready for JPMS, you can do like this project does: https://xy2401.com/local-docs/java/jetty.9.4.24.v20191120/startup-jpms.html Could that work if your plugin generates such an intermediate application starter that finally starts the final application in JPMS mode with the parameter we would pass to your plugin? |
Yes!! That's the problem
Yes, in fact, I think it's possible. Maybe this way all native launchers could always call the same startup JAR, which will launch a new JVM instance like you said. But I'm not sure how this will affect the way the system shows the started process (e.g. in Task Manager). This was one of the reasons why you have several launchers for Windows: launch4j, winrun4j, why (new one in 1.6.7), ... if we do so, with an intermmediate launcher, "java" process will be shown in the Task Manager, not the EXE. I have to think a bit more about this, but thanks so much for your proposal! |
Hi @salmonb! I think I have good news... I've been trying to run a modular Java application in different ways and finally realized that maybe we can pass In theory it should work since Launch4j should be nothing more than a wrapper for Java. I mean, my understanding is that all it does is invoke I'll tell you something when I come to some empirical conclusion 😃 |
Hi @salmonb! <winConfig>
<wrapJar>false</wrapJar>
</winConfig>
<vmArgs>
<vmArg>--module-path ${project.name}-${project.version}-runnable.jar;libs/commons-io-2.7.jar</vmArg>
</vmArgs>
<mainClass>--module=hello.world.maven/io.github.fvarrui.helloworld.Main</mainClass> It's working fine, but JAR cannot be wrapped into the EXE ... of course, since this is possible, it can be automated internally in JavaPackager, so I'm thinking that also it's possible to automatically detect if the runnable JAR is modular or not, and if so then apply last changes internally to properties. Even it's possible to automatically modularise all non-modular dependencies, transforming them into explicit modules (including |
hi @fvarrui, I was on holidays... Thank you so much for all the progress you made in the meantime, very much appreciated 😃 Great idea to automate the process and make it transparent to the user. |
Hi @salmonb! |
I'm also going to open a new issue requesting to add JPMS support to myself 😄 ... so, you can follow the progress. I think we can close this issue. |
Branch issue-204 merged into devel. |
hi @fvarrui, Yes sure you can close this issue now. Let me know when you have created the new issue for the JPMS support. And no problem to wait version 1.7.0 to have it. Thanks for all your work on this project 👍 |
JavaPackager v1.6.7 released to Maven Central. See changes here. |
Thanks for making this plugin.
I'm submitting a…
Short description of the issue/suggestion:
The generated application crashes. After investigation, it's because the runnable start generated by the plugin is not a fat jar (standalone application), it doesn't include the dependencies required by the application.
Steps to reproduce the issue/enhancement:
What is the expected behavior?
The generated runnable jar should run as a standalone application.
It should be a fat jar with all dependencies required by the application included.
What is the current behavior?
The runnable jar crashes with a java.lang.ClassNotFoundException because it doesn't find the class required in the dependency.
Do you have outputs, screenshots, demos or samples which demonstrate the problem or enhancement?
It's a private project... If my description is not good enough, please let me know and I will try to create a simple reproducer.
What is the motivation / use case for changing the behavior?
Just make it work :)
Please tell us about your environment:
Other information (e.g. related issues, suggestions how to fix, links for us to have context)
Thank you!
The text was updated successfully, but these errors were encountered: