How do I include java stuff in .jar files? - java

Okay. So here's my question: I am making a data parser in Clojure. One part of my program is that it has to be able to graph the data. I figure, I'll use jFreeChart. However, I have absolutely NO IDEA how to include stuff in JAR files. What I mean is: if I have a app.jar file in my classpath, I don't seem to be able to do:
import app.thing.thing2
without changing the classpath to be inside the jar file.
The idea here is that I don't think I can change my classpath since I need to set it to run Clojure (Or do I?). The global classpath is currently /usr/share/java.
And please don't ask me to use Maven, Ant or any project-building tool unless it is the only way to do this. This is a script for personal use that doesn't need or want a whole lot of overhead.
I wonder if I should just unpack every JAR file, so that I can reference the directory structure? Is this bad?
Let me know if you need any clarifications!

The content of the (Java) CLASSPATH environment variable is available to Clojure so if you add your jar to the global classpath before to run Clojure, you'll "see" it:
export CLASSPATH=/path/to/jfreechart.jar:$CLASSPATH
But, in my opinion, this is not the "clean" way to add a jar to Clojure's classpath (because this makes the library visible to any Java program and may not be desired). Instead, you should use the CLOJURE_EXT environment variable. This is how this variable is documented:
# CLOJURE_EXT The path to a directory containing (either directly or as
# symbolic links) jar files and/or directories whose paths
# should be in Clojure's classpath. The value of the
# CLASSPATH environment variable for Clojure will be a list
# of these paths followed by the previous value of CLASSPATH
# (if any).
On my system, it is defined as below:
export CLOJURE_EXT=~/.clojure
So, to add jfreechart.jar (or any other library) to Clojures's classpath, copy it (or add a symlink pointing to it) in the directory defined in the CLOJURE_EXT variable.
And by the way (I'm sorry but your question is not that clear), if you want to bundle some Java classes into a jar, the command is something like that:
$ jar cf myjarfile *.class
You'll find documentation of jar - the Java Archive Tool - here.

I completely respect your desire not to use a project management tool, though I just spent longer typing this sentence than it takes to set up leiningen. For your one-off script any tool is going to be overkill and Pascal Thivent's answer covers this very well. For people reading this question who perhaps want to produce a jar file, or easily load their Clojure into emacs/slime-swank I cant recommend leiningen too strongly.

If you going to basics you can inline your classpath to include the hardcoded location of your jars, so if you on windows it will look something like
java -cp .;%CLASSPATH%;C:/here/it/is/foo.jar com.foo.MyClass

Not sure how clojure is run, but don't you just add the jar file to the classpath?
i.e.
/usr/share/java:/home/user/myjarfile.jar

Related

Where is the CLASSPATH?

I would like to use the library "Lucene" with java. The instructions to use it tell me I have to put the jar's cointaining the classes inside the CLASSPATH.
The CLASSPATH is the directory containing all the default classes of Java? Or the directory of my specific project? I'm using Eclipse as IDE.
Really confused about that! Thank you.
USEFUL SOLUTION: http://www.avajava.com/tutorials/lessons/how-do-i-use-lucene-to-index-and-search-text-files.html
The Classpath is a collection of directories and JAR files inside which the Java runtime will look for classes.
It can be configured via an environment variable named CLASSPATH, but this usage is not recommended, as it tends to constantly result in problems.
The preferred way to configure the classpath when running a Java program is to pass it via the -cp command line switch when you start the Java interpreter. Usually you write a shell script so you don't have to type it out every time.
If your issue is with using the classes inside the IDE where you write your code, then it depends of course on the IDE. For eclipse, the "Java Build Path" tab of the project properties is where you configure the classpath.

Redux: How do I get Jython to use Python modules stored in Lib within its own jar file when running in Hadoop?

I'm attempting to use Jython for an implementation within Hadoop 1.2.1. I have seen strikingly little about Jython+Hadoop other than stale projects (like code.google.com/p/happy), and a stale implementation in $HADOOP_HOME/src/examples/python/WordCount.py, so perhaps I'm barking up the wrong tree to begin with... but this seems reasonable and possible. I am also very aware of Hadoop Streaming, with which I can use Python in Hadoop without using Jython, but that's not what I'm trying to do here.
Basically, when I invoke the embedded/standalone Jython jar file using java -jar /full/path/to/myjythonjar.jar, the /full/path/to/myjythonjar.jar/Lib is in my Python sys.path, but when I invoke using bin/hadoop jar /full/path/to/myjythonjar.jar input output the ...jar/Lib is not in my path, and the script can't find the Python modules I'm referencing.
Here's what I'm doing...
I'm using the standalone version of the Jython jar, and using the JarRunner interface, roughly as described on SO here and other places; essentially as follows:
cp jython-standalone-2.7-b1.jar jythonsalib_test.jar
jar ufe jythonsalib_test.jar org.python.util.JarRunner __run__.py
That is, take a copy of the standalone jar, add my script with name __run__.py, and change the Manifest to execute JarRunner -- many thanks to #Frank Wierzbicki for that gem.
This all works fine when I'm running directly as, e.g.,
java -jar jythonsalib_test.jar
My sys.path reports that it includes '/full/path/to/jar/file/jythonsalib_test.jar/Lib', which is exactly what I expect, and it is the path from which I'm getting the Python modules (empirically tested by setting sys.path to null-list (fails) and ONLY that path (works)).
When I run this same jar in Hadoop, e.g., as
bin/hadoop jar /full/path/to/jar/file/jythonsalib_test.jar input output
sys.path only includes
['__classpath__', '__pyclasspath__']
I've also used the Jython standalone jar versions 2.5.4-rc1 (which has the same behavior described above) and 2.5.3 (that doesn't work for me for unrelated reasons).
As pointed out in other SO answers, the workaround I'm currently using is basically to directly add my Lib directory of my jar, inside of the Jython script like
import sys
sys.path.append('/full/path/to/jar/file/jythonsalib_test.jar/Lib')
And this basically works -- but this is meant to be a distributed application! There is no path that I can reference in this way. Other SO articles suggest various mechanisms, but are all basically adding to library paths (again, no links because I have <10rep) by Python like above, Java, or Jython installation or Jython "registry" (startup/rc) files. Sure, I could use HDFS or bootstrapping mechanisms or other mechanisms to distribute something to the compute nodes, like the jar or Jython or whatever, but the code is already in the jar! So I shouldn't need to distribute it again, separately...
So, in sum: It looks like I need to be on a filesystem that can directly, and separately, reference the jar file containing Python modules. (akin to the old java -jar jythonjar.jar -jar jythonjar.jar) How do I convince an embedded, standalone Jython jar to always use the Python modules with in the Lib subdirectory of the Jar file, without separately pointing to (potentially the same) jar file?
Or: how do I add a relative path link to the current jar file...? Or am I missing something more insidious and fundamental about Hadoop or Jython or Java or...?
I had a boatload more links, but SO tells me that I can only have TWO links because I'm new here. I hope some day to get enough rep to be able to truly contribute to this fantastic site! :)
Anyway. LTWFTW -- long time watcher, first time writer -- many thanks!
I wonder if packaging your app with OneJar would improve things. Please try and report back. I´m just shooting in the dark here.
Hadoop (version 2.6.0-cdh5.4.2 running MR1 jobs) + Jython (version 2.7.0) only has this problem in the launching phase: that is, when the main or Tool code is running, Jython's sys.prefix is null and sys.path doesn't contain the /path/to/jarfile.jar/Lib entry that you need, resulting in the error message. In the remote mapper code, the sys.path is correctly set.
One option is to only use Jython in the remote mappers and reducers.
If you need to run Jython in the launching phase, you can edit the sys.path manually (before the first call to PythonInterpreter).
String pathToJar = getClass().getProtectionDomain().getCodeSource().getLocation().getPath().toString();
PySystemState sys = Py.getSystemState;
sys.path.insert(0, new PyString(pathToJar));
See this SO question (or elsewhere) for the pathToJar trick. If you first look at pathToJar, you might think it's not going to work because when you run it in Hadoop, you actually get the path to the exploded jar in a temporary directory, rather than the original jar file. That's okay: this exploded directory has a Lib directory and Jython picks up the exploded one, rather than the jarred one.
Finally, I'm also assuming that your original job jar is a jar-with-dependencies that depends on jython-standalone and excludes hadoop-core, as is normally the case for Hadoop job jars.

