(I guess this is less a question than a report/personal experience looking for critique or whatever. The project described contains an external library.)
Many users need more than all the help they can get in trying to execute a Java project. I'm describing ways that come to mind for getting a project to a user--none particularly foolproof--and wonder if I'm missing some much-easier method.
One way: Do what the dist folder README says: "To distribute this project, right click to zip up the dist folder (including the lib folder) and distribute the ZIP file" and, I'll add, hope the user has the skill to extract and then find the executable jar. And to go get a JRE if need be.
A seamless way: use Netbeans 7.4 Native Java Packaging, which produces a self-extracting executable (an "EXE installer"; an .EXE file) and runs whether or not user has JRE installed. It can be executed from Windows Search box (and can be uninstalled via Control Panel). Method assumes NO JRE available; humongous (30MB) .EXE was produced. [See ((this link))
Unhappy medium: forget the admirable use of an external library; just add the package containing the library's source code. This produces a .jar that runs if JRE is present; otherwise user still has to get involved.
None of the above are exactly ideal ways of providing an app for a tech-challenged user.
I was going to include Webstart as a fourth and what I hoped best alternative, but for no apparent reason, I can't get a compilation that works inside my own Netbeans IDE. Calls to the utility modules--now included in the GUI part of the project; external in NO WAY--never pop up the dialogs they should.
Related
I'm re-using a standalone Swing-based Java class which backs up and restores mysql databases.
I've tested running it from a Windows batch file (.bat) on my dev system, and it works there.
But, if I run the batch file on a different Windows , I get a "main class not found" exception.
However, when I run the command directly on the command line, it works.
The command in the batch file to run it is:
java -cp lda-services.jar;bip-services-1.6.0.0-SNAPSHOT.jar;decryptor-1.6.0.0-SNAPSHOT.jar;slf4j-api-1.7.31.jar;commons-io-2.6.jar com.ilcore.util.SosaMaintenanceJFrame
The SosaMaintenanceJFrame class is contained in the lda-services jar.
Here's the error message:
Error: Could not find or load main class com.ilcore.util.SosaMaintenanceJFrame
Caused by: java.lang.ClassNotFoundException: com.ilcore.util.SosaMaintenanceJFrame
The class is definitely in the jar file, as I've extracted it the file and seen it.
Any thoughts on why this would be happening? I need to run inside a batch file so the user can just click on it to run it.
Most likely explanation
Your paths are relative, which means that the batch file isn't going to work unless you run it from the right place. In general, having a batch file that has an invisible rider stapled to it with: "I break in mysterious ways if not run from the appropriate dir" is a crappy batch file - make it better.
Better solution
Or, even better, get rid of it. You don't need batch files to distribute java programs.
Proper ways to distribute java programs:
The modern take is very very different from what you have here: JREs are dead, you must ship an installer that does the whole thing, notably including a java runtime (no longer called a JRE, and one you ship and keep up to date if relevant). That's perhaps a bridge too far for what you're doing here. Relevant tools include jlink.
A slightly less modern take involves jars with manifests:
Your jar file should contain a manifest. This manifest must contain 2 relevant entries:
Class-Path: lda-services.jar bip-services-1.6.0.0-SNAPSHOT.jar decryptor-1.6.0.0-SNAPSHOT.jar slf4j-api-1.7.31.jar commons-io-2.6.jar
and
Main-Class: com.ilcore.util.SosaMaintenanceJFrame
You can use jar's -m switch, or just include the manifest (it's just a file in the jar): it's at META_INF/MANIFEST.MF and it's a text file, each line is an entry, and an entry consists of a key: value pair.
When a jar contains this, just double clicking the jar and running java -jar thejar.jar will then take care of it all: Java will load the stated jars as part of the classpath, and these, crucially, are resolved as paths relative to the directory the jar is in, so it DOES work when you try to launch them from elsewhere, i.e. if you do:
C:
CD \
java -jar "c:\Program Files\MyApp\myapp.jar"
it works fine, whereas that batch script would fail due to being in the wrong place.
Build systems let you define the manifest too, check your build systems docs for how to do this, it'll be easy, and there are tons of tutorials if you search the web for e.g. 'manifest executable jar maven' or whatnot.
You can consider making a shaded jar. But I wouldn't.
A shaded jar takes all your dependencies and packs them into your main jar, so that there is only one jar. There is now no need for a Class-Path entry (the jar you run is obviously already on the classpath and there's nothing else to include) and your app is shipped as 'just' a single jar file.
But this is mostly a red herring: There are no consumer JREs anymore so you've made the user experience from a D- to a D. If you actually care about giving your users a nice experience, there's no getting around an installation process of some sort and once you have that, having the separate jars is no longer a problem. Separate jars are less hairy when signed jars are involved, are much easier to keep up to date, and have a significantly faster turnaround (when you build your stuff and want to ship what you built, shading takes ages, so it's nice to cut that step out). The faster your CI system tells you about failing tests, the better.
Meet in the middle
You don't have to upgrade to modules and the like. What you can do instead is use something like launch4j. The aim is to end up with a zip file along with the installation instructions: Make a dir somewhere. unzip this zip in it. Doubleclick 'myapp.exe'. Done.
The zip would contain an entire JRE, all your jar file deps, and your main app, and an exe file which launch4j made for you, that launches your app using the JRE packed into the jar. This means you know exactly which JRE is being used, and it'll work even on systems that didn't have one installed yet (which, these days, should be all of them - the notion of 'end user downloads a JRE from oracle and the user + oracle work together to keep that thing up to date and security-issue-free', is dead).
The fact that it's an EXE is nice: Now if the user e.g. alt+tabs through their apps, they get your app, with your name, and your icon, instead of 'javaw.exe' with an ugly coffee mug logo.
But when I try running it from the jar file generated by Maven, however, I get a "class not found" exception.
Even if you didn't get that error, you'd get another one unless you'd used Maven Shade, as that's the only way you're going to run that with a single jar. My guess as to why that particular error occurs is that the app class you're attempting to run is in fact in one of the *SNAPSHOT* jars
I am currently working on a jar file and I am going to distribute it soon. I was looking forward to distributing it for user without him needing installing JRE to run my app. I am well aware of tools like Jar2Exe but those tools inject some additional content to the executable and I am not going to buy license for that! So I am working on a solution. And I have the idea, So I will create a C file with this content ( I am using C Language power in nativity! ) :
#include <stdlib.h>
int main() {
system("java -jar test.jar");
return 0;
}
And I will put the jar file and the compiled file of the C file above and java.exe located in my JRE installation dir in a same directory and this should work but surely there are a bunch of dlls that java.exe depends on them! A list of those dependencies to put them all in a directory and make the idea work will be very helpful:)
Please Note : I don't want to create an executable from the JAR file, I only want the user need not INSTALL JRE.
EDIT
I realized the above approach isn't practical, so I am going to install JRE behind the scenes ( my only goal is that the user doesn't find out whats going on in the installation process ) I am going to copy required files to ProgramFiles/jre_version but what in addition should I do? In the other words what does the JRE installer do under the hood?
Why do you think those other companies want you to pay money for their product?
Hint: because it ain't that easy.
The point is that not only need your JAR file. You need to make each and any class that your code will be using available to the JVM you are starting up.
You know, exactly that other stuff that those commercial tools are backing into their EXE files; the stuff that you think makes their EXE files so big and slow. That is the stuff that you need to run your java classes ...
The JRE alone comes with megabytes and megabytes of java classes, packaged up in various JARs. And any 3rd party library that you are using will be required too.
So, of course, when you are able to find all classes that will be loaded when your code is executed, then you could manually package that into a single JAR. But as said: if that would be an easy undertaking, those other people wouldn't have much of a business case. And of course: as soon as reflection and Class.forName() kicks in, you are completely broken. Because you can't predict at all, which classes will be used at runtime then.
I want to create a runnable JAR that include referenced libraries, namely jackson, in eclipse via the export. There used to be fat jar that seemed to be the goto solution before Eclipse offered to export to runnable JAR.
From this question, the first option would be what I'm looking for. Since it is for the moment a small project, it wouldn't be a problem to always have everything together (plus it's easier for me since I'm just starting with JARs, runnables and jnlp)
When I try to launch it, there's an alert window saying there was a problem and to try to find it in the console (which I can't get to open).
If I remove any use of this referenced library everything runs perfectly (except the part that it's not doing what I want at all). The window looks the way I designed it, but no functionality without the library.
I don't even have a stack trace to help with the problem. I've created other projects without any referenced libraries and everything is fine. So I've pretty much narrowed it down.
Since I let Eclipse handle the exporting and everything, I don't suppose you need the manifest to see if it is alright. Any questions you might have, I'll provide the informations you need. It goes without saying that the project runs directly from Eclipse.
Eclipse
Version: Indigo Service Release 2
Build id: 20120216-1857
Edit following Baqueta's answer
What happens when I do that is that I get a custom RuntimeException. I'm a bit baffled here. Here's a simple explanation of my code.
I have a utility class (UtilityJSON) that uses the referenced library (jackson). The constructor of that utility class instantiate an object defined in the referenced library, let's call it mapper.
A method of UtilityJSON uses a method of 'mapper'. At this point the exception is raised. Why I'm baffled is that 'mapper' is succesfully instantiated but using its method raises an exception. If the jar couldn't find the referenced library, it probably couldn't create the object 'mapper'. But running the project from Eclipse is all fine.
Is there any way to debug when running an executable jar? Maybe echo something in the console.
Edit 2
I may have found the error. My program reads a *.txt file in a folder inside the project. When exploring the content of the jar I see that this folder was not included, thus the exception. So the question now becomes: how do I include this folder? It's in the root folder of the project.
You could try the following:
In Eclipse, go to Project->Properties.
Select 'Java Build Path' from the column on the left.
Select the 'Order and Export' tab.
Find 'jackson' in the list and make sure it's checked.
EDIT
To answer your updated question:
In Eclipse, find the *.txt file in the Package Explorer. Right-click it and select Build Path->Add to Build Path. Then follow the instructions above to make sure the file gets included in the Jar. Finally, do a clean and rebuild.
If you're ever going to add more resources, it is common practice (and makes sense!) to have a resources folder (often called 'res'). You can then add the entire folder to the build path, so that all the resources in there get included in the Jar.
Enable the java console by writing
javaws -viewer
in a terminal. Close the Cache Viewer and click the advanced tab. There open Java-Console and click "enable console".
I have a Java application installed. The jar is bundled into an .exe file using Launch4J. Now I want to create a patch for this application.
If I create another jar containing only updated files, how can I refer it in the original code?
I have java application installed. ..Now I want to create a patch for this application.
This is one of the strengths of the Java Web Start launch technology that comes with the J2SE. Simply update the Jar on the server, and the next time the app. launches, it will be updated.
The update can be honed for your use-case, configured to be done lazily or eagerly, before or after launch, or even programatically controlled using the JNLP API's DownloadService.
..And the jar is bundlled into an .exe file ..
'Unfortunately', JWS works on Windows, ..and Mac., and *nix - so you may have to expand your horizons.
BTW - I have no idea how to do the same with Launch4J, but then, that is really the wrong question. I aim to provide an answer to the right question, which is "How do I deploy & update a Java rich client?". ;)
I've never worked with Launch4J, however I think you should try to affect the classpath. JRE always loads the classes from the classpath. From this point of view, jars have no added value and just serve as a containers for your *.class files and resources.
Now, if you succeed to configure your tool to do something like:
classpath = C:\Temp\my_patch_path;$your_current_classpath
then its enough to put your changed files into C:\Temp\my_patch_path (of course preserving the package structure). JRE will load your classes first in this case.
Hope, this helps
Mark
It is might not be possible to do this without changing the contents of the exe.
we have downloaded jar files for lambdaj and its dependencies which are again jar files.
we do not know how to go about it. we have copied these files in the
C:\Program Files\Java\jre6\lib\ext
have set the class path in environment variales as:
variable: classpath
path: C:\Program Files\Java\jre6\lib\ext
but we do not know how to go further. we want to run some lambdaj programs.
can anyone suggest how to run lambdaj programs?
You would run a Java program that requires lambdaj in exactly the same way you'd run any other java program with an external dependency, i.e. by invoking the java executable passing in the fully-qualified name of the Main class, or the JAR with an appropriate manifest, or by deploying it in a servlet container, etc. Additionally you should be putting the LambdaJ JAR on the classpath for this invocation, not in the lib folder for your entire JVM.
What have you tried so far and why/how is it not working? Your question at the moment is a bit analogous to "I want to use Microsoft Word to view some Word documents, how do I do this?".
Update for comment 1: You said "it's not working". That doesn't help anyone address your problem as it gives no clue what you expected to happen and what you observed, only that they were different. As for where JAR files can be stored - you can put them in any directory, so long as that directory is on the classpath (or you add it to the classpath) of the Java application that runs. The canonical place to put external dependencies is in a folder called lib below the root of your project, but the important thing is that you choose somewhere consistent and sensible.
It sounds like you don't quite grok Java and classpaths yet. If you have followed some tutorials and are still stuck, ask for help to let you understand. Adding more detail to your question, including the layout of your files, the commands you issued, and the response that came back would be useful too.
If you are using Netbeans create a project and right click on the Libraries folder within the desired project. Click Add JAR/Folder...