Load java premain-class from jar library with ANT - java

Is it possible to load a premain-class from a jar library packed within a jar library? I'have the following setup:
Contets of my library:
# jar -tf myLibrary.jar
META-INF/
META-INF/MANIFEST.MF
agent/
agent/myAgent.jar
com/
com/package/
com/package/subpackage/
com/package/subpackage/A.class
com/package/subpackage/B.class
com/package/subpackage/C.class
Now within my MANIFEST.MF I would like to use something like:
Manifest-Version: 1.0
Premain-Class: com.agentpackage.AgentClass
Class-Path: agent/myAgent.jar
But unfortunately if I "use" this setup with -javaagent:myLibrary.jar it gives me the following error message:
java.lang.ClassNotFoundException: com.agentpackage.AgentClass
FATAL ERROR in native method: processing of -javaagent failed
Is it somehow possible to access a premain-class within a .jar file?
My (truncated) ANT build file for myLibrary.jar:
<jar destfile="myLibrary.jar" update="true">
<zipfileset dir="lib" includes="myAgent.jar" prefix="agent" />
<manifest>
<attribute name="Class-Path" value="agent/myAgent.jar" />
<attribute name="Premain-Class" value="com.agentpackage.AgentClass" />
</manifest>
</jar>
I know I could do the following:
<jar destfile="myLibrary.jar" update="true">
<zipgroupfileset dir="lib" includes="myAgent.jar" />
<manifest>
<attribute name="Premain-Class" value="com.agentpackage.AgentClass" />
</manifest>
</jar>
But then the contents of myAgent.jar gets inflated within myLibrary.jar and thats not what I want. Thanks for any help.

Java doesn't support loading nested jars.
You'll have to use inflated version or place these two jars in the same folder and update classpath correspondingly.

Related

How can I use Ant to build a single executable .jar that has dependency .jars in it in a /lib dir in the .jar?

How can I use Ant to build a single executable .jar that has dependency .jars in it in a /lib dir in the .jar?
I have a /lib directory in the project root file that contains all the binary dependency .jars.
In java an executable jar has a specially formatted manifest, that includes the following attributes:
Main-Class
Class-Path
In ANT this is easily accomplished as follows with the jar task:
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" includes="*.class">
<manifest>
<attribute name="Main-Class" value="${main-class}" />
<attribute name="Class-Path" value="${jar-classpath}" />
</manifest>
</jar>
For extra credit one can use the very useful manifestclasspath task to help assemble the correct classpath string.
<manifestclasspath property="jar-classpath" jarfile="${jar.dir}/${ant.project.name}.jar">
<classpath>
<fileset dir="/path/to/lib/dir" includes="*.jar"/>
</classpath>
</manifestclasspath>

Issue with class-path in manifest file during deployment in Tomcat

I am building the java project using Ant and I am using Ivy for the dependency management. There are two options in ant build for resolving the dependencies during the deployment. One is the lib mode, if this mode is enabled, all the dependent jars will be downloaded into project's WEB-INF/lib folder. Other is manifest mode which does not download any jar. During deployment, MANIFEST.MF (which has the class-paths to all the dependent jars) file will be used for resolving the jars.
Project is running properly when it is in lib mode, but when manifest is enabled, the build is successful but the deployment fails.
Please tell me how to fix this or what could be the reasons for this?
Note: Tomcat server is VWL enabled by default.
Thanks in advance.
Without an example one must speculate what your code looks like. The following example demonstrates the use of the ANT manifestclasspath task to construct a classpath suitable for a jar manifest file. The ivy "retrieve" task populates a relative direcotory containing the jars:
<target name="build" depends="compile">
<ivy:retrieve pattern="${dist.dir}/lib/[artifact].[ext]"/>
<manifestclasspath property="jar.classpath" jarfile="${dist.jar}">
<classpath>
<fileset dir="${dist.dir}/lib" includes="*.jar"/>
</classpath>
</manifestclasspath>
<jar destfile="${dist.jar}" basedir="${build.dir}/classes">
<manifest>
<attribute name="Main-Class" value="${dist.main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</jar>
</target>
The following is a detailed example:
How to avoid copying dependencies with Ivy

How to set classpath order while building jar file using Ant?

I am using zipgroupfileset to bundle all jars from lib folder to include in my executable application jar file.
<zipgroupfileset dir="${lib.dir}" />
Jars must be getting included in some default order. I want to alter this default order.
A note on why I want this: my Java desktop application uses many third party jars which are included in class path. When I run my code through Eclipse it works fine. But when I build the jar file using ANT it doesn't work as expected. I am sure it is related to jar sequence in classpath as if I change jar order in Eclipse it fails there as well.
Note: I am using Eclipse Kepler, Java 7, Ant 1.8.
Finally I got the solution. I build the Jar after altering my ANT file. Now my ANT build includes 3rd party APIs explicitly in classpath and that was the key to the solution.
<property name="lib.dir" value="lib" />
<manifestclasspath property="jar.classpath" jarfile="${lib.dir}/*.jar">
<classpath refid="project.class.path"/>
</manifestclasspath>
<jar destfile="${jar.dir}/${jar.name}">
<fileset dir="${class.root}" includes="**/*.*" />
<manifest>
<attribute name="Main-Class" value="${Main-Class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
Previously I had class-path entry in ANT as follows:
<attribute name="Class-Path" value="." />

How to a jar file include another jar via Ant?

I have 'test.jar' . I want to create 'my.jar' . I want my.jar include test.jar
My code:
<target name="jar" >
<copy file="${conf.dir}/default.xml" todir="${build.classes}" />
<jar jarfile="${build.dir}/test.jar" basedir="${build.classes}">
<manifest>
</manifest>
</jar>
</target>
<target name="services-jar">
<jar jarfile="${build.dir}/my.jar">
<manifest>
<attribute name="Main-Class" value="mypackage.MyClass" />
<attribute name="Class-Path" value="${build.dir}/test.jar" />
</manifest>
</jar>
</target>
If I run 'my.jar' : java -jar my.jar
display message: Could not find or load main class mypackage.MyClass
My MANIFEST.MF file:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.4
Created-By: 1.7.0_17-b02 (Oracle Corporation)
Main-Class: mypackage.MyClass
Class-Path: ./build/test.jar
Any idea?
The paths in the manifest Class-Path need to be relative to the location of the JAR file that contains the manifest. Since both my.jar and test.jar are in the same directory (${build.dir}) the relative path is simply test.jar, i.e. you need
<jar jarfile="${build.dir}/my.jar">
<manifest>
<attribute name="Main-Class" value="mypackage.MyClass" />
<attribute name="Class-Path" value="test.jar" />
</manifest>
</jar>
More generally, you may wish to look up the <manifestclasspath> task which, given the location of the target JAR file and a set of other JARs that you want to put on the Class-Path, calculates all the relative paths for you and generates the correct value for the manifest attribute.
You are mixing separators. Replace your"${build.dir}\test.jar" with "${build.dir}/test.jar".

Error while creating consolidated jar file - no manifiest section for signature file entry javax/mail/internet/ContentDisposition.class

I have some jar files into /libs/ and my project classes are located at /target/. To remove dependency on external folder. I want to make a consolidate jar file. Which contains all the classes from jar files found in all /libs/*.jar
I am using following Ant script:
<jar destfile="mytest.jar" basedir="target/classes">
<manifest>
<attribute name="Main-Class" value="com.mytest.MyProcessor"/>
</manifest>
<fileset dir="target/classes" includes="**/*.class"/>
<zipgroupfileset dir="libs" includes="*.jar"/>
</jar>
But, when I run the jar using "java -jar mytest.jar" command, it says:
Exception in thread "main" java.lang.SecurityException: no manifiest section for signature file entry javax/mail/internet/ContentDisposition.class
at sun.security.util.SignatureFileVerifier.verifySection(Unknown Source)
at sun.security.util.SignatureFileVerifier.processImpl(Unknown Source)
Any idea, how to make a consolidated jar that have no such issues, would be highly appreciated. I am using IntelliJ IDEA.
Exception in thread "main" java.lang.SecurityException: no manifiest section for signature file entry
This error message tells exactly why bundled jar is not recommended for production release. The problem is some of your dependency jar is signed with signature files. repack it may violate some security policy on the dependency jar.
To make it work, you need remove all signature files from the signed jar, before copying the unpacked files into your final build jar file. Note that <zipgroupfileset> doesn't support exclude file within jar archive, try using a list of <zipfileset> instead:
<zipfileset src="libs/mail.jar">
<exclude name="**/*.RSA, **/*.SF, **/*.DSA"/>
</zipfileset>
... ...
Something like this might work for you.
<jar destfile="mytest.jar" basedir="target/classes">
<restrict>
<not>
<or>
<name name="**/*.RSA"/>
<name name="**/*.SF"/>
<name name="**/*.DSA"/>
</or>
</not>
<archives>
<zips>
<fileset dir="libs" includes="**/*.jar"/>
</zips>
</archives>
</restrict>
<manifest>
<attribute name="Main-Class" value="com.mytest.MyProcessor"/>
</manifest>
</jar>
I adapted this from the example at http://ant.apache.org/manual/Tasks/jar.html under the "Merging archives" section.
Use Maven and the shade plugin. Have a look at http://maven.apache.org/plugins/maven-shade-plugin/
I would suggest to unjar all your jar files into a lib folder and then jar together with your your source code, try it might work for you.

Categories