Better way to add custom Java classes to Matlab?

I can create Java classes, compile them into *.class files and may be pack them into *.jar files and place anywhere.
But I don't like editing of javaclasspath.txt, because it is systemwide and located somewhere in Matlab directory.
Also I don't like issuing 'javaaddpath' command and similar, because it will require doing this each time.
I would like to attach some jars or class-files to directory. For example, just put them there. Or I would like to add ajr files or classpath entries with Set Path menu of Matlab GUI.
Fortunately, it is said, that "You can also put the JAR file on the MATLAB path." in manual.
But unfortunately, I can activate this. Adding path entries feature does not see jar files and if I add java classpath entry, it does not work.
Is it possible to add classpath entries to Matlab in my suggested way?
You can place the javaaddpath(...) call in a startup.m file that you create and is placed anywhere on your MATLAB path, such as your default start directory.
You will not need to call javaaddpath each time you launch MATLAB because a startup.m on your path is automatically called every time.
It will not be systemwide unless you happen to place the startup.m in one of the MATLAB system paths.
see doc startup
Another variation is to use the -r flag and specify an m-file to run on launch that can be named anything. You can modify the Windows shortcut to use this flag, or create an alias if using Linux.
Follow the "Specifying Startup Options in the MATLAB Startup File" link from the doc startup page mentioned above for more info.
Using a startup file or function is the proper way to handle it - as explained in the other answer.
To see a better way to add jar files dynamically than using javaaddpath, refer to https://stackoverflow.com/a/21489260/2043349.

