-
Notifications
You must be signed in to change notification settings - Fork 418
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
Add module picocli-jpms (was: Include module-info.class for full JPMS modularization and jlink support) #495
Comments
It turns out that an application does not need to be a full-fledged JPMS module with a Example application: package hello;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "hello", description = "picocli demo", version = "3.6.1", mixinStandardHelpOptions = true)
public class HelloWorld implements Runnable{
@Option(names = {"-u", "--user"}, description = "Specify a user. Default is ${DEFAULT-VALUE}.")
String user = "unknown";
@Override
public void run() {
System.out.printf("Hello, %s", user);
}
public static void main(String[] args) {
CommandLine.run(new HelloWorld(), args);
}
} Example
Build the application:
If you try to run it now as an executable jar it complains because it is still missing picocli on the classpath:
Copy the picocli jar into
Now you can run the jar:
Get the list of dependencies from
Our
You now have a
And we're done! You can copy the contents of the
|
I'm having this issue too, but I'm using maven... |
All that’s really needed is a jar with the HelloWorld class where the manifest has HelloWorld as the main class so that the application can be run with It would be great if you could provide a minimal maven Pom that accomplishments that, so I can include it in the documentation. |
It's just that I can't run jLink while my module-info.java depends on picocli? Oh wait, you mean that for now:
|
I think can work with that, when I get to it, but I'm definitely looking forward to the "picocli-jpms" module. I had a go at modularising it, but was having issues with groovy being found (I think it's because I'm using JDK 11). So I'm guessing it will not be an easy task to convert. |
I got my inspiration from Simon Ritter: https://medium.com/azulsystems/using-jlink-to-build-java-runtimes-for-non-modular-applications-9568c5e70ef4 I'm considering separating the groovy stuff into a separate module (#479) but that will likely be a picocli 4.0 thing. There are other things I want to work on first. Especially since there is a workaround as described in the above comment and Simon't article. |
Thank you. i look forward to it. For now I am happy with the workaround. |
Besides it's better to use Picocli than not :P haha |
For now, I've added a new module to my project called picocli with ComandLine.java & AutoComplete.java (plus module-info.java) and named the version 3.7.0-JPMS. This is letting my compile and create my JRE! The downside is, of course, that I have to manually download changes to your source code. |
Did following the steps in the comment (or Simon’s article) not work? You shouldn’t need a module-info.class... |
My application is a JPMS app, so it does not work for me. My solution means that I have Linux & windows zips being created by just running mvn package. I have made use of service loader (I don't know if this is only java 9+?) to essentially enable installing sub commands prior to run-time... I have a folder called "jobs", in there maven puts my default jobs (sub commands for picocli) - which are excluded from jlink as they aren't depended upon at any point. I also have a second git repo that proves to me that building the jar and dropping it into the jobs folder immediately enables the sub-command in picocli and lets me run that jar's code. |
In picocli 4.0 I’m planning to do the following:
|
Sounds great. |
Is this still planned for 4.0? |
Hi, yes, this is part of the plan for 4.0. I haven’t really given much thought on how to implement this. It’ll probably require some Gradle magic. Will you be able to help out with this one? |
I would be more than willing to but I struggled the last time I tried. I have absolutely zero experience with gradle (I use maven) and was struggling to make it work. Do you have any pointers. Are you planning on 4.0 being a breaking change (i.e. no longer supporting Java 5?) |
I did have a quick go, but struggled to modify. I'll have a proper sit down soon to work out exactly how it currently works, because only then can I make adequate decisions. It has reaffirmed my personal preference of maven haha. Each to their own eh? |
Hi guys, Warkdev |
@Warkdev that would be great! Any help would be appreciated. |
@Warkdev if you have experience with Gradle, then I would suggest you take a look at it as i have not had a proper look in earnest yet, so don't worry about taking over if that's what you want. I have absolutely no experience with Gradle, so am not the best person tackle this (unless @remkop wants to switch to Maven haha) |
@jwheeler91 I think we've the same level of knowledge with Gradle. I just recently adapted a Gradle-projet to JPMS recently. I do have a preference for Maven projects :) @remkop Will have a look, hopefully I won't make any mistake. |
Having worked with both Maven and Gradle I much prefer Gradle. As with any technology, there is some learning involved, but that is an opportunity, right? ;-) Don't worry about making mistakes, we'll just fix them. :-) One idea is to introduce a new Gradle subproject in the project, module info.picocli {
exports picocli;
} In that subproject we need to use Java 9 to compile this source file. We can let this subproject depend on the main project, so that the main parent project's jar is created before the subproject's jar. (See The next step would be a bit unconventional. Usually a subproject's build.gradle only works with resources in its own subproject, but in this case we may want to take the root project's jar file, and work with that. Concretely, we want to unjar it in a temp folder, remove the Groovy classes, add our TBD:
|
Great, so did I start the right way. However, I've a first remark. To manage JPMS, I need to use gradle plug-in which is compiled with Java 11, I hope this is not an issue. Currently, I'm also fighting with junit and gradle because I do need a second module info for the test module (why do I need to make it a module too? Or there's something really wrong with the way my IDE and gradle handles it). Still early stages.. I've forked it to my repo and make some changes but no commit yet. |
I think it will be wiser if we want to have this being released :) Maybe, with this start, someone else will jump on it and bring all his gradle knowledge ! |
No problem, let’s do it that way. |
Can you submit a PR for the module bits? |
Done boss! |
PR merged. Thanks for the hard work! Note to self: keeping this ticket open: still need to remove the automatic module name from the manifest of the |
…dule-Name from main picocli artifact manifest)
Following up on the conversation on PR #662: If anyone wants to help out further, one thing I can think of is that it would be nice to have a README.md for this module. Also, creating automated tests turned out to be quite challenging, but it would be good to confirm manually that the artifact produced by the build for this subproject can in fact be used in a modular java application (that is, just using jars on the By the way, I am still undecided, but considering to rename this module to |
Credit where credit is due: https://twitter.com/picocli/status/1116722078516826112?s=21 |
Ni need for credit but thanks. You made this awesome lib'! |
Note to self: it turns out that the (nice and short) DSL syntax for configuring the plugin has some issue in some environments where I am testing. The legacy plugin application syntax is more verbose but does not have this issue:
|
Note to self: So it may be safer to put it in the root of the jar after all. Since we publish two artifacts, old tools that cannot handle Java 9 bytecodes can always use the non-modular I will take a look at this later, before 4.0-GA. |
I created #674 to follow up. |
Currently the picocli jar is an automatic module (manifest has
Automatic-Module-Name: info.picocli
).Update: this is a common misunderstanding. See the comment below for a tutorial for creating a JLink binary image with an automatic module.
module-info.class trade-offs
It is possible to compile only the module-info.java file with Java 9 and include it in the picocli jar where all other classes are compiled with Java 5.
However, there are quite a few tools that scan all classes in a Jar and that would choke on the module-info.class (whether it is in the root of the jar or in
META-INF/versions/9/
). For example: jandex, and Apache Commons BCEL.Consider producing a
picocli-jpms-3.x.x.jar
that has the same contents aspicocli-3.x.x.jar
but in addition amodule-info.class
. Users looking to create a JLink custom runtime image can use the picocli-jpms jar.Solution
The comment below is a brief tutorial for creating a JLink binary image with an automatic module. No
module-info.class
required in picocli or in the application.Todo: do a more formal write-up and add it to the picocli documentation.
The text was updated successfully, but these errors were encountered: