Jar Manifest Properties

I’ve been using properties in manifest files to make Jar files executables. This suits me very well… but… I want to use some properties to the JVM… is there a property in the manifest file I can use to set these up?

Kev

I doubt it. The manifest is parsed in the JVM, after the JVM has loaded. Command line options are probably parsed during JVM initilization.

I looked and looked, but to no avail. I wanted a double-click jar with JVM flags set, but that isn’t possible.

You can, however, specify the classpath. yippee.

I’m having trouble doing this though.

java -jar ignores all -cp and environment variable settings, so the only way to give a classpath is through the jar’s manifest.

So with this in mind, why does the following simple example work as expected with the compile and test targets, but the jar file generated complain of not finding com.sun.jdi.BootStrap when i try to run it with java -jar?

the code:


import com.sun.jdi.*;
import com.sun.jdi.connect.*;

import java.util.*;

public class ObjectGraph
{

      public static void main( String[] args )
      {

            System.out.println( "Classpath set to :" );
            System.out.println( System.getProperty( "java.class.path" ) );

            Bootstrap bs = new Bootstrap();
            VirtualMachineManager vmm = bs.virtualMachineManager();

            List connectors = vmm.allConnectors();

            ListIterator iter = connectors.listIterator();

            while( iter.hasNext() )
            {
                  System.out.println( ( ( Connector ) iter.next() ).description() );
            }
      }
}

the ant build.xml file

<project name="ObjectGraph" default="compile" basedir=".">

      <description>
            Builds ObjectGraph to varying degrees
      </description>
      <!-- set global properties for this build -->
      <property name="build" location="build"/>
      <property name="JDIlib" location="/usr/java/j2sdk1.4.2/lib/tools.jar"/>

      <target name="init">
            <!-- Create the time stamp -->
            <tstamp/>
            <!-- Create the build directory structure used by compile -->
            <mkdir dir="${build}"/>
      </target>

      <target name="compile" depends="init"
                  description="compile the source" >
            <!-- Compile the java code from ${src} into ${build}-->
            <record name="compilelog.txt" action="start" append="false" emacsmode="true"/>

            <javac srcdir="." destdir="${build}" debug="true"
                                          classpath="${JDIlib}"
                                          debuglevel="source,lines,vars" />

            <record name="compilelog.txt" action="stop"/>
      </target>

      <target name="jar" depends="compile"
                  description="generate the distribution" >

            <!-- Put everything in ${build} into the ObjectGraph.jar file-->
            <jar jarfile="ObjectGraph.jar" basedir="${build}" index="true">
                  <manifest>
                        <attribute name="Class-Path" value="${JDIlib}"/>
                        <attribute name="Main-Class" value="ObjectGraph"/>
                  </manifest>
            </jar>
      </target>

      <target name="test" depends="compile"
                  description="start up the application for testing" >
            <record name="runlog.txt" action="start" append="false" emacsmode="true"/>

            <java classname="ObjectGraph" fork="true" >
                  <classpath>
                        <pathelement location="${build}"/>
                        <pathelement location="${JDIlib}"/>
                  </classpath>
            </java>

            <record name="runlog.txt" action="stop"/>
      </target>

      <target name="clean" description="clean up" >
            <!-- Delete the ${build} directory tree -->
            <delete dir="${build}"/>
            <delete file="compilelog.txt"/>
            <delete file="runlog.txt"/>
      </target>

</project>

You may have to alter the value of JDIlib in the ant file to get it running on your system.

No doubt there’s some trivial, obvious reason for this annoying behaviour, and i would love for someone to enlighten me.

Cheers

Personally I don’t find that executable jar files are flexable enough. Sure - I normally give them a Main-Class tag (and Class Path tag) anyway as it’s pretty simple - but I always supply OS dependant shell scripts with them.

This two pronged approach means that people who like executable jar’s have them. But the following benifits from shell scripts are also added:

  • power users edit them and see what commands you can change.
  • the “jar” file association might have been lost preventing exectuable jars from working (I have seen this - WinRAR I think did it).
  • If java isnt’ installed - a clever batch script can alert the user ie. “echo Make sure you hava Java (java.com) installed! - followed by a “pause””
  • JVM flags can be set
  • Some users don’t know what a .jar file is! It’s easy to forget when you use java every day but for the newer users a .bat file is probably easier to understand
  • there is no debugging output from a crashing .jar file. Worse - if it crashes on load nothing happens. That is the worst thing for the user “um I double clicked and nothing happened”. Since Java stack traces are quite useful and somthing even a novice end user can submit to you why cut this option out?

the last .bat file I made for my application has a big chunk of text at the top explaining that Java 1.4 or better is needed. I use “java -showversion” so an end user with half a clue can work it out, I mention java.com and my own support forums. After the java command, I print more text - and have a pause statement (else the .bat will simply exit straight away). I am hoping this will reduce the number of emails I have to send to people saying “download Java 1.4!”

I am also against the idea that all java applications should be a single jar file. While some may be suited to this - if you have editable (text) options and the likes it may be favourable to have other files in the directory as well.

Jar files are great - and exectuable ones can be handy but I am wary of their limitations and always provide alternatives.

Cheers,

Willl.

Fair enough, but I’d still quite like to know why the above doesn’t work.

Ah well, I suppose I can use System.setProperty() for now.

Aha!

Found the problem, it seems that the “index” flag in Ant’s jar task does not generate the index properly, and so you need to do it seperately like so:


            <echo>Generate *correct* index files for jar. Bloody ant...</echo>
            <exec executable="jar">
                  <arg value="-i"/>
                  <arg value="MyJar.jar"/>
            </exec>

All’s well
:slight_smile:

sorry - I hadn’t read your code, I was just giving my $0.02 on Jar files :slight_smile:

You can’t have absolute paths in your Class-Path attribute - they all must be relitive to the jar file (this is so it works when you put them on other peoples systems, or the internet etc) if you do java just ignores them.

You would need to bundle the tools.jar file in say a “lib/” directory then specify it as “lib/tools.jar” as the Class-Path.

I learned that inadvertantly yesterday when trying to work out how to get two jar files recognised in the Class-Path (and the answer to that is just add a space between them, eg. “lib/foo.jar lib/bar.jar”.

The other option is to pop “tools.jar” into your default class path ie. “/jre/lib/ext/” which would then negate the need of specifying it as in a class path.

Cheers,

Will.

[quote]You can’t have absolute paths in your Class-Path attribute - they all must be relitive to the jar file
[/quote]
I suppose that’s fair enough, but it could be documented better ( or indeed at all )

I suppose the real problem is that, while tools.jar is part of the JRE distribution ( It contains, among other things, the [link=http://java.sun.com/j2se/1.4.2/docs/guide/jpda/index.html]JPDA[/link] classes ), it strangely is not in a place where it will automatically be part of the classpath :-/