Java and compiling when not using a IDE

I understand in java that you are forced into a single file per class.
So if I have classes like:
/my_project/main.java
/my_project/classes/user.java
/my_project/classes/other.java
And my main.java references the user and other files, how would I compile this via the command line?
If I was to have external .jar's that I was referencing, and I placed them in a particular folder, how could I also include this in my compiling? (or is there a general place I can put them where they will be picked up automatically like how python does this)
to compile, you will need to specify each source file, from the my_project folder:
javac classes/user.java classes/other.java main.java
You can also specify jar files for your classpath with the -cp option:
javac -cp myjarfile.jar main.java
You may also need to fiddle with the -cp flag to make sure your classes folder is in the classpath.
First of all it's poor style to make Java classes starting with lowercase.
Only public classes need to be in their own file, but you can add as many package-private classes as you like to the same file (although this is seen as poor style).
That said, the easiest way would to compile your code would be:
javac /my_project/main.java /my_project/classes/user.java /my_project/classes/other.java
In any case, proper code layout should be that classes are in a directory structure matching their package.
EDIT: There is a fairly good explanation of conventions here http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter05/packagesImport.html
In addition to the above answer, you can use something like Apache Ant, for easier configuration of your build (if it gets complicated).
Look at the documentation for javac. You can pass multiple source files, or specify the source directory.

How to combine library with my jar?

