How to detect duplicate JARs in the classpath? - java

Does anyone have code to detect duplicate JARs in the classpath?
Background: When there are two versions of the same JAR in the classpath, really strange things can happen. This can even happen when using tools like Maven: Change a dependency and build the WAR without cleaning first. Since target/webapp/WEB-INF/lib wasn't cleaned, the dependency will be in there twice.
Is there a safety-net for this?

JBoss Tattletale might help you with this.
It's a free tool which scans the JAR files used by your project and gives you a report about them.
Amongst its feature are:
Spot if a class is located in multiple JAR files
Spot if the same JAR file is located in multiple locations
Find similar JAR files that have different version numbers

There is a Maven plugin to do just that: maven-duplicate-finder-plugin
[EDIT] If you want to do it in unit tests yourself, use
getClass().getClassLoader().getResources( "com/pany/package/Java.class" )
If this returns more than one URL, you have duplicates on the classpath.
The drawback is that this only works for cases where you had conflicts in the past. On the positive side, it's just a few lines of code (or one line when you write a helper method) and it works on your build server.

System.getProperty("java.class.path"), split it, sort it, look at it with the human eye
:-).
It will not include the classpath derived from manifests inside other jars thou :-(.
Or use http://www.jboss.org/tattletale as one of the posters suggested.

I think the simplest way is to simply trash the target directory first. Hopefully copying all the .jar files in isn't going to be time-consuming.
Otherwise you're going to have to somehow compare sizable files (whether directly, via computed checksum or similar). Which doesn't sound very nice at all.

You can write a simple script to compare the md5 sum of every jar file to every other jar file and deleting duplicates along the way.

Related

My jar resource files in intellij are read only and I need to edit them

I have tried unsuccessfully for a few hours now to edit the java files in a jar I am using as a library. I have marked the resource as a content root and as a source root but I am still unable to edit the code in the jars. The project compiles and runs correctly but I need to make an adjustment to a resource file and cannot; I have tried every project structure I could think of. Is it just impossible? All help is appreciated.
It is not recommended to edit JAR files. From the perspective of reproducibility1, it is better to:
Get hold of the source tree for the library
Check it into your version control (or fork it on Github)
Modify and build it
Use the resulting JAR instead of the original JAR
Another approach is to "overlay" the changes you want to make by creating a another JAR with the alternative version of the resources and placing it earlier in the application classpath.
But if neither of those works for you, you can use the jar command from the command line to modify a JAR file:
Use jar -x ... to extract the files to a temporary directory tree
Apply what ever changes need to be made to the tree
Use jar -c .... to create a new JAR from the tree.
Read the manual entry for the jar command for more details. Signing the new JAR with the original keys would be an issue if you are not the original signer, but I doubt that that is relevant to you.
1 - The point is that the next guy maintaining your code needs to know what you did to the library JAR that you "edited", in case he needs to do the same procedure with another version of the JAR. If you do it by hand, he has no choice but to do a forensic comparison of the differences between the original and your edited version. And that assumes that the original JAR can still be obtained. Note that "the next guy" could be you ... in a couple of months or years time, when you have forgotten exactly what you did.

How to share common files between several projects in Java

Suppose that I have a common directory that contains general-purpose files like FileUtils.java and ImageUtils.java. Also I have two projects that should use these common files. What is the most Java-way to import them into these projects? Just add path manually to the -classpath option when using javac and java? Build them into one jar file? Or something else?
Just follow simple steps:
1.) Have module say, companyname-commons-util
2.) build to a jar file, companyname-commons-util.jar
3.) Add dependency of this jar into other projects, and just reuse the classes. (maybe maven, gradle or explicitly adding into classpath)
** The same can be reused in other projects as well. Good from maintenance point of view, and keeping project structure intact.
The recommendation would be to create a third project and then use that to generate a JAR file; you can then use that reference in your other projects. If you're using Maven to build them you'd end up with a different module with your common code in place.
Besides the things that have been said; a word of warning: try to slice your projects aka components to be as small as possible.
In other words: before just blindly going forward and pushing all content of your "common" folder into its own project it might be worthwhile to step back and carefully look at
a) the contents of common
b) how other projects make use of that source
And theoretically, you match that whole picture with the thing that is called "architecture" (which may or may not exist for your overall "product") to understand where "reality differs from as-it-should-be".
Then, finally, you define one or more projects that cover all (or parts of) your source code in "common"; and then you change your whole infrastructure so that other "dependent" projects do not rely on using your "common" source files but some kind of build artifact.

Eclipse - checking that all libraries are imported

I have a project that uses a lot of external libraries (mostly .jar files). I am using Eclipse Helios Service Release 2.
When something doesn't work, the problem is usually caused by missing jars or some problem with classpath. What I have to do, is to check that all necessary jars are correctly included in my classpath.
The problem is that I have several libraries imported + external jars (in case of libraries, the classpath only points to the directory with the jars) and Eclipse provides no easy way to search for included jars. If there was any kind of function that would work like this: "search for xyz.jar" and find if the jar with given name is already included somewhere, instead of manually controlling this, it would be a great help.
It would also help if Eclipse provided a function to sort all the jars and libraries by name instead of displaying them in the same order they are specified in path (I mean only in the project manager, of course).
So my question: is there an easy way to check these things or do I have to do that manually? I have cca 30 jars to include and cca 300 already there and this is a real pain...
You could use a build environment, such as Maven, to manage your dependencies for you. Then Eclipse does zero thinking on its own and your life becomes far more pleasant (particularly when the time comes to package your code for release).
I couldn't imagine managing 300+ dependencies any other way.

