I created a little framework for myself which I want to use in multiple projects. I also want the distributed jar-file to include all external libraries so that my projects just need to include my library to access all external libraries.
I need this to simplify updating the external libraries.
So I placed this in my build.xml which adds all libraries from dist/lib into my own jar-file.
<target name="-post-jar">
<!-- Include all java libraries -->
<fileset dir="dist/lib" id="extern.libs">
<include name="*.jar" />
</fileset>
<!-- Add the libraries from the fileset to the project.jar -->
<jar jarfile="${dist.jar}" update="true">
<zipgroupfileset refid="extern.libs"/>
</jar>
</target>
But when I try to use external libraries like "org.zkoss.zk.ui.Component" I get the error that this library could not be found.
Is there a better way to include the external libraries into my own library so that my project can use them?
You can publish a Maven artifact, which users of your framework can then use without having to include the dependencies yourself--your pom is enough.
If you want to create an "all-in-one" artifact, consider something like OneJar or jarjar or Maven's Shade plugin to create a jar that has no external dependencies.
The standard classloader can't find class files inside a jar that is itself inside a jar. You must add every jar to the classpath, and not nest jars.
BTW, it would probably be a bad idea to allow nesting jars: you would end up with 6 or seven versions of commons-lang or log4j into every project, because many libraries depend on them.
You can use One-jar or Fat Jar.
If you use maven you can use maven-assembly plugin.
Depends on IDE...If you are using Eclipse then it is very easy...go to Properties->Build Path and then add library...
Related
I am using Ant to build my project and deploy it to JBoss. Ant is building using jboss-home/server/default/lib jars. But during deployment it gives error:
java.lang.Error: Unresolved compilation problems:
The import org.apache.commons.lang3 cannot be resolved
StringUtils cannot be resolved
I am using commons-lang3-3.1.jar for StringUtils class by following Ant entry:
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar">
<include name="{jboss.home}/server/default/lib/commons-lang3-3.1.jar" />
Well, for me it seems like compilation error, but still I can suggest a few things.
Try to include 'missing' library into your aplication (for example, place it into web-inf/lib if it is war packaging or use descriptor - application.xml or jboss-app.xml) and see what will happen.
Check if your jboss is actually using the lib: the fact, that jar is located inside jboss directory, does not mean that it will be actually loaded. I don't know what version of jboss you are using, but for jboss as7 it is possible to disable any jar from modules via module.xml or via specific server configuration file (like, standalone.xml).
I've been searching for a possibility to generate ANT targets from top-level macro.
Details:
We have heterogenic build system. ANT+IVY is used as top-level (inherited solutin, can't be changed). Some projects are built via MSBuild, called from ANT via exec task. For each of these projects, there's at least two distinct calls to msbuild (wrapped with macro for brevity), one in "build" target, and one in "clean". Two of them are different only by "target" parameter. So I was guessing, if there's possibility for something like this:
Extension nodes:
<extensionpoint name="build-ext-point" />
<extensionpoint name="clean-ext-point" />
<target name="build" depends="build-ext-point" />
<target name="clean" depends="clean-ext-point" />
My magic macro:
<macrodef name="msbuild-proj" />
<attribute name="project" />
<sequential>
<target name="#{project}-build" >
<msbuild project="#{project}" target="Build" />
</target>
<target name="#{project}-clean" >
<msbuild project="#{project}" target="Clean" />
</target>
</sequential>
</macrodef>
How it would be used:
<msbuild-proj project="CPP-proj" />
Thanks!
P.S: Yeah I know that I can define those build and clean overridden, or via ext point, or whatever. The question is actually whether I can remove some code duplication.
UPD: I'd answer this by myself. At the point, there's no such possibility. Mainly, because Target class is a task container, but not a task. So, it cannot be placed into container. So I guess I'll write some kind of extensible task.
ANT has a couple of mechanisms for building modular builds.
First of all I think your main question was on how to build "extension points" to your build? The following ANT tasks are designed to import common build logic from another build file:
import
include
Since you're already planning to extend your build using macrodefs, I'd recommend packaging these as a reusable ANTlib. The ANTlib can live within your project, but it's really designed to be packaged within a jarfile which another build can pickup, for example by installing it in the standard ANT lib directory:
$ANT_HOME/lib
$HOME/.ant/lib
Finally, if you're already using ivy and you package your taskdefs as ANT libs, you could version your build logic by installing it in a Maven repository manager like Nexus. This addresses one of the key problems with large ANT builds. Over time they become so big it's impossible to change the common logic without impacting older builds (Demonstrating that the builds are not properly isolated from each other).
Actually done this.
Does its job, although some caveats are present.
For those interested: https://bitbucket.org/targetsan/ant-events
In project A's build file, there is a <path>;
In project B's build file, I want to execute a tool class in project A by <java> task.
The <java> task need to use that path in its "classpathref" property.
The <path> in project A's build file is quite complicated so that I don't want to copy it to project B's build file.
So is it possible to refer to a classpath defined in one build file from another build file?
Using the import or include ANT tasks is the way to do this.... however, these are both designed build multi-module builds. It's generally a really bad idea to couple two different projects in this manner....
I understand the motivation, classpath management is one of the most important and error-prone parts of a Java build. My recommendation is to adopt Apache ivy and let it manage your build's 3rd party dependencies.
Example:
The ivy cachepath task to create your ANT path, using dependency declarations.
<ivy:cachepath pathid="test.path">
<dependency org="org.slf4j" name="slf4j-simple" rev="1.6.4" conf="default"/>
<dependency org="junit" name="junit" rev="4.10" conf="default"/>
</ivy:cachepath>
The jars themselves can be locally stored or retrieved from the Maven Central repository
Ant allows to import a project file into another. You may check section 'Resolving files against the imported file' as this will be needed in most cases.
Do you have some predefined set of targets which all build.xml files you create contain?
For example, a lot of ant manuals suggest the following list of targets:
init
clean
compile
build
jar
test
javadoc
dist
deploy
webapp
What is the most large build file you met in your life? How many targets did it have and what are they? How often do you need more than predefined set of targets?
The goal is to develop some conventions to have standard buildfile template for any project having the notion of the maven-like approach in mind (when a lot of work happens under the cover, convention over configuration). Also it would be great if you know the place where one can find collection of different buildfiles to choose or to get inspired from.
I also use these targets in all ant files
init
clean
compile
build
test
javadoc
The build targets always creates the artefact, no matter whether it is a jar or war or whateveer.
You should also include structural things in your conventions like a shared repository for all libraries (versioned by some VCS).
Another thing would be to define properties for your jar versions i.g.:
lib.commons-collections=commons-collections-2.1.jar
lib.commons-io=commons-io-1.4.jar
which are referenced in all ant files, common.jar is a place where artifacts are placed in case other projects depend on them.
<path id="local-cp">
<pathelement path="${dir.common.jar}/${lib.shared}" />
<pathelement path="${dir.lib}/${lib.commons-logging}" />
<pathelement path="${dir.lib}/${lib.commons-io}" />
...
For deployment I use another set of ant files deploy_component-name.xml
After years with ant I would recommend to keep the number of targets limited, sometimes you may have a few more steps for code generation etc.
To see how others handle bigger projects you could download the source distribution of an application server to examine how they do this job.
int
build
jar
deploy
package
clean
test
I'm working with ant on linux using the command line. I've got a simple build step with javac. This compiles correctly but it creates a directory structure under build like my namespace.
ie: ./build/com/crosse/samplespace/SampleProgram.class
How can I get this output into one directory (where it's easier to call java on it).
I tried
<target name="output" depends="compile">
<copy todir="${output}">
<fileset dir="${build}" includes="**/*.class"/>
</copy>
</target>
but that repeats the same thing in my output directory. How can I use ant to get everything into a single directory?
Alternatively how could I use an ant step to copy another file into the root of that path (an apache commons configuration file)?
Edit: This is mainly a convenience factor, I get tired of navigating through the same 3 directories to run my program.
What about creating a jar file containing all your files (classes and other resources)?
A jar also has a 'default' class the main method of which gets executed when the user double clicks it or calls it using java -jar <jar-file>.
You can use the Ant jar task.
Beside that, it is important that you keep your directory structure (outside a jar), otherwise the java class loader won't be happy when it has to load these classes. Or did I get your question wrong?
To answer your question, you would use a flatten mapper, as carej points out. The copy task even has a shortcut for it:
<copy todir="${output}" flatten="yes">
<fileset dir="${build}" includes="**/*.class"/>
</copy>
However, I also don't understand what you hope to accomplish with this. The java runtime expects class files to be in a directory structure that mirrors the package structure. Copying the class files to the top-level directory won't work, unless the classes are in the default package (there is no package statement in the .java files).
If you want to avoid having to manually change directories, you can always add a target to your ant build file that calls the java task with the appropriate classpath and other parameters. For example:
<target name="run" depends="compile">
<java classname="com.crosse.samplespace.SampleProgram"
classpath=".:build"/>
</target>
You can accomplish what you want to do by using the flattenmapper but I'm at a loss to understand what possible valid reason you'd have for doing it.