Ok so i wrote a program that makes use of a 3rd party open source library and i want to package it with my program in a single jar. I'm using netbeans 6.8 and everything I've tried java always spit back the error:
java.lang.NoClassDefFoundError: libraryname;
off topic:also i would like to know how to make an executable-jar(exe) through netbeans if it is possible. (ive seen programs that were written in java but were an .exe)
EDIT discovered a plugin for eclipse called FatJar which can do what i want, but i cant find something similar for netbeans, is there such thing?
I'll start off with the obligatory disclaimer: Java executable JARs do not work this way. An executable JAR has a main class defined in the JAR's MANIFEST.MF file, and the MANIFEST also allows the definition of a class path to include libraries that the code in the executable JAR will need. The class path definition in the MANIFEST must enumerate every JAR or folder to put on the class path, relative paths are relative to the location of the executable JAR - not to paths contained inside the executable JAR. Executable JARs are launched with the "-jar" argument to the java executable, and both the java "-cp" flag and the CLASSPATH environment variable are ignored. As for why executable JARs were designed this way, you should be aware of the primary disadvantage of loading classes from JARs contained within JARs, even though the rest of this reply will focus on doing just that.
NOTE: I lost the original sun forum topic that explained it fully, but essentially it is because entries in the top level JAR can be read in a random access manner, but the entire embedded JAR must be read before any entries can be accessed, because the top level JAR might have compressed its entries.
I have used One-Jar successfully in the past, but the structure of the final resulting jar may not be what you expect. Essentially the One-Jar classes are the only non-JARd classes in the final jar; all other code (your code and any dependent library code) is included in the resulting as JAR as JAR files. Your application is JARed as a regular JAR file named "main.jar" in the final JAR's "main" folder. Any libraries your code needs is placed, as JAR files, in the final JAR's "lib" folder. And last but not least the final JAR's MANIFEST.MF file tells One-Jar what your main class is. Execution is a dead simple "java -jar final.jar [args your app uses]". I don't know how to take the next step of converting to an OS-native EXE regarding your off-topic question, but it would probably be best to use a different packaging mechanism than One-Jar anyway. I'm not sure how to go about this with NetBeans, my advice there is to use a build tool to package the final jar. Fortunately One-Jar provides instructions on generating the final jar with Ant, and that should be easily integratable into NetBeans.
I believe the Eclipse FatJar plugin creates a One-Jar executable JAR, so if that plugin seems to do what you want, then One-Jar is the way to do it. Personally, I used a Maven assembly.
There is a caveat - any signed libraries that require (or desire) to take advantage of Java's signed JAR verification may not work this way - Java Cryptographic Extension (JCE) implementations like BouncyCastle are a notable example. I think the reason is that the signature verification runs against the final JAR, not the signed library. Fortunately One-Jar allows the end user to add additional libraries to the classpath, something that is explicitly precluded when running an executable JAR; to workaround this you might be better off delivering the problematic JARs with the final JAR and an OS dependent launch script (.bat, .sh, etc).
I realize that this doesn't achieve exactly what you want, but I'll describe the customary method of distributing a standalone application. If it does meet your needs, you'll find that it's better supported by tools and more readily understood by users, because it follows established conventions.
Put your code in a jar (I'll call it app.jar) along with a META-INF/MANIFEST.MF file with entries like this:
Main-Class: com.y.app.AppMain
Class-path: third-party.jar blort.jar foo.jar
Then, you can throw all of the jars into a directory and run AppMain like this:
java -jar app.jar
If you want, you can put the third-party libraries in a single directory like lib and refer to them in the Class-path attribute using a path relative to the main jar: lib/third-party.jar That helps keep your distribution tidy.
My generic answer to your off-topic question is a (rather lengthy) article: Convert Java to EXE - Why, When, When Not and How. It has lots of links to free and commercial tools, but I have never seen a Netbeans plugin with such functionality, sorry.
To include another jar in your jar, you might find jarjar useful.
Executable jars just have a class defined as 'Main', if I'm not mistaken. This may be useful.
If there's not any concern of repackaging 3rd party jars into your final big jar, then this should be the easiest method.
If there are no licencing issues then the most preffered way is to unjar the actual jar and rejar it with your class files in it, to a new jar.
You can simply use the jar cmd itself for this, no big deal!!
if you use MAVEN, use "maven-shade-plugin" plugin. It will compile jar with all dependencies(3rd party and etc.)

Categories

Resources