Enforce compilation dependencies with Ant compiler tasks - java

There are certain compiler dependencies that are not allowed in our (Java) environment. We have two servers, call them Application and Process. We have three root Java packages, call them Application, Process, and Shared. Application and Process are not allowed to reference each other, but they can each reference Shared. Shared can reference any class in any of the other two packages. How can I enforce these dependencies with Ant? The problem, as you might guess, is that in our Eclipse based environment everything compiles successfully, but we've come across runtime errors where a class is not there (since we have multiple servers).
I have attempted quite a few things but nothing has worked. See my current attempt below, where I have omitted irrelevant code for clarity. Comments are included.
<!--Compile the 'shared' directories. Since shared depends on Application and Process, we compile everything then delete Application and Process later. -->
<javac srcdir="${src.dir}" destdir="${build.dir}">
<classpath>
...
</classpath>
</javac>
<delete dir="${build.dir}/application" />
<delete dir="${build.dir}/process" />
<!--Compile the 'application' directories -->
<javac sourcepath="" srcdir="${src.dir}/application" destdir="${build.dir}">
<classpath>
<pathelement location="${build.dir}/shared" />
...
</classpath>
</javac>
<!--Compile the 'process' directories -->
<javac sourcepath="" srcdir="${src.dir}/process" destdir="${build.dir}">
<classpath>
<pathelement location="${build.dir}/shared" />
...
</classpath>
</javac>

you need to split shared into three parts, shared-standalone, shared-application and shared-process.
compile shared-standalone first,
compile shared-application together with application,
compile shared-process together with process.

Related

Why do we set classpath in ant

Below is the code for setting class path in ant.
<path id="build.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</path>
<target name="compile" depends="clean">
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="build.classpath" />
</target>
Why do we need to set classpath in ant ?
Think of ant as a framework to run your build tasks - compiling the code, running the (unit) tests, etc. In order to properly compile and execute your (test) code, java will need access to the third party libraries you may be using (e.g., JUnit for running unit tests). The classpath tells java where these JARs are located, so it can use them.

How to compile the annotation processor with Ant?

The question seems to be obvious, but the implementation is pretty hard for me.
My goal is to write Ant build script to compile some classes that require another classes generated by Annotation Processor.
I have a custom annotations and it's processor implementation (inherited from AbstractProcessor class).
As I understand I need to:
Compile the Annotation Processor
Run the compiler over some annotated classes to generate the new ones.
Compile the classes that require generated classes
The code (step 1 & 2):
<target name="compileAnnotationProcessor">
<javac destdir="${OUTPUT_DIR}"
debug="true"
failonerror="true"
includeantruntime="false"
classpath="${java.class.path}">
<src>
<pathelement path="${PROJECT_DIR}/tools/src"/>
</src>
<include name="/path/to/annotation/processor/package/**"/>
</javac>
</target>
<target name="generateFilesWithAPT" depends="compileAnnotationProcessor">
<javac destdir="${OUTPUT_DIR}"
includeantruntime="false"
listfiles="false"
fork="true"
debug="true"
verbose="true">
<src>
<pathelement path="${PROJECT_DIR}/common/src/"/>
</src>
<include name="/path/to/files/to/compile/**"/>
<classpath>
<pathelement path="${OUTPUT_DIR}"/>
<pathelement path="${java.class.path}"/>
</classpath>
<compilerarg line="-proc:only"/>
<compilerarg line="-processorpath ${OUTPUT_DIR}/path/to/annotation/processor/package/annProcessorImplement"/>
</javac>
</target>
Actually, the first task is performing good and compiles the .class file for the Annotation processor implementation. It is stopping at 2nd task.
Ant says: Annotation processing without compilation requested but no processors were found.
What am I doing wrong?
Maybe I should put the annotation processor class in a .jar? Or provide a file name with .class extension as -processorpath argument?
I tried several options but nothing helps..
Notes:
I'm using ant javac task instead of aptone because documentation claims that apt tool as well as com.sun.mirror API is deprecated.
I've also looked through this question, but there is no information how to compile the processor in right way.
I'm using:
Java 1.6
Ant 1.8.2
My usual approach is:
pack the annotation together with the annotation processor in its own jar
register the annotation processor via META-INF/services in that jar
Then wherever you have a dependency on your annotations, the annotation processor will be picked up automatically without any additional configuration.

Getting CLASSPATH from environment in ant build.xml

How can I get the CLASSPATH from the environment in a build.xml?
I've tried
<property environment="env"/>
<path id="classpath">
<pathelement location="${env.CLASSPATH}"/>
</path>
<target name="compile">
<javac includeantruntime="false">
<src path="${src}"/>
<classpath refid="classpath"/>
</javac>
</target>
I have a feeling this is failing because ${env.CLASSPATH} is a colon-separated list.
How then, can I get my classpath? I was surprised when ant didn't use my environment's CLASSPATH.
EDIT:
I've found a quick solution, but the preferred method is to use a separate properties file like the example here http://www.java2s.com/Code/Java/Ant/Useseparatepropertyfile.htm
Solution is, add
<property name="build.sysclasspath" value="first"/>
to the top of the build.xml
Yes, it's failing because it's a colon-separated list. In general, it's considered a bad idea to specify the class-path externally and use it within Ant. This is because running the same Ant script on different machines may yield different results. Instead, you're better of specifying the class-path from within Ant.

