Most of the time , the developers will be having hard time to debug the issues related to class loading issues for the reasons like
1 . the class path might have two different jars with the same class having different version.
2. class loading issues.
Although we could use jar utility to delve into each and every jar , it is going to be extremely tedious and error prone.
Is there a tool or some mechanism to resolve this kind of issues .
Though the class loading is not simple in realistic , say how the weblogic will do class loading of a particular ear file.
give a try to tattletale, it works both in ant and maven:
The tool will provide you with reports that can help you
Identify dependencies between JAR files
Find missing classes from the classpath
Spot if a class/package is located in multiple JAR files
Spot if the same JAR file is located in multiple locations
With a list of what each JAR file requires and provides
Verify the SerialVersionUID of a class
Find similar JAR files that have different version numbers
Find JAR files without a version number
Find unused JAR archives
Identify sealed / signed JAR archives
Locate a class in a JAR file
Get the OSGi status of your project
Remove black listed API usage
I find running Java in verbose mode quite handy for resolving class path errors.
It will show you what classes and jars are being loaded by the program.
It can be a quick first step to try fix the problem without using a debugging program.
Related
I have java server application wich uses many libs (netty, guava, etc). I always export this application as one single .jar. When I run application in Eclipse, I didn't have any problems. But if I start app in console (Windows, or Ubuntu, doesn't matter), I have strange problem: ALL connection processes via sockets last toooo long. For example, simple http connection via HttpAsync or others (rabbitmq connection, etc.) lasts 1-2 min. But after connection completed, data sends/receives fast. I can't figure what the problem. As mentioned before, I use Eclipse for development.
As you know, you can export project 3 dif ways (in Eclipse):
Extract required libraries into JAR.
Package required libraries into JAR.
Copy required libraries into sub folder next to JAR.
So, when I used 2 option, I had problem. When I switched to 3d option (all .jars in folder near main .jar), problem was solved.
Generally there are no big difference between 2 and 3 option (in 2 all .jars just inside one jar). I thought that it was cause of extra time needed to load new classes in execution time from the jars. But problem occurs not only at start, but for all new connections.
Can someone explain this behavior?
UPD: Eclipse Luna. Doesn't matter what OS I'm using (Windows, or Ubuntu), even doesn't matter what jvm (tried with different Oracle jdk, even tried open jdk).
This all talks about difference in performance when packaging into JAR v/s extracting into JAR & difference in performance when running from Eclipse v/s running from console.
Difference in performance when packaging into JAR v/s extracting into JAR:
Extract required libraries into JAR:
What it does:
In this option Eclipse will extract all the classes from the referenced JARs and package into the generated JAR.
If you open the JAR then you will find that there are NO referenced JARs packaged but all the classes of referenced JARs are arranged as per the package structure and then packaged inside the JAR at root level. This brings the key difference in performance as compared to the "Packaging required libraries into a jar file" where there is additionally cost of runtime parsing and loading of JAR in memory etc..
When exporting as JAR through Eclipse then it is best option if performance is concern. Also this is scalable option because you can ship this JAR
MANIFEST.MF Main thing to note in this file is you main class. When you run the JAR you are directly running the class you need.
Main-Class: com.my.jar.TestSSL
Package required libraries into JAR:
What it does:
In this option Eclipse will:
package all the referenced JARs into the generated JAR.
employ Eclipse's JAR loading mechanism through org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader and you can also see org.eclipse.jdt.internal.jarinjarloader package into your generated JAR and this package is just under the root directory of the generated JAR.
Now of course this is the additional cost which comes when you choose this option because when you run the JAR then it is not you main class getting executed but JarRsrcLoader will be executed which will load your main class and other libraries, and all the referenced libraries are packaged. See MANIFEST.MF section below
MANIFEST.MF Main thing to note in this file is you main class. When you run the JAR, JarRsrcLoader will run and will do further job.
Rsrc-Main-Class: com.cgi.tmi.TestSSL
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
Now for last Eclipse export option - "Copy required libraries into sub folder next to JAR", I don't think it is a very scalable solution to consider because this imposes your file system dependency, so I would say don't do it.
Difference in performance when running from Eclipse v/s running from console:
When you run application from Eclipse then it is quiet similar to 1st export option where Eclipse doesn't need to parse and load JARs at runtime and all.
This is however a very trivial point, key is the consideration of Eclipse JAR export option 1 v/s option 2.
Final words:
Use "Extract required libraries into JAR" for exporting JAR and you will see substantial performance gain.
It is highly improbable that your socket connections are lasting long when you run from console because JVM runs code then it would have same or very comparable performance when running from Eclipse and console (considering same Java versions in both case). You could be feeling because of packaged JAR performance. Try extracted JAR and you should be fine.
Also, consider the amount of logging you are doing. When running through, depending upon configuration Eclipse may mask a lot of logging and hence saving you i/o time.
Do understand how classes are accessed from JAR class path, which is like additional computational cost when you are referencing classes from JAR.
As we don't know the exact structure of your JAR here is a more general explanation (assumed you run your application with java -jar your_app.jar).
case Copy required libraries into sub folder next to JAR.
if a class needs to be loaded the class loader (after the runtime JAR) first checks your_app.jar to find a required class
if the class is not found it traversed over all JAR files in the subfolder
all JAR files could be kept in the filesystem cache for further reading
case Package required libraries into JAR
if a class needs to be loaded the Eclipse class loader JarRsrcLoader (after the runtime JAR) first checks your_app.jar to find a required class
if the class is not found it traversed over all embedded JAR files, which means as first they need to be decompressed from your_app.jar before the content can be read
the extracted embedded JAR files are not kept in the filesystem cache for further reading (as they are not files in the filesystem)
If you have a bigger number of hugh embedded library JARs this might lead in a slow down of class loading (but only for the first time a class is loaded by a class loader).
You can see the difference in the class loading if you compare the outpout of
java -verbose:class -jar your_app_external_library_jars.jar
with
java -verbose:class -jar your_app_embedded_library_jars.jar
The performance might be improved by generating an INDEX.LIST file for each JAR file (e.g. your_app.jar and the embedded library JARs).
It happens because when you go with "uber jar" approach, some metadata might be lost.
It's just an example, but if you download this and this, take a look inside the jar. There are a few files with the same name in the same META-INF folder.
Those files might be important, and when eclipse repackages things for you, he might not be the doing a decent job on merging such files.
That is what might be happening to you.
In the 2nd approach, You have all dependency jars in the main.jar.
So it won't load any of the dependency jars unless required.
Whereas, in case of 3rd option, your main.jar and other dependency jars are independent (unlike 2nd way), and hence gets loaded for connections and is available.
try adding a log statement or syso by manipulating a dependency jar to see this working.
Let's assume I have two jar files on classpath when building my project - myJarFile.jar and myJarFileOld.jar. They contain the same packages and the same classes, but the myJarFileOld.jar contains old implementation, which causes that the compilation fails. I'm not asking for solution of this error, I know that I should remove myJarFileOld.jar to make compilation work. However I'd like to know, what mechanism decides which class from which jar file is used during compilation, when both jar files are present?
When a class needs to be loaded, all jar files in the classpath, in order, are scanned. As soon as the class is found, it's loaded.
Not fully sure, but I believe the order of classpath appearance is deciding. If it's found in first jar, then it's not search in another. However I'm pretty sure that class loader will load both jars at the beginning, and you will get some errors about duplicate code. However I'm not sure this, this is probably related to runtime environment.
you have this feature in Eclipse where you can specify the ordering of the jars that you want to be executed from the project classpath.Go to
Project->Select Properties->Select Build Path from left pane-> go to Order and Export Tab->Select Top or Bottom button-> click ok.
The next time you build your project the jar from the classpath will be picked in the order that you have specified.
I'm new to Java and NetBeans and I'm having a very hard time getting a simple project started.
I'm trying to include .jar files I need to work on a NetBeans plugin. I can successfully add the .jar files to my project using a variety of attempted methods.
I added .jar files by the project properties and added the 'wrapped jar' files to the project
I added the .jar files to the 'Libraries' item in the Projects explorer tree
Both methods appear to work in the IDE. They allow the desired classes to be accessed in the IDE and no syntax or access errors (etc) are detected. However, when I build and run I get ten pages of errors such as NullPointerException and this doozy:
java.lang.ClassNotFoundException: Will not load class org.netbeans.modules.openide.nodes.NodesRegistrationSupport arbitrarily from one of ModuleCL#2afef4c1[org.openide.nodes] and ModuleCL#2debe24[com.myproject.simplelauncherbutton] starting from SystemClassLoader[316 modules]
com.myproject.simplelauncherbutton is my own package. Why would NetBeans even be looking in my package for this class? And even if it is looking there, how can it be finding the class there, to be confused? I just want to make a NetBeans plugin using a .jar file for support. How can I get this working?!
Solved with help from a coworker. The problem was the way in which I was including packages in my project. I was trying to include packages in my project that did not seem to be available. For example, I needed to use org.openide.nodes, so at the top of my class file I wrote:
import org.openide.nodes;
NetBeans would respond saying it couldn't find this package. When I found a wrapped JAR package containing org.openide.nodes and included that in my project, it generated a slew of errors too long to list here.
However, when I add the module by its English name "Nodes API" in the project properties, everything works fine. I wish there were some documentation or instructions I had been able to find to save me hours of stressing about why I couldn't get NetBeans to recognize the various versions of org.openide.* I was trying to use.
Is there a tool out there that can check if an imported JAR is being used from within a package? Basically I want to remove any unused JARs from a project and I do not want to have to remove each JAR one-by-one and check for possible reference issues for each removed JAR.
ProGuard will do the trick for you! Configured correctly and given some initial rules it will take jar files in an input directory and output the same jars into the output directory. Java class files that aren't needed won't be included in the output jars and if a jar has no classes left, it's simply removed. The website also includes tons of examples.
In addition to doing this, it has a number of great features to help in compacting and obfuscating your final project. The configuration files may seem a bit tricky at first -- but it pays off. In some projects at work, we have final archive sizes that are reduced well over 1000%. How often have you included a library only to use a fraction of the functionality? With a proper setup the final product will only include what's needed.
I have downloaded a complete package of Java product and trying to compile it using Ant. The project compiles with many errors, mostly related to imports starting with "org.apache.commons".
I'm new to Java. It looks to me that some system component is missing.
Some of the errors are:
package org.apache.commons.logging does not exist
package com.ibm.icu.text does not exist
cannot find symbol
What should I do to get rid of those errors?
As Sujee has said you need to include 2 jar files in your classpath. You can find the jars here:
http://download.icu-project.org/files/icu4j/4.4.1.1/icu4j-4_4_1_1.jar
http://apache.forthnet.gr/commons/logging/binaries/commons-logging-1.1.1-bin.zip
org.apache.commons.logging and com.ibm.icu.text are third party Java libraries. Download them from their websites and include in the Java classpath.
Update
Classpath is a list of file system paths which defines the locations of Java classes and libraries. JVM uses this to load the class it needs in the runtime. Usual practice is to put all libraries in a sub folder called 'lib' then add '\lib' in the classpath. My advice is to use a graphical tool like Eclipse so you don't need to manually do this. Please read this wikipedia article for more info about Classpath.