How to use Ant include non-java resource files with compiled classes - java

I have a Java project with all source files in the src folder. This src folder contains several packages. Some of these packages/folders do not include any Java code. They just contain some images that I use in the application as icons.
The directory structure is similar to the following.
src/
com/
example/
pk1/ # This contains only some Java files.
pk2/ # This will contain some XML and Java code.
im1/ # This subfolder will contain just the images
Now, when I use the javac task, it compiles all the Java files into class files and stores them in the destination directory that I specify. However, an non-java files remain as is in the source folder.
I referred this Question on SO. However, I think in my case I want to include all non-Java resource files (without the need to explicitly specifying what files to be moved) automatically into the build directory (one that contains all the class files) while following the same directory structure as in source.
Pardon me if I am missing something very trivial, but how do I ask Ant to do this?

Use the ant copy task to copy your resources into the classes directory (or wherever your .class files are stored). By default, ant keeps the directory structure.
For example:
<copy todir="classes">
<fileset dir="com/example">
<exclude name="**/*.java"/>
</fileset>
</copy>

Just to complete the previous answer, the block
<copy todir="classes">
<fileset dir="com/example">
<exclude name="**/*.java"/>
</fileset>
</copy>
goes before the task javac
<javac [...]
and inside the target compile
<target name="compile" [...]
then
<target name="compile" [...]>
<copy todir="&&&" [...]>
[...]
</copy>
<javac srcdir="[...]" destdir="&&&" >
</javac>
</target>
in my case the attribute "todir" of tag "copy" it's the same of the attribute "destdir" of tag "javac"; I wanted to detailing the answer in order to give you a resolution as immediate as possible.

Related

ant fixcrlf include/exclude does not work

I am having little problem with fixcrlf from ant. When I try to compile for unix target with fixcrlf filter, it modifies all files in the target folder, no matter of includes and excludes. I expect it should not convert any files that are not in the includes patterns, or at least I could force some files to not be converted via excludes attribute. None of that I tried been able to exclude anything. Even some binary files are modified and as result screwed up.
According to fixcrlf documentation from apache site, these parameters should work like this:
includes: comma- or space-separated list of patterns of files that must be included.
excludes: comma- or space-separated list of patterns of files that must be excluded.
When I run ant with parameters -verbose and -debug, there is no information on that fixcrlf did.
<copy todir="target">
<fileset dir="source1"><exclude name="**/*.bak"/></fileset>
<fileset dir="source2"><exclude name="**/*.bak"/></fileset>
<filterchain>
<fixcrlf srcdir="${src}" includes="**/*.sh,**/*.properties" excludes="**/*.xml" eol="lf" />
</filterchain>
</copy>

Missing class errors running Java built with Ant

I have some code that I revised.
When I try to just run Ant in the directory it fails with missing classes. I can specify the location to the existing classes by using the -lib option to ant. The compile then works fine, however dist ZIP file that is created appears to have missing libraries, as when I try to run it, I see errors relating to missing classes which are the classes that I specified with the -lib option, so this is probably due to the way I have used the -lib option.
How can I force the regular Ant command to include the additional classes specified with the -lib command?
You can write a target that will copy your lib directory/files in your zip file.
Let's say create a temp dir then copy your files then execute target for copying lib directory and then zip temp dir.
<target name="copyLib">
<copy todir="${temp.dir}">
<fileset dir="${lib.dir}">
<include name="*.jar" />
</fileset>
</copy>
</target>
Update paths and call this target into your create zip target.
Compiler task could look like this:
<javac srcdir="${base}/src"
destdir="${base}/classes"
classpath="${base}/lib">
</javac>
And the zip task could look like this:
<zip
destfile="${base}/dist.jar"
basedir="${base}/classes"
includes="..."
excludes="...">
</zip>
So sources are compiled in classes and zipped in a jar, but libraries used for compile are not included in the jar, they are runtime dependencies.
I would suggest that you declare your paths at the top of your ANT scripts as follows, using a fileset.
<path id="build.path">
<fileset dir="lib" includes="*.jar"/>
</path>
Less error prone compared to forcing users to specify the correct "-lib" parameter.
Finally the same fileset can then be used to include the same jars inside the zip file you're creating:
<zip destfile="${dist.dir}/mycode.zip">
..
..
<fileset dir="lib" includes="*.jar"/>
</zip>

I need to fail the build when a package imports from another package within the same project. How can I do so cleanly?