Ant unless attribute not working?

I must be not understanding the unless attribute properly. I have a properties file that has a property as follows:
module.project.enabled=false
module.finance.enabled=true
And in my Ant build file I have the following piece
<echo message="Finance module enabled is ${module.finance.enabled}"/>
<echo message="Project module enabled is ${module.project.enabled}"/>
<javac srcdir="src" destdir="${classes}" debug="true">
<classpath>
<pathelement path="src"/>
<fileset dir="web/WEB-INF/lib" includes="*.jar"/>
<fileset dir="lib" includes="*.jar"/>
<fileset dir="${GWT.HOME}" includes="gwt-user.jar,gwt-servlet.jar"/>
</classpath>
<exclude name="bla/finance/*.java" unless="${module.finance.enabled}"/>
<exclude name="bla/project/*.java" unless="${module.project.enabled}"/>
</javac>
When running my ant target the properties do seem to be read
[echo] Finance module enabled is true
[echo] Project module enabled is false
But when I look at the ${classes} directory I would have expected to see no classes in the project package and classes in the finance package but alas it seems to be excluding both packages?
For Ant 1.7 and prior, the if and unless attributes only check if a property is set. They don't actually check the value. You could in fact set it to anything, and that'll evaluate as true for if and false for unless. Likewise if you don't set it at all, you'll get false for if and true for unless.
In either case I'm not aware of the if and unless being available for <exclude>.

How can I exclude sources in a javac task in ant?

I have the following in my build.xml:
<target name="compile.baz" depends="init">
<javac destdir="${build.dir}/classes" debug="on">
<compilerarg value="-Xlint:deprecation"/>
<src>
<pathelement location="${src.dir}/com/foo/bar/baz/" />
<pathelement location="${src.dir}/com/foo/bar/quux/" />
<!-- Need to exclude ${src.dir}/com/foo/bar/quux/dontwant/ -->
</src>
<classpath refid="classpath.jars" />
</javac>
...
</target>
This mostly does what I want, except that (as the comment says) I do not want the files in
${src.dir}/com/foo/bar/quux/dontwant/ to be compiled by this task (but I do want everything else under ${src.dir}/com/foo/bar/quux/ to be compiled in this task).
I'm a complete ant n00b, and the documentation hasn't been much help to me. I see several places where it says there are various exclude/excludes elements/attributes, but every variation I can think of either has no effect or results in an error like "blah doesn't support the 'exclude' attribute".
A couple of people suggested using <exclude>. This didn't work with the way my task was specified. trashgod's answer linked to the sixth example on this page which gave me an idea of how to restructure my task specification.
It looks like my problem was related to the way I was specifying the source files. Rather than using <pathelement> elements in a <src>, like this:
<src>
<pathelement location="${src.dir}/com/foo/bar/baz/" />
<pathelement location="${src.dir}/com/foo/bar/quux/" />
</src>
I switched to using a single <src> with a path and then a set of <include> elements, like this:
<src path="${src.dir}" />
<include name="com/foo/bar/baz/**" />
<include name="com/foo/bar/quux/**" />
This appears to be functionally identical, but is compatible with the use of <exclude>:
<exclude name="${src.dir}/com/foo/bar/quux/dontwant/**"/>
(Actually, I'm surprised that what was there in the first place worked at all.)
From my experiments you should not include full path for file you want to exclude.
This one doesn't work:
<javac>
(...>
<exclude name="${src.dir}/com/foo/blah/blah1/FILENAME.java"/>
(...)
</javac>
but this one does:
<javac>
(...>
<exclude name="com/foo/blah/blah1/FILENAME.java"/>
(...)
</javac>
Try
<javac>
(...>
<exclude name="${src.dir}/com/foo/bar/quux/dontwant/*" />
(...)
</javac>
I'm not sure about the rest, but the <exclude/> nested element should work in the Javac task. See the sixth example down.
Addendum: Patterns, including the ** notation, are discussed in Directory-based Tasks.
<target name="compile.baz" depends="init">
<javac destdir="${build.dir}/classes" debug="on">
<compilerarg value="-Xlint:deprecation"/>
<src>
<pathelement location="${src.dir}/com/foo/bar/baz/" />
<pathelement location="${src.dir}/com/foo/bar/quux/" />
</src>
<exclude name="${src.dir}/com/foo/bar/quux/dontwant/**"/>
...
</javac>
...
</target>
If you are trying to exclude Java classes but Ant is still trying to compile them then this may be due to references to these classes in your code.
If A.java has a reference to B.java and you try to exclude B.java then compiling A.java will require that B.java is compiled too.
This is one reason for interfaces in Java, so you can compile the interface without needing to compile the implementations.
try
folder "test" under {source.dir} would not be complied
<javac destdir="${compile.dir}" ...>
<src path="${source.dir}" />
<exclude name="test/**"/>
</javac>

Categories

Resources