15

I am trying to use the axis-java2wsdl ant task to create a wsdl from one of my java classes, but I cannot get the classpath correct.

I am using Ubuntu's libaxis-java package which installs axis-ant.jar in $ANT_HOME/lib and axis.jar in /usr/share/java. The interesting parts of my build.xml look like this:

<property name="library.dir" value="lib"/>
<property name="system.library.dir" value="/usr/share/java"/>
<path id="libraries">
    <fileset dir="${library.dir}">
        <include name="*.jar"/>
    </fileset>
    <fileset dir="${system.library.dir}">
        <include name="*.jar"/>
    </fileset>
</path>

<target name="genwsdl" depends="compile">
    <taskdef resource="axis-tasks.properties" classpathref="libraries"/>
    <axis-java2wsdl>
            details omitted
    </axis-java2wsdl>
</target>

Running ant genwsdl results in:

/build.xml:50: taskdef A class needed by class
org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask
cannot be found: org/apache/axis/utils/DefaultAuthenticator

Ant is able to find the definition of the axis-java2wsdl task, because axis-ant.jar is in $ANT_HOME/lib, but it cannot find classes in axis.jar, even though that jar is on the path defined by "libraries"

I know it's a classpath issue because I was able to get past DefaultAuthenticator to other class's not found by symlinking axis.jar into $ANT_HOME/lib. How can I get the taskdef to recognize jar files in /usr/share/lib or my project's local lib directory without symlinking everything into $ANT_HOME/lib?

EDIT:

I was finally able to successfully generate the wsdl with this line:

ant -lib /usr/share/java/axis.jar -lib /usr/share/java/jaxrpc.jar -lib /usr/share/java/wsdl4j.jar -lib /usr/share/java/commons-logging.jar -lib /usr/share/java/commons-discovery.jar -lib build genwsdl

I would still very much appreciate if somebody could tell me what I'm doing wrong in not being able to define those libraries in build.xml

Ryan Ahearn
  • 7,886
  • 7
  • 51
  • 56
  • Looks like the same class-loader problem as this question: http://stackoverflow.com/questions/472559/how-to-load-an-optional-task-into-ant-without-lib-or-global-installation – Dan Dyer Jan 27 '09 at 12:10

6 Answers6

16

In general, this works. But you need to check very carefully which classes are where.

If your task class can be loaded in a classloader higher up in the classloader hierarchy (like CLASSPATH or ANT_HOME/lib) then your classpathref will simply get ignored.

Read the FAQ entry for more details.

Ant's class loader implementation uses Java's delegation model

The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When called upon to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the bootstrap class loader, does not itself have a parent but may serve as the parent of a ClassLoader instance.

Note: running ant -diagnostics can help too.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • That seems like bad behavior, to ignore the classpathref, but it is confirmed by the fact that it all works when I move axis-ant.jar from $ANT_HOME/lib to the /usr/share/java directory that I referenced in the libraries path. – Ryan Ahearn Jan 28 '09 at 00:45
  • 1
    Helped me a lot, 3 years later :) – devmiles.com Apr 07 '12 at 20:06
  • @VladimirVolodin glad to have helped, even three years later ;) – VonC Apr 07 '12 at 20:13
  • @Ryan Important to note that you can *also* solve the problem by copying the needed Axis libraries into `~/.ant/lib`; this way you don't have to mess up your Ubuntu-managed directories. – Luke Maurer Jul 10 '14 at 20:02
5

Ant mechanism for adding libraries is:

  • via command line argument -lib
  • adding to ${user.home}/.ant/lib
  • adding to ${ant.home}/lib

Only. The manual doesn't mention anything about using the system.library.dir property. Probably it pretty much ignored for this purpose.

Also, run ant in verbose mode ( and -verbose ) to see what is doing under the hood.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • system.library.dir is a property that I defined, and is being used successfully by the classpathref in the javac task. Why wouldn't it be used in the taskdef task? It seems strange that you can add libraries with a for compiling, but not for running an external task. – Ryan Ahearn Jan 27 '09 at 05:41
  • Because, that "value" is used for a "program" that will run ( javac ). But attempting to use it for a program that is already running won't work ( the program already running is ant ). – OscarRyz Jan 27 '09 at 17:18
  • 1
    For instance, the "javac" task is defined when the ant is running. But the arguments to javac doesn't. When you use the property you're defining the arguments to javac and then you run it. In the other hand your optional task doesn't exists when ant is already running. Even if you attempt to use... – OscarRyz Jan 27 '09 at 17:53
  • .. the property, the script fails by not having a source where that task is defined. By using one of the listed strategies, you're allowing to ant to define where it should look for that task. – OscarRyz Jan 27 '09 at 17:54
  • 1
    This could be a workaround. Load the property and start a new ant task using the "ant task". See this: http://stackoverflow.com/questions/422848/ant-how-to-modify-java-library-path-in-a-buildfile#422869 – OscarRyz Jan 27 '09 at 17:56
  • Well, it knows where to find the task, it just couldn't find classes that the task needed to run correctly. Thanks for your help. – Ryan Ahearn Jan 28 '09 at 00:43
  • +1 for the `-verbose` reminder – has helped greatly in discovering a missing slash `/` between path elements. – fheub Jun 30 '16 at 07:04
1