For a variety of reasons (regardless of whether or not this is a wise idea) we have a project with several packages (say one, two, three) that are similar in structure. There is one additional common package.
I want the build to fail when something in each of those packages imports something that isn't in common, e.g. because you accidentally accepted the wrong import completion, or because Eclipse silently brought over the wrong imports while copy-pasting bug fixes from one into two.
What works is copying all the source files, except for each package, over to a temporary folder and attempting to build the result:
<target name="enforce-no-cross-imports">
<phony-build without="one"/>
<phony-build without="two"/>
<phony-build without="three"/>
</target>
<macrodef name="phony-build">
<attribute name="without" />
<sequential>
<echo message="Checking there are no cross imports to the #{without} package." />
<mkdir dir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/src" />
<mkdir dir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/bin" />
<copy todir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/src">
<fileset dir="${src.dir}">
<include name="**/*.java"/>
<exclude name="**/#{without}/"/>
</fileset>
</copy>
<javac srcdir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/src"
destdir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/bin"
classpathref="classpath" encoding="UTF-8" nowarn="on"/>
<delete dir="${java.io.tmpdir}/my-awesome-project" />
</sequential>
</macrodef>
However, when the build DOES break, the error obviously occurs inside ${java.io.tmpdir}.
enforce-no-cross-imports:
[echo] Checking there are no cross imports to the one package.
[mkdir] Created dir: C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\src
[mkdir] Created dir: C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\bin
[copy] Copying 47 files to C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\src
[javac] Compiling 47 source files to C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\bin
[javac] C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\src\my\awesome\project\two\very\long\path\SomeController.java:43: package my.awesome.project.one.very.long.path.SomeConstantsClass does not exist
[javac] public static final String TEST = my.awesome.project.one.very.long.path.SomeConstantsClass.TEST;
As a result I can't click on the file name to jump directly to the issue. This adds way too much friction to the compilation process: it's bad enough that I'm effectively tripling the project build times.
What I thought I could do instead is not copy the files over and use the excludes attribute on the javac task instead:
excludes: Comma- or space-separated list of files (may be specified using wildcard patterns) that must be excluded; no files (except default excludes) are excluded when omitted.
...except this does not cause the build to break. What happens is that javac will not compile the other packages, but it will still look at them for confirmation. Turning on verbose shows this log line:
[javac] [checking my.awesome.project.one.very.long.path.SomeConstantsClass]
includeDestClasses seemed like another helpful flag, but setting it to false didn't help. <compilerarg value="-implicit:none"/> also was not helpful.
How can I tell javac that it really positively does need to exclude those files from the build, even if they are right there?
Alternatively, how can I take the output of javac and run find-replace on it so that the console output shows the correct path instead?
You could use the compilewithwalls or verifydesign tasks of ant-contrib, but the safest way to enforce separation like this is to isolate the modules into separate source directories and compile them independently. You'd first build the common module, then build each of the other modules with the compiled classes of "common" on their classpaths but not the classes of any of the other modules. This is the default approach when you're building with a higher level build tool like Maven. If you have a directory structure like this:
build.xml
lib
library JAR files
common
src
classes
one
src
classes
two
src
classes
then you could structure the build as
<macrodef name="compile-module">
<attribute name="module" />
<element name="depends" implicit="true" optional="true"/>
<sequential>
<javac srcDir="#{module}/src" destDir="#{module}/classes"
encoding="UTF-8" nowarn="on">
<classpath>
<path refid="classpath" />
<depends/>
</classpath>
</javac>
</sequential>
</macrodef>
<compile-module name="common" />
<compile-module name="one">
<pathelement location="common/classes" />
</compile-module>
<compile-module name="two">
<pathelement location="common/classes" />
</compile-module>
<compile-module name="three">
<pathelement location="common/classes" />
</compile-module>
You mention Eclipse in the question, so you'd need to do something similar there. Eclipse allows the root of one project to be inside another, so you could create one main Eclipse project "myapp-common" pointed at your project root with just common/src as its source directory (and common/classes as the corresponding output directory), then create separate "myapp-one", "myapp-two" etc. projects rooted at the one, two, etc. folders, each depending on the "myapp-common" project. That way you would never get Eclipse offering the "wrong" auto-completion, as project one simply cannot see project two or vice versa.

Apache Ant {Compile javac srcdir} does not exist