classpath issue with jar files

I'm having a classpath issue with commons-httpclient.jar.
The application uses a newer version of the commons-httpclient.jar, which is commons-httpclient-3.0.1.jar.
Once JBOSS is installed it installs the original version named commons-httpclient.jar in two different directories.
/opt/appname/lib and /opt/appname/server/default/lib
It would be easy to simply remove them, but it turns out that they are being used by another application on the system. I would like to know if there is any way to designate an order to which classes are used, for example.
Use commons-httpclient-3.0.1.jar first then use commons-httpclient.jar
Fairly new to Java, so any help would be appreciated.
I believe the only way to do this under the constraints you mention is to move the right JAR into the server/default/lib folders of each of the apps on your JBoss, and remove it from /opt/appname/lib.
That said, this may still be problematic, as JBoss itself may also need the JAR. In that case, you may be out of luck.
As a side note, you can create a folder /jboss/lib/endorsed. Libs placed there take precedence over those is jboss/lib.

Easiest way to manage my CLASSPATH?

I'm beginning to play with Clojure a bit and my Java experience is pretty limited. I'm coming from the dynamic world of Ruby and OO, so the functional side of things is very interesting!
Anyway, as I discover libraries and various tools for use (and the tutorial files for the Pragmatic Clojure Book), everything typically calls for placing files in the CLASSPATH in order for Clojure to see the library for use.
Is there such thing as good CLASSPATH practice? Would I ever want to only have a CLASSPATH with just the external libraries of files I need or can I go ahead toss any library or file I would ever need in a directory and simply define it as my CLASSPATH and only require what's needed?
If it helps, I'm an OSX and Emacs user (Using slime and swank-clojure).
I recommend using leiningen and lein-swank to manage this. You can start a REPL in the directory and connect to it from Emacs.
Personally, I'm using a variant of a clojure-project elisp function by Phil Hagelberg, see source in this post to the Clojure group. It sets up the classpath appropriately for the project you'll be working on, then launches SLIME. (EDIT: You'll need to change the value which gets assigned to swank-clojure-jar-path to point to clojure.jar. I'm using (expand-file-name "~/.clojure/clojure.jar") as the default.)
To answer the question about having everything on the classpath all the time vs only throwing in what's needed: to the best of my knowledge, nothing will actually break if you take the first approach (I know I do that for experimental purposes), but apparently things might break with the first approach (see cjstehno's comment below) and in a proper project I find the second to be cleaner. At some point it'll be necessary to determine what libs are being used (and which versions of them), if only to tell leiningen (or maven) about it -- why not keep tabs on it as you go.
We are using Clojure and use a number of infrastructure tools, especially Eclipse (IDE) (http://en.wikipedia.org/wiki/Eclipse_%28software%29) and maven (http://en.wikipedia.org/wiki/Apache_Maven). maven manages libraries and jar dependencies so if you have a number of these and they are likely to grow start using maven.
In answer to your original question you can just put your jars in one directory and you can access them by name every time you run. But you will benefit from the tools...
If you are just exploring then Eclipse will probably manage your jar files fairly painlessly. You can add these to the project as required through the Build Path -> Configure Build Path option.
As your work progresses you will possibly wish to split it into Projects which Eclipse supports so you can add your (or other projects) to your Build Path.
If you use external Clojure libraries look to see if they have been packaged as maven projects (they will have a pom.xml file). The POM will give a list of dependencies.
#
The usual CLASSPATH practice for Java is to put only the jar files needed for a project into this projects class path, which means to have potentially different class paths for diffent projects. This is usually managed by the IDE as part of it's project properties.
Since you are using Emacs and thus probably don't have or use something like projects it might be more convinient for you to set up and use a single global class path for all your clojure related stuff or maybe even simply put all the needed jar files into the java2se/jre/lib/ext directory of your java installation.
The two main problems that could arise from having unneded jar files in your class path are: 1. it has a minor negative impact on the start up time of the JVM and 2. it becomes more difficult to make sure that you are not having classes with different versions in the same class path (i.e. different classes with the same package and name in different jar files).
Since Java SE 1.6 (or JDK 1.6) you can include class path entries by wildcard. If your class files live in .\bin, and your library jar files live in .\lib, then on Windows you could define your class path like this:
set CLASSPATH=bin;lib\*;
This will let you add jar files into the .\lib directory and they will automatically be added to the class path for new instances of the JRE.
See this link for details: Setting the class path
Prior to JDK 1.6 you had to add each jar file onto the ClassPath individually.
I just discovered this bit which I need to give a shot:
(setq swank-clojure-extra-classpaths (list "/class/path/1" "/class/path/2" "/class/path/3" "etc"))
clojure-contrib/launchers/bash/clj-env-dir has an interesting property that you can point it at a directory and it will basically include anything in there. In the past I've had a ~/classpath directory which I would dump any jars into and link any commonly used directories and it worked great. Very simple way to dump and use. Now I tend to use Maven clojure-maven-plugin and that works well also though can be a bit tedious when you just want to muck around with some ideas.

Categories

Resources