I am currently working on an application which is around a decade old. When I looked in to the jar files which are associated with the application , I can see lots of jars which are not required and lots of different versions of same jar.
What are the cons of having unwanted jars in lib. What is the easy way to find and remove them?
You might get problems if a class loader decides to load classes from different version of jar file than you expect. These kind of problems are usually hard to track. Server will look through jars in some specific order (alphabetically by filename?) and use the first matching class/resource it finds. There are probably no guaranties that the newest version of a jar file is looked first.
I do not know of any tools that would find out which jars are unused. That may be impossible in general case due to reflection, but some degree of automatic checking should be possible, at least in theory.
Removing unused jar file by trial and error is problematic if you do not have good unit tests, which I doubt you have in your decades old application. There may always be some rare error case that depends on just the old jar version you just removed.
My suggestion is that if your applications are working, leave the jars as they are now. It will be very troublesome if not impossible to find out, which jar files are actually picked up by the class loader. (Of course do not deploy new applications).
You can find which packages a jar file contains by using JarAnalyzer. This will give you an idea of duplicates and you can start removing older versions of jar files. However this procedure needs to be done by hand and by trial and error. Also, the same package may be contained in two jars with different names and no versioning information.
As already said having different versions of the same jar could bring havoc. You can't know which version will actually be used and what conflicts it will bring to this or another application. That's why you should never use Tomcat's shared folder for applications jars. If you are in a situation, where many jar files are placed in the shared folder, avoid using this server for new applications.
By unwanted jar files in your application, do you mean that these are generated as part of your compile and build process every time? If so, then it might be the build scripts that you want to clean up.
If you are referring to the actual deployment environment, then any cleanup must be done very carefully. Why not try starting over in a fresh test environment with a clean tomcat installation and the latest build's executables deployed? See if it runs well on just that, and if it does, then maybe the extra jars are indeed unnecessary.
As for the cons, I don't see any aside from the filesize of your deployment.
How can you decide which of the jars are not being actually used?
I would suggest making this a full QA-needing change. You have no idea if the code chosen from the set of jars shadow an erroneous implementation surfacing if you remove an "obsolete" jar.
Related
Let's imagine, I created a bunch of command line utilities, written in Scala and/or Java, and I'm using SBT to build them. They all use a couple of libraries, some of them pretty big, and in case of Scala, also the (not so small) Scala standard library.
I want to have these utilities in completely built form (runnable .jar files) to be able to instantly launch any of them and, if needed, also easily distribute them. But what I don't want is to include their dependencies in all of them, because they will be taking disk space. Instead I want them to get dependencies from a shared folder at runtime, and the application jar should contain only "my" classes.
The question is, is there a standard way to accomplish this? If so, where must be shared .jars located? Otherwise, what would you recommend to do?
You can set the CLASSPATH for this.
The JRE searched for classes in the .jar files named in the CLASSPATH.
Additionally all .jar files in the directory jre/lib/ext are used.
To find the complete serching in classpathes please consult the official documentation from Oracle.
Something you might like to consider (although it will require slightly changing what you plan to do) is to have a local Maven repository.
You could have SBT publish libraries to it when they're built. Instead of building runnable JARs, you could run your applications via SBT, which would pull libraries from the local repository as/when required.
The benefit of this is that all the plumbing to do this is built into SBT, and it would make distribution trivial.
The downside is that you would have to run your apps via SBT instead of building runnable JARs. Whether that will work for you, I don't know.
I'm working in a Web Project on Java using Eclipse.
This project will be deployed, at least, as "Develop" and "Testing" in two different WARs.
The project is working fine.
But when I Exported as a WAR file, each WAR have inside a copy of the libraries used (Spring JARs, Quartz JARs, Hibernate JARs, etc).
So I'm repeating the JARs on each implementation.
So the Idea of my Boss is remove the JARs from the web project and:
Option 1: Copy all the libraries to a windows folder and then reference with a "Relative Path".
Option 2: Put the JARs on Java JRE/JDK lib folder and the reference the JARs in some way.
Also with this change, we are trying to solve a PermGem Exception
What it is the best Idea?
I'm new with Java project, so I don't know how to do that.
Thanks for yours answers and sorry for my poor english
IMO the best idea is to bundle them with your application.
If for no other reason, this allows you to upgrade a library in one version without affecting the others.
I feel your current approach is better, having jars packed with each war. As #Dave said, if you put them to a common place it will have dependency problems.
Also both of your options will not solve PermGen error, to solve that as a temporary measure try to increase PermGen memory using -XX:MaxPermSize JVM argument, even after this if you still get the out of memory error then you need to dig out where the memory leak is.
i am setting up a java project now. in the past, we always included everything (unzipped) from the 3rdparty, such as ant, junit, jfreechart, and others, inside our release. I am wondering is it possible just take those related .jar files but not everything with our software release? then we can get a smaller and neat release. Those 3rdparty library licenses don't allow us to do that way? what's your way? thanks,
You really want to retain the separate jars, if possible. Check out the maven appassembler plugin. It does a nice job of putting together an "unzippable" installation for you, in a controlled way. In the result you'll have a very straightforward "repo" directory filled with all of your dependencies.
I use the maven-assembly-plugin to build a single jar for each application. The plugin quickly handles the fuss of unzipping all the library jars and putting the whole lot back together as a single jar. It also supports writing a manifest with a main class specified which makes running the application simple from a command line (much simpler than specifying a classpath argument as long as your arm anyway).
If their licenses say that you should distribute derivatives with sources, then you are obliged to do that by law.
Another question is if they really force that. As far as I remember GPL, you shall distribute the sources if you want, but there is another way - you must make sources easily availiable to users. So you can drop sources in your distributables.
Any way, you should look at the licenses.
EDIT:
If you will decide to pack the whole program into single jar, I recommend Proguard. It is java optimiser, shrinker, and much more - all in one! To pack everything into one jar, just specify all your jars - program and libraries - as program jars, and specify only one jar as output. Usually it works just fine.
I am a brand new Java developer (I have been working in asp.net) and I inherited a project I am trying to get running correctly. I am on Windows 7 and have Tomcat installed and I am using Eclipse
I'm trying to figure out how the heck Jar's work in java and I am really confused at the moment. I have been playing around with it and looking up stuff on the web for about a day now and this is where I am:
I have a dynamic web project which I inherited and it has what I am going to assume is a fairly standard project layout. There is a lib folder in the project root which contains some jar's.
If I don't do anything and go to a particular page in the site I get this error: "The import net.sf cannot be resolved, XLSTransformer cannot be resolved to a type"
So I added jxls-core-0.9.8.jar to my build path in Eclipse and that error went away but now I am getting this error "java.lang.ClassNotFoundException: net.sf.jxls.transformer.XLSTransformer"
I copied that jar from its current location to the tomcat/lib directory and that error went away. Now I am getting essentially the same issue with another file.
Mainly I just need to know how should jar's work? Do they need to be in the class path, in web/WEB-INF/lib, in tomcat/lib, in all of them, none of them I just can't figure it out.
Also when I was looking around I saw some stuff that indicated the order of my classpath entries matters as well. If that is the case how do you insure you have them in the correct order.
Where your jars need to go actually depends - there are entire best practices and major headaches involved. The term Jar Hell exists for a reason.
All classes used by your application must be on the classpath. How they get there will vary depending on the classloader.
For a fuller understanding, you'll want to do reading on the Java classloader. Ideally you'll want to look into Tomcat's classloader, or at least a Servlet Container's classloader, as the classloader for Tomcat will differ from that for a Java SE (desktop) app, will differ from that for an applet. On top of that, classloaders can really bite you if you don't understand them. If you want the gory details of how a servlet container ought to work, you can check out the latest and greatest Servlet specification.
The information on Tomcat's classloader provides a best practice list for you. Note that I've linked a 5.5 version. If you are using a later or earlier version, check around for the same file for your version.
Here's a suggestion that might help in troubleshooting the problem.
WAR files (Web Archives) will put all of your application's dependency JARs in the directory WEB-INF/lib. If you get a report of a missing class, try unzipping your WAR file, or looking in the exploded webapp directory of your app server, and see if the necessary jar is there.
The difference between this location and tomcat/lib is that JARs in tomcat/lib are made available in Tomcat's parent classloader for all loaded apps. (Indeed this can cause a problem if an app has its own version of a particular JAR in WEB-INF/lib.) The JARs in WEB-INF/lib are loaded in the application's classloader and are only available to that app.
If your JAR is missing from WEB-INF/lib, check your build scripts or the Build Path of your project in Eclipse. Good luck!
In Eclipse, I export as "Runnable JAR file", and in the dialog after, under "Library handling", I choose "Extract required libraries into generated Jar".
Basically, what this means is that if I can run it in Eclipse without error, it will run stand alone too since everything that I've told Eclipse is required will be included in the JAR.
my application needs multiple jars to work. Since it is a desktop application i can not hold the user responsible of installing. So in my build script i unzip the jars content in to my build directory delete manifest files, compile my software and jar it again. Everything works as it should my question is are there any long term side effects to this process?
In the past, there were JARs with weird content (like the DB2 driver which contains com.ibm and com.IBM; after decompressing in a Windows filesystem, those two packages would be merged).
The only issue you need to be aware of are signed jars and other files in META-INF which might have the same name in multiple source JARs.
A simple solution for all these issues is to use One-JAR. It allows to wrap several JARs into one without unpacking them, first. And read this answer: Easiest way to merge a release into one JAR file
A simpler solution (IMO) is using Maven's assembly plugin, which is also described in one of the answers to another question which was linked to in a previous Q&A. This is provided you are using Maven (which is a recommended tool by its own right) as a build tool.
If you want a no fuss way for the end user to kick off a program with multiple jar dependencies you may want to look at Launch4j or Jsmooth (I prefer Launch4j). Both are programs that create executables that wrap jar(s) and the JRE together so that to the end user it appears no different then any other executable.
Another great option is ProGuard, which can also shrink and/or obfuscate the code too.
If your primary target platform is Windows desktop, then you could also consider generating an Windows native exe from the jars of your application
If some of the jars are signed you lose the signature by unpacking/repacking it.
Well you're throwing away the MANIFEST of your third party jars, so that could cause you problems. For example you could be causing security issues by throwing away the "Sealed" attribute.
Why not just create a simple installer and a script to launch your application which sets the CLASSPATH correctly?
One-JAR will do the job, and has a new release (0.97) which supports frameworks like Spring and Guice, which users are now packing into One-JAR archives. http://one-jar.sourceforge.net
Ference Hechler also did some great work inside Eclipse with the Eclipse export wizard: we worked together on FatJar/One-JAR from which the Eclipse work grew, and I can recommend that as an approach, though I don't know how well it handles the frameworks.