I am new to apache ant and I am currently working on an apache Ant project. I Just started out, imported the project into workspace and tried to run the build.xml. I added all the libraries that come with the original project to the build path. I am having the following problem. Please someone else wrote the code and I am supposed to improve it. The directories this is all about exist in the project directory.
BUILD FAILED
C:\workspace\MyApp\build.xml:83: srcdir "C:\workspace\MyApp\${compile.javac.srcdir}" does not exist!
The error code is referencing the following part of the build.xml file
<target name="compile.default" depends="init">
<javac fork="yes" srcdir="${compile.javac.srcdir}" destdir="${compile.javac.destdir}" includes="${compile.javac.include}" excludes="${compile.javac.exclude}" classpath="${compile.javac.classpath}" debug="${compile.javac.debug}" optimize="${compile.javac.optimize}" deprecation="${compile.javac.deprecation}" verbose="${compile.javac.verbose}">
</javac>
<copy todir="${compile.javac.destdir}">
<fileset dir="${compile.javac.srcdir}" includes="${compile.copy.include}" excludes="${compile.copy.exclude}"/>
</copy>
</target>
<target name="compile" depends="init,compile.default" description="Compile all java source">
</target>
<!--+++++++++++++++-->
<!-- lib target(s) -->
<!--+++++++++++++++-->
<target name="lib.default" depends="init,compile">
<xmlbean schema="config/schemas/validate/1.0/validate.xsd" destfile="lib/glx-beans.jar" classpath="lib/xbean.jar:lib/jsr173_1.0_api.jar" />
<jar jarfile="${lib.filename}">
<fileset dir="${lib.srcdir}" excludes="${lib.exclude}" />
</jar>
</target>
<target name="lib" depends="init,compile,lib.default" description="Create all Project Libraries">
</target>
Would you please tell me what I am missing?
The ${compile.javac.srcdir} isn't defined. There are a few possibilities:
This is defined not in the build.xml, but in some sort of properties file. See if you have something like <property file="..."/> in your build script. My recommendation is to have all properties defined in the build.xml file, and use a properties file to override those settings. This way, the only build file that a developer needs in the build.xml file and doesn't have to worry about setting up a separate build.porperties file.
This is defined in the build.xml file under a particular task, but you forgot to say that your target where you use thisis dependent upon this task.
One of the things you can do is use the -d parameter when running Ant. I run the following command when running Ant with the -d parameter:
$ and -d 2>&1 | tee ant.out
I can then look at ant.out and see if somehow I didn't define that particular property. Maybe I had the wrong capitalization or misspelled the property name. For example, it's very likely I'll define the property as copmile.javac.srcdir because I don't know how to spell. Looking at the -d output can quickly point these types of errors out.
By the way, you shouldn't have all of your tasks dependent upon init since they're dependent upon compile.default anyway:
<target name="compile.default" depends="init">
....
</target>
<target name="compile" depends="compile.default">
....
</target>
<target name="lib" depends="compile,lib.default">
....
</target>
If I run the target lib, it will see compile is dependent upon compile.default which is dependent upon init. Thus, your build will run init, then compile.default, then compile, then 'lib.defaultand finallylib`.
If the init task is just setting up properties, you can do that outside of any task. Then, these properties will be setup before any task is executed. This way, they're not forgotten. If your init is also creating directories, you may want to move those <mkdir/> tasks in front of the task where that directory is used. For example, you may want to make the destdir uses in javac before the <javac/> task.
I find assigning default properties outside of any task, and creating directories before they are needed to simplify the build.xml. Plus, you're not creating a whole flock of unused directories if the user is merely compiling and not packaging the jar/war/etc.

Ant task for easier deployment

We have quite a big tree of source code, parts of it are deployed as two separate jar files. We need an easy control of what goes to which jar.
So far we do this by <exclude name="" /> and <include name="" /> tags, but this is quite inconvenient. The best option would be a separate config file with all the packages listed which we could comment out when needed, say with a '#' character.
Does something similar exist or do we have to write a new ant task that reads such a file and runs a <jar> task?
The best option would bee to seperate the code into different modules which can be build on their own (of course with dependencies to each other). Doing this also makes cyclic dependencies obvious and gives you the chance to optimize your code base.
ANT includes and excludes can be managed with external files and referenced in a fileset using includesfile and excludesfile attributes.
includesfile the name of a file; each
line of this file is taken to be an
include pattern.
excludesfile the
name of a file; each line of this file
is taken to be an exclude pattern.
For example:
<jar destfile="${dist}/lib/app1.jar">
<fileset dir=".">
<includesfile name="app1.properties"/>
</fileset>
</jar>
<jar destfile="${dist}/lib/app2.jar">
<fileset dir=".">
<includesfile name="app2.properties"/>
</fileset>
</jar>

Categories

Resources