It works for me to specify the classpath directly in the taskdef task, as menstioned by matt b. For my project I find it useful to include the taskdef library in the project folder and specify the classpath in the ant build file, to simply setup on other development pcs. I use the following taskdef:

<taskdef resource="antenna.properties" classpath="${myprojectroot}/lib/antenna-bin-1.2.1-beta.jar"/>

Note that this might not work for versions of ant earlier than 1.7.0.

Ralf
  • 14,655
  • 9
  • 48
  • 58
1

Using the answers from here and all the partial information, I came up with a solution. I added the jar the ant file needed to a lib folder in the project (specifically mysql jdbc drivers). Then I run a setup task in ant that copies to the user's home .ant/lib folder, and then fails ant with a message to restart. It only fails once for a user, and then works every time. It might be tricky if you update the jar to a new version...

Here's the ant build.xml:

<project name="data_source" default="build">

  <!-- BUILD PROPERTIES -->
  <property file="build.properties"/>

  <!-- SQL Server Properties -->
  <property name="sql.driver" value="org.gjt.mm.mysql.Driver"/>
  <property name="sql.url" value="jdbc:mysql://127.0.0.1/datastore"/>
  <property name="sql.user" value="user"/>
  <property name="sql.pass" value="password"/>

  <!-- FILE LOCATIONS  -->
  <property name="sql.dir" location="sql"/>

  <!-- INITIALIZE PROJECT -->
  <target name="init" description="Initialize the project">
      <available property="no.ant.lib.dir" file="${user.home}/.ant/lib/" type="dir" />
  </target>

  <!-- SETUP MYSQL -->
  <target name="setup_mysql" description="Copy the lib so ant can see it" unless="no.ant.lib.dir">
      <mkdir dir="${user.home}/.ant"/>
      <mkdir dir="${user.home}/.ant/lib"/>
      <copy file="lib/mysql-connector-java-5.1.13-bin.jar" todir="${user.home}/.ant/lib"/>

      <!-- ant already missed picking up the jar - we have to restart -->
      <fail message="JDBC mysql class copied to ${user.dir}/.ant/lib/ - please restart ant" />
  </target>

  <!-- BUILD DATA SOURCES -->
  <target name="build" depends="init,setup_mysql,clean_data" description="Create and populate tables">

    <sql driver="${sql.driver}" url="${sql.url}" userid="${sql.user}" password="${sql.pass}" >
      <transaction src="${sql.dir}/create_tables.sql"/>
      <transaction src="${sql.dir}/insert_data.sql"/>
    </sql>
  </target>

   <!-- CLEAN PROJECT -->
  <target name="clean" description="Cleans up project build">
    <!-- Don't clean data sources here - may get called by accident -->
  </target>

  <!-- Delete all tables and data -->
  <target name="clean_data" description="Deletes all data and tables">
    <echo>Dropping all database tables in ${sql.schema}...</echo>
    <property name="exec.command" value="mysqldump -u${sql.user} -p${sql.pass} --add-drop-table --no-data ${sql.schema} | grep ^DROP | mysql -u${sql.user} -p${sql.pass} ${sql.schema}" />
    <exec executable="sh">
      <arg value = "-c"/>
      <arg value="${exec.command}"/>
    </exec>

  </target>

</project>

Hope this helps

Kieveli
  • 10,944
  • 6
  • 56
  • 81
  • 1
    Interesting solution. Could probably be made a bit smarter (check for actual .jar file instead of just the directory in init) but I'll have to remember this next time I run into this problem. – Ryan Ahearn Dec 08 '10 at 21:21
1

Why not just take the simplest option and specify the classpath in your <taskdef>?

<taskdef resource="axis-tasks.properties">
    <classpath>
        <fileset file="/path/to/axis/jars"/>
    </classpath>
</taskdef>

Or create a second <classpath> entry that subsets library.dir?

<path id="axis-tools-classpath">
    <fileset dir="/path/to/axis/home">
        <include name="*.jar"/>
    </fileset>
    <path refid="library.dir"/>
</path>

Messing around with ${ant.home}/lib is not such a good idea and can almost always be avoided.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • taskdef is ignoring the classpathref and also ignoring any direct classpath in it's task. I believe the problem is as VonC stated and the axis-ant.jar is found in a classloader that cannot find axis.jar so the solution is to either use -lib or sumlinks in ~/.ant/lib – Ryan Ahearn Jan 28 '09 at 00:35
  • Perhaps you need to resolve the layout of your libraries then - sounds like you could address the problem by making sure that whatever classloader finds axis-ant.jar also has an axis.jar available to it. – matt b Jan 28 '09 at 15:03
  • Agreed, the layout of the libraries is not ideal. It is the layout that is default after you install ant and libaxis-java packages in Ubuntu. But also not ideal is moving around those packages or throwing a bunch of symlinks in $ANT_HOME/lib. – Ryan Ahearn Jan 28 '09 at 17:29
  • I am generally happy with the solution of adding a shell script to the project that calls ant with the correct -lib arguments. – Ryan Ahearn Jan 28 '09 at 17:30
0

I met the same problem when I copy a *.jar to the {ant.home}/libs, then i user the -lib to locate the *.jar, it's runs ok! I consider it's the new jars can't be loaded, then i'll test it!

Andrew
  • 21
  • 1