Omitting base directories when JARing multiple selective files - java

I have the following directorie structure:
base\
dir1\
dir11\
RequiredFile.class
NonRequiredFile.class
dir12\
AnotherRequiredFile.class
AnotherNonRequiredFile.class
As part of a makefile actions, I would like to archive RequiredFile.class and AnotherRequiredFile.class in the same JAR file, and omit the base/dir directories. The final output should be a single JAR file so that unpacking the JAR file would create the following structure:
dir11\
RequiredFile.class
dir12\
AnotherRequiredFile.class
I know that this can be done using -C flag in the bin/jar command, but it reuqires me to add -C dir1 before each one of the input file. The above example only contains two, but later there would be more and i wold like to avoid commands such as jar -C dir FILE -C dir FILE2 -C dir FILE3 ..... -C dir FILEn
Is there a way to use the -C flag for all input files?
Thanks

Assuming you have all your class files filenames in a Makefile variable already. Provided you are using gnu make, you can then use the patsubst function to achieve that:
CLASSFILES := RequiredFile.class AnotherRequiredFile.class
DIR := dir1
JAR_CMD = $(patsubst %.class, -C $(DIR) %.class, $(CLASSFILES))

Related

How to create tar file which contains only file

I have a file in /tmp/a.crt I will have to make a.tgz which contains a.crt not tmp/a.crt. As i am running tar command through java I can't navigate to /tmp and execute tar -cvf a.tgz a.crt
If i run tar -cvf a.tgz /tmp/a.crt it creates a a.tgz which contains tmp/a.crt .
I tried tar --exclude='/tmp' -cvf a.tgz /tmp/a.crt but while untaring it says
gzip: stdin: not in gzip format
tar: Child returned status 1
Is there any way to achieve my requirement.
If you want to create a compressed tar file (.tgz or .tar.gz), you have to use the option z. Otherwise you have only an uncompressed tar file (.tar). You probably omitted this option during creation.
Here is a Bash session demonstrating what you want (as I understand it):
# first, create test files
$ mkdir tmp
$ touch tmp/a.crt
$ find .
.
./tmp
./tmp/a.crt
# use "-C" to keep the filename out of the archive
$ tar -C tmp -czvf a.tgz a.crt
a.crt
# confirm results
$ tar tf a.tgz
a.crt
As you can see, in the final a.tgz file, there is no tmp/ directory present.
This is generally a bad idea, creating what is sometimes called a "tar bomb" (link). But presumably you have a good reason for it (:

Extract several of jar in one command

I have folders with lots (20) of jar files. Is there a way to extract all those jars in one command in the terminal instead doing it one by one?
I'm using a MAC.
A simple solution.- Get all the jars and extract it
find ./ -name "*.jar" -exec jar -xf {} \;
You can use this from the folder in which all your jars are -
jar {ctxu}[vfm0Mi] [jar-file] [manifest-file] [-C dir]
Options:
-c create new archive
-t list table of contents for archive
-x extract named (or all) files from archive
-u update existing archive
-v generate verbose output on standard output
-f specify archive file name
-m include manifest information from specified manifest file
-0 store only; use no ZIP compression
-M do not create a manifest file for the entries
-i generate index information for the specified jar files
-C change to the specified directory and include the following file
refer the documentation for explaination - http://docs.oracle.com/javase/tutorial/deployment/jar/unpack.html
you may user *.jar in place of jar-file to extract all
This should extract in same location where the jars are present.
jar xvf *.jar

Batch Deleting Files While Performing a Copy/Merge

I have 2 files, "launcher.jar" and "camStudio.jar" that I need merged. I decided to try to do this using batch with the code:
copy /b launcher.jar + camStudio.jar file.jar
However, the resulting "file.jar" only contains the contents of "camStudio.jar". How can I prevent the files in "launcher.jar" from being deleted?
Combining the contents of two .jar files is a little more complicated than just calling copy from the command line. Rather than a normal directory, .jar files are a type of compressed file, so you need special utilities to manipulate them. Fortunately these tools come with the standard JKD.
The JDK comes with the utility jar that is unsurprisingly used for manipulating .jar files. It's usage is described as this:
Usage: jar {ctxui}[vfmn0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
Options:
-c create new archive
-t list table of contents for archive
-x extract named (or all) files from archive
-u update existing archive
-v generate verbose output on standard output
-f specify archive file name
-m include manifest information from specified manifest file
-n perform Pack200 normalization after creating a new archive
-e specify application entry point for stand-alone application
bundled into an executable jar file
-0 store only; use no ZIP compression
-M do not create a manifest file for the entries
-i generate index information for the specified jar files
-C change to the specified directory and include the following file
If any file is a directory then it is processed recursively.
The manifest file name, the archive file name and the entry point name are
specified in the same order as the 'm', 'f' and 'e' flags.
Example 1: to archive two class files into an archive called classes.jar:
jar cvf classes.jar Foo.class Bar.class
Example 2: use an existing manifest file 'mymanifest' and archive all the
files in the foo/ directory into 'classes.jar':
jar cvfm classes.jar mymanifest -C foo/ .
Relevant commands for combining two .jar files are x and c. Even with this, combining the .jar files takes more than a line or two, so I put together this .bat files to automate it.
:: Pass one or more .jar files as command line arguments
:: Combine_Jar [file1] [file2 ...]
:: Combine_Jar Test.jar
:: Combine_Jar Test.jar Test2.jar Test3.jar
#echo off & setlocal enabledelayedexpansion
set "jarDir=%cd%"
set "newJar="
set "folders="
pushd %temp%
for %%a in (%*) do (
call :extract %%a
set "newJar=!newJar!_%%~na_"
)
set "tempDirs=!newJar:_=^"!"
set "tempDirs=%tempDirs:^"^"=^" ^"%"
set "newJar=!newJar:~1,-1!.jar"
set "newJar=!newJar:__=_!"
if exist "!newJar!" del /Q "!newJar!"
jar cf "!newJar!" %tempDirs%
for %%a in (%*) do call rd /s /q "%%~na"
move /Y "!newJar!" "%jarDir%" > nul
popd
exit /B
:extract
set "tempDir=%~n1"
if exist "%tempDir%" (
rd /s /q "%tempDir%"
)
md "%tempDir%"
pushd "%tempDir%"
jar xf "%jarDir%\%~1"
popd
exit /B
It will all jar files passed as arguments into a single jar files.

How do I link jar packages together with *.java files during compilation using GCJ?

I have the following files:
A.jar (containing *.class files)
B.jar (containing *.class files)
Program.java (containing Program class with main function, which depends on A.jar and B.jar)
How can I build an executable file Program using GCJ?
It's been a while since I played around with Java so the following are mostly off the top of my head.
In linux usually a java program is launched by a wrapper script. For your case this wrapper script can be the Program, the content:
#!/bin/sh
java -cp A.jar:B.jar:/path/to/dir/where/Program.class/is/in Program
If you prefer to have only a single jar file then you can "unjar" A.jar and B.jar and create a new jar, say Program.jar that contain all the classes from A.jar, B.jar and your Program.class, and you create a little manifest file that tells which class is to be run when you execute the jar file (in this case it's your Program.class).
The content of the manifest file (let's call it manifest.txt):
-----8<------
Main-Class: Program
----->8------
Note the blank line after the "Main-Class: Program" line - it's needed.
So the create the single Program.jar:
gcj --classpath A.jar:B.jar Program.java
mkdir tmp
cd tmp
jar xf ../A.jar
jar xf ../B.jar
cp ../Program.class .
jar cmf ../manifest.txt ../Program.jar .
cd ..
Now create the shell script wrapper Program:
#!/bin/sh
java -jar /path/to/Program.jar
Make it executable:
chmod +x Program
and run it:
./Program
Applause if it works, throw rotten tomatoes otherwise!
This works for me:
gcj -c A.jar -o A.o
gcj -c B.jar -o B.o
gcj --main=Program --classpath=A.jar:B.jar -o Program A.o B.o Program.java

Comparing two .jar files

How do I compare two .jar files?
Both of them have compiled .class files.
I want the difference in terms of method changes, etc.
JAPICC, sample usage:
japi-compliance-checker OLD.jar NEW.jar
Sample reports for log4j: http://abi-laboratory.pro/java/tracker/timeline/log4j/
PkgDiff, sample usage:
pkgdiff OLD.jar NEW.jar
See sample report for args4j.
Clirr, sample usage:
java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jar
If you select two files in IntellijIdea and press Ctrl + Dthen it will show you the diff. I use Ultimate and don't know if it will work with Community edition.
Rename .jar to .zip
Extract
Decompile class files with jad
Recursive diff
Extract each jar to it's own directory using the jar command with parameters xvf. i.e. jar xvf myjar.jar for each jar.
Then, use the UNIX command diff to compare the two directories. This will show the differences in the directories. You can use diff -r dir1 dir2 two recurse and show the differences in text files in each directory(.xml, .properties, etc).
This will also show if binary class files differ. To actually compare the class files you will have to decompile them as noted by others.
Create a folder and create another 2 folders inside it like old and new. add relevant jar files to the folders. then open the first folder using IntelliJ. after that click whatever 2 files do you want to compare and right-click and click compare archives.
I use to ZipDiff lib (have both Java and ant API).
Here is my script to do the process described by sje397:
#!/bin/sh
# Needed if running on Windows
FIND="/usr/bin/find"
DIFF="diff -r"
# Extract the jar (war or ear)
JAR_FILE1=$1
JAR_FILE2=$2
JAR_DIR=${PWD} # to assign to a variable
TEMP_DIR=$(mktemp -d)
echo "Extracting jars in $TEMP_DIR"
EXT_DIR1="${TEMP_DIR}/${JAR_FILE1%.*}"
EXT_DIR2="${TEMP_DIR}/${JAR_FILE2%.*}"
mkdir ${EXT_DIR1}
cd ${EXT_DIR1}
jar xf ${JAR_DIR}/${JAR_FILE1}
jad -d . -o -t2 -safe -space -b -ff -s java -r **/*.class
cd ..
mkdir ${EXT_DIR2}
cd ${EXT_DIR2}
jar xf ${JAR_DIR}/${JAR_FILE2}
jad -d . -o -t2 -safe -space -b -ff -s java -r **/*.class
cd ..
# remove class files so the diff is clean
${FIND} ${TEMP_DIR} -name '*.class' | xargs rm
# diff recursively
${DIFF} ${EXT_DIR1} ${EXT_DIR2}
I can run it on Windows using GIT for Windows. Just open a command prompt. Run bash and then execute the script from there.
Use Java Decompiler to turn the jar file into source code file, and then use WinMerge to perform comparison.
You should consult the copyright holder of the source code, to see whether it is OK to do so.
In Linux/CygWin a handy script I use at times is:
#Extract the jar (war or ear)
cd dir1
jar xvf jar-file1
for i in `ls *.class`
do
javap $i > ${i}.txt #list the functions/variables etc
done
cd dir2
jar xvf jar-file2
for i in `ls *.class`
do
javap $i > ${i}.txt #list the functions/variables etc
done
diff -r dir1 dir2 #diff recursively
If you are using IntelliJ IDEA or Android Studio, add your jar files to a project under the libs folder.
Then select the both jar files, right click then select "Compare Archives"
use java decompiler and decompile all the .class files and save all files as project structure .
then use meld diff viewer and compare as folders ..
Here's an aparently free tool http://www.extradata.com/products/jarc/
Please try http://www.osjava.org/jardiff/ - tool is old and the dependency list is large. From the docs, it looks like worth trying.
This application may be what you need, works great and display a simple GUI showing differences. Try Jarcomp

Categories