I have a codebase that I want to produce several deliverable jar files, each of which is to be run from the command line and which accesses some functionality of the codebase. When run, some of the command-line parameters are other classes within the jar that are then created by reflection. It works, nicely, but I have to specify the very long fully qualified path to the class, even though the classes are within the jar file.
I am using ant to compile and then jar a series of directories. From a minimal sample build.xml file:
<property name="build" location="build"/>
<property name="jars" location="${build}/jars"/>
<property name="classes" location="${build}/classes"/>
<property name="src" location="src/dom/place/proj"/>
<target name="utility">
<javac
includeantruntime="false"
srcdir="${src}/utility" destdir="${classes}"
classpathref="classpath" />
<jar
destfile="${jars}/utility.jar"
basedir="${classes}"
includes="**/utility/**" />
</target>
<target name="tokenizers" depends="utility">
<javac
includeantruntime="false"
srcdir="${src}/tokenizers"
destdir="${classes}"
classpathref="classpath" />
<jar
destfile="${jars}/tokenizers.jar"
basedir="${classes}"
includes="**/tokenizers/**" />
</target>
Later, I am creating a single jar file that includes all needed classes and will run a command, for example:
<target name="tokenize-file-jar">
<jar destfile="${dist}/TokenizeFile.jar">
<zipgroupfileset dir="${jars}">
<include name="utility.jar"/>
<include name="tokenizers.jar"/>
</zipgroupfileset>
<manifest>
<attribute name="Main-Class" value="dom.place.proj.tokenizers.TokenizeFile"/>
</manifest>
</jar>
</target>
This all works, and looking in the jar file, all the classes are there.
prompt > unzip -l TokenizeFile.jar
Archive: TokenizeFile.jar
Length Date Time Name
-------- ---- ---- ----
0 01-11-12 11:07 META-INF/
286 01-11-12 11:07 META-INF/MANIFEST.MF
0 01-11-12 10:16 dom/
0 01-11-12 10:16 dom/place/
0 01-11-12 10:16 dom/place/proj/
0 01-11-12 10:16 dom/place/proj/tokenizers/
1737 01-11-12 11:07 dom/place/proj/tokenizers/FileTokenizer.class
1411 01-11-12 11:07 dom/place/proj/tokenizers/PorterTokenizer.class
1754 01-11-12 11:07 dom/place/proj/tokenizers/TokenizeFile.class
992 01-11-12 11:07 dom/place/proj/tokenizers/Tokenizer.class
0 01-11-12 10:16 dom/place/proj/utility/
1106 01-11-12 11:07 dom/place/proj/utility/BoundedExecutor.class
3128 01-11-12 11:07 dom/place/proj/utility/Converter.class
1107 01-11-12 11:07 dom/place/proj/utility/ExceptionHandler.class
Now, to run the code, I do:
java -jar TokenizeFile.jar test.txt dom.place.proj.tokenizers.FileTokenizer dom.place.proj.tokenizers.PorterTokenizer
and it works. Yay! But I would prefer my client not have to specify the fully qualified name for each class on the command line - this is a small example, and there may be many items. What can I change, in my code or in my build process, to allow this instead:
java -jar TokenizeFile.jar test.txt FileTokenizer PorterTokenizer
Thanks for your help. I am transitioning from C++/make and like ant and Java very much so far.
The short and simple answer is that this isn't possible; class names are only unambiguous given their package as well.
One option to make things simpler to callers is have your application prepend "dom.place.proj.tokenizers."
to each class argument they provide - so your shorter, preferred example would behave identically to the first one.
However, with great simplicity comes diminished power; it would no longer be possible for a user to define their own custom class and pass it in, as the packages wouldn't match. (To some extent you could work around this by only prepending the default package if the class name doesn't contain a period ( .
), but the more special cases you add the harder this will be to understand...)
You mention that you're transitioning to Java. At the end of the day, I would expect to have classes specified by their full package-prefixed name when they appear in situations like this, and so the abbreviated version would likely be more confusing to someone who's used to Java.
My recommendation therefore is to leave things as they are now, and, basically, become more accustomed to the first version of the command line. Even if you were to solve the problem in this particular case, there are many other first-party and third-party Java apps and tools that require classes to be specified on the command-line - and they all require the fully-qualified class name too.
Apologies if this doesn't seem much like an answer, but I believe it is the best course of action in this situation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.