Jar executable with sqlite driver - java

I made a code that connects to my sqlite driver which is in the CLASSPATH and reads some database file. I want to create an executable which can be used on computers that don't have the sqlite driver.
If I do:
jar cvfe exec.jar main_class
I will get "class not found: org.sqlite.JDBC" when running with
java -jar exec.jar
What should I do to make the executable work?
Edit:
I don't know if it makes any difference, but this is the JDBC driver I use:
https://bitbucket.org/xerial/sqlite-jdbc

You need to include the library inside the JAR. Maybe you don't know this, but JAR files are just ZIP files, so you can change their contents easily. Here are some quick instructions on how to do it. Assuming your JAR file is named exec.jar, and the JAR of the library you want to include (the JAR you downloaded) is driver.jar
Change your file name from exec.jar to exec.zip.
Extract all the contents of exec.zip into folder exec/
Change your library file name from driver.jar to driver.zip
Extract all the contents of driver.zip into folder driver/
Copy the contents of driver/ into exec/, but do not copy the META-INF folder. If a pop-up asks if it's ok to merge the folders, click yes.
Compress all files in exec/ into exec.zip
Rename exec.zip to exec.jar (replace the original).
You can include any java library inside a JAR using this method.

Here is the doc:
C:\Windows\System32>jar /?
Illegal option: /
Usage: jar {ctxui}[vfmn0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
And so I think the command you need is:
jar cvfe exec.jar main_class main_class

Related

How to access outside file from java jar

I have a jar that is reading a file using below code:
Thread.currentThread().getContextClassLoader().getResource(fileName);
I want to run this jar using java -jar .jar command but I want to keep this file outside my jar, so that I can edit the jar file later on without touching the jar. Can anyone help me, how to run this jar so that it will pick up the file from outside.
There are multiple approaches you can do that and it will depend on where would you like to place this external file. For the sake of this answer, I will refer to this file as config file
Not In The Same Directory
The first approach is where you will need to place this file outside the JAR and not necessarily next to the JAR file in the same directory. In that case, you can pass the file location of the config file using either an environment variable (if you are running the JAR in a shell for example) or a Java property.
To use an environment variable, assuming you are using some Linux distro, then you can use the export command to set the value; something like this:
$ export CONFIG_FILE_LOC=/etc/myapp/config.file
You can then read the value in your code using the System class by using the following code:
String fileLocationEnv = System.getenv("CONFIG_FILE_LOC");
Alternatively, you can set this as a property by adding the following segment to your launch command:
$ java -Dconfig.file.location=/etc/myapp/config.file -jar myapp.jar
You can then read the value in your code using the System class for properties using the following code:
String fileLocationProp = System.getProperty("config.file.location");
In The Same Directory
If you need the config file to co-exist in the same directory as your JAR file, then you can use the following code to get the JAR directory and then append the filename to it. Here's the code (assuming a class named MyApp)
try{
new File(MyApp.class.getProtectionDomain().getCodeSource().getLocation().toURI());
} catch(URISyntaxException exception){
System.out.println("Exception");
}
Hope that helps.
To open the file as a resoure, add the folder containing the file(s) you want to use, to your classpath:
java -classpath .;config -jar myjar.jar
This example adds the current directory and the config directory to your classpath.
Multiple folders can be specified by using a separator. On windows use ';' , on unix use ':' .
To open the file as a File, you can just use
new File("configfile")
which will look in the working directory (directory where you launched your java)

Replace a single file from jar file

I need to replace a single class file from a jar file. The jar file is quite big and every time I don't want to extract it and replace manually. I want to automate this procedure. Can someone please help me on this.
When jar file is extracted below folders are created :
render
classes
com
I need to go inside "com/cgp/f1/cmmi/" folder and replace a class file inside it.
Things I tried :
zip file.jar com/cgp/f1/cmmi/services.class Services.class
jar uf file.jar com/cgp/f1/cmmi/ services.class
jar -uf file.jar com\cgp\f1\cmmi\ services.class
jar uf file.jar com/cgp/f1/cmmi/services.class services.class
The error I am getting is :
when using jar command
com\cgp\f1\cmmi\ : no such file or directory
when using zip command :
zip warning: name not matched: com\cgp\f1\cmmi\Services.class
can some one please guide me where I am going wrong.
Maybe the jar -uf found here could help you: How to update one file in a zip archive
If graphical apps are an option, you could use winrar or 7-zip to replace the class. You don't need to extract the jar file to make this work. Just open the jar with one of those apps, go to de directory where is the class file to be replaced, drag-and-drop the new file to replace the old one and save.

Replacing a class file inside a folder in a jar file

I have a jar file in C:\ (xx.jar). I need to replace a class file (path: com\sample\folder\xfile.class) within xx.jar with a class file (yfile.class) that is placed C:\.
Please help me with the command for replacing one class file in the jar with another class file outside the jar. I am struggling in pointing the directory structure.
I tried with,
jar uf C:\xx.jar C:\yfile.class
The above command creates a new folder C:\ within xx.jar and the yfile.class comes inside C:\. But I want the file to be inside the com.sample.folder in the xx.jar
Kindly help. Thanks in advance!
You can't, really. Jar is really meant to package a prepared folder.
I guess this is also why maven etc create a build folder with everything that is going to end up in the jar/war/ear file.
jar uf C:\xx.jar C:\yfile.class
is indeed just adding the file to the archive.
In the folder you are archiving from you can use some -C directive, but that is about it. Suppose yout myfile.class is in a dir called C:\classes and you cal jar from that folder
jar uf C:\xx.jar -C .. classes\file.class
Is going to add the folder classes to the jar with the file myclass.class in it.
Kind regards

Running jar doesn't work

We are trying to make a jar out of our class files but somehow it does not work. The creation of the jar-file works fine with
jar -cvfm client.jar Mainfest.txt /home/pi/Desktop/Client/*.class
But when we try to run it comes with a classnodefferror. Our application is using 2 property files - one for database and one for log4j.
The directory and the one subdirectory included looks like this:
See link - image nr. 1 and 2
When we try to execute the jar file it shows this error:
(See link image 3)
Normally when we run it, we type (see link image 4)
And the manifest-file looks like this (see link image 5)
We have tried different solutions like changing paths, leaving out environment (-D) etc. and we really can't figure out what we do wrong.
There are several problems here:
It is better to explicitly mention each included JAR file in the manifest - wildcards like * isnt working too well
You can't use absolute paths in a JAR file - use relative paths instead
So, 1) change Manifest.txt to
Main-Class: Client
Class-Path: . includes/log4j-1.2.17.jar includes/mysql-connector-java-5.1.33-bin.jar includes/sqlitejdbc-v056.jar includes/RXTXcomm-2.2pre2.jar includes/..... (repeat for all pi4j JAR files)
And, 2) copy ALL the JAR files you need (including RXTXcomm-2.2pre2.jar and the pi4j JARs) into the include/ subdirectory, and change command to
jar -cvfm client.jar Manifest.txt *.class *.properties includes/*

Reference jars inside a jar

I have a jar whose content looks as shown below,
Below is my manifest file
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_06-b24 (Oracle Corporation)
Main-Class: org.sai.com.DerbyDemo
Class-Path: derby.jar derbyclient.jar derbynet.jar derbytools.jar
When i try to run the jar, it has thrown a ClassNotFoundExcception meaning it isn't referencing the jars inside the outer jar.
In the Class-Path attribute, how can I reference jars (derby.jar, etc) inside the actual jar?
You will need a custom class loader for this, have a look at One Jar.
One-JAR lets you package a Java application together with its dependency Jars into a single executable Jar file.
It has an ant task which can simplify the building of it as well.
REFERENCE (from background)
Most developers reasonably assume that putting a dependency Jar file into their own Jar file, and adding a Class-Path attribute to the META-INF/MANIFEST will do the trick:
jarname.jar
| /META-INF
| | MANIFEST.MF
| | Main-Class: com.mydomain.mypackage.Main
| | Class-Path: commons-logging.jar
| /com/mydomain/mypackage
| | Main.class
| commons-logging.jar
Unfortunately this is does not work. The Java Launcher$AppClassLoader does not know how to load classes from a Jar inside a Jar with this kind of Class-Path. Trying to use jar:file:jarname.jar!/commons-logging.jar also leads down a dead-end. This approach will only work if you install (i.e. scatter) the supporting Jar files into the directory where the jarname.jar file is installed.
You can't. From the official tutorial:
By using the Class-Path header in the manifest, you can avoid having
to specify a long -classpath flag when invoking Java to run the your
application.
Note: The Class-Path header points to classes or JAR files on the
local network, not JAR files within the JAR file or classes accessible
over internet protocols. To load classes in JAR files within a JAR
file into the class path, you must write custom code to load those
classes. For example, if MyJar.jar contains another JAR file called
MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's
manifest to load classes in MyUtils.jar into the class path.
In Eclipse you have option to export executable jar.
You have an option to package all project related jars into generated jar and in this way eclipse add custom class loader which will refer to you integrated jars within new jar.
Default implementations of the classloader cannot load from a jar-within-a-jar: in order to do so, the entire 'sub-jar' would have to be loaded into memory, which defeats the random-access benefits of the jar format (reference pending - I'll make an edit once I find the documentation supporting this).
I recommend using a program such as JarSplice to bundle everything for you into one clean executable jar.
Edit: Couldn't find the source reference, but here's an un-resolved RFE off the Sun website describing this exact 'problem': http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4648386
Also, you could 'test' that your program works by placing the library jar files in a \lib sub-directory of your classes directory, then running from the command line. In other words, with the following directory structure:
classes/org/sai/com/DerbyDemo.class
classes/org/sai/com/OtherClassFiles.class
classes/lib/derby.jar
classes/lib/derbyclient.jar
From the command line, navigate to the above-mentioned 'classes' directory, and type:
java -cp .:lib/* org.sai.com.DerbyDemo
if you do not want to create a custom class loader. You can read the jar file stream. And transfer it to a File object. Then you can get the url of the File. Send it to the URLClassLoader, you can load the jar file as you want.
sample:
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("example"+ ".jar");
final File tempFile = File.createTempFile("temp", ".jar");
tempFile.deleteOnExit(); // you can delete the temp file or not
try (FileOutputStream out = new FileOutputStream(tempFile)) {
IOUtils.copy(resourceAsStream, out);
}
IOUtils.closeQuietly(resourceAsStream);
URL url = tempFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
urlClassLoader.loadClass()
...
Add the jar files to your library(if using netbeans) and modify your manifest's file classpath as follows:
Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar
a similar answer exists here
in eclipse, right click project, select RunAs -> Run Configuration and save your run configuration, this will be used when you next export as Runnable JARs

Categories

Resources