jbaird123
asked on
How to resolve java.lang.NoClassDefFoundError
I have a piece of Java code that compiles fine in Eclipse, but I get a run time "NoClassDefFoundError" when I execute it, The missing library is com.ibm.as400.access.*;
Now I have isolated the issue somewhat, but I am puzzled as to what to do about it. I have attached 2 different sets of Java code, one works and the other doesn't. Both contain this command:
import com.ibm.as400.access.*;
The one that works contains some extra code used to establish a connection to an AS400 machine, but this code never actually executes. You will notice at line 333 of the "good.java", there is an if statement which prevents any of this code from executing.
So... the "good.java" program runs fine. The "bad.java" program fails with the "NoClassDefFound" error.
I cannot understand what is wrong with my "bad.java" program.
I just need someone to tell me how to fix my bad code without adding all that extra code which is never used. There is something in the good.java which allows the code to run.
Please help.
Thanks.
Below is the error:
Starting job iseries_db_execute at 14:58 19/11/2013.
Exception in thread "main" java.lang.Error: java.lang.Error: java.lang.NoClassDefFoundE rror: com/ibm/as400/access/QSYSO bjectPathN ame
at prj_archintegrate.iseries_ db_execute _0_1.iseri es_db_exec ute.tJava_ 3Process(i series_db_ execute.ja va:339)
at prj_archintegrate.iseries_ db_execute _0_1.iseri es_db_exec ute.runJob InTOS(iser ies_db_exe cute.java: 596)
at prj_archintegrate.iseries_ db_execute _0_1.iseri es_db_exec ute.main(i series_db_ execute.ja va:464)
Caused by: java.lang.Error: java.lang.NoClassDefFoundE rror: com/ibm/as400/access/QSYSO bjectPathN ame
at prj_archintegrate.iseries_ db_execute _0_1.iseri es_db_exec ute.tJava_ 2Process(i series_db_ execute.ja va:418)
at prj_archintegrate.iseries_ db_execute _0_1.iseri es_db_exec ute.tJava_ 3Process(i series_db_ execute.ja va:330)
... 2 more
Caused by: java.lang.NoClassDefFoundE rror: com/ibm/as400/access/QSYSO bjectPathN ame
at prj_archintegrate.iseries_ db_execute _0_1.iseri es_db_exec ute.tJava_ 2Process(i series_db_ execute.ja va:376)
... 3 more
Caused by: java.lang.ClassNotFoundExc eption: com.ibm.as400.access.QSYSO bjectPathN ame
[statistics] connecting to socket on port 3735
[statistics] connected
here...
[statistics] disconnected
[statistics] disconnected
at java.net.URLClassLoader$1. run(Unknow n Source)
at java.net.URLClassLoader$1. run(Unknow n Source)
at java.security.AccessContro ller.doPri vileged(Na tive Method)
at java.net.URLClassLoader.fi ndClass(Un known Source)
at java.lang.ClassLoader.load Class(Unkn own Source)
at sun.misc.Launcher$AppClass Loader.loa dClass(Unk nown Source)
at java.lang.ClassLoader.load Class(Unkn own Source)
... 4 more
Job iseries_db_execute ended at 14:58 19/11/2013. [exit code=1]
good.java
bad.java
Now I have isolated the issue somewhat, but I am puzzled as to what to do about it. I have attached 2 different sets of Java code, one works and the other doesn't. Both contain this command:
import com.ibm.as400.access.*;
The one that works contains some extra code used to establish a connection to an AS400 machine, but this code never actually executes. You will notice at line 333 of the "good.java", there is an if statement which prevents any of this code from executing.
So... the "good.java" program runs fine. The "bad.java" program fails with the "NoClassDefFound" error.
I cannot understand what is wrong with my "bad.java" program.
I just need someone to tell me how to fix my bad code without adding all that extra code which is never used. There is something in the good.java which allows the code to run.
Please help.
Thanks.
Below is the error:
Starting job iseries_db_execute at 14:58 19/11/2013.
Exception in thread "main" java.lang.Error: java.lang.Error: java.lang.NoClassDefFoundE
at prj_archintegrate.iseries_
at prj_archintegrate.iseries_
at prj_archintegrate.iseries_
Caused by: java.lang.Error: java.lang.NoClassDefFoundE
at prj_archintegrate.iseries_
at prj_archintegrate.iseries_
... 2 more
Caused by: java.lang.NoClassDefFoundE
at prj_archintegrate.iseries_
... 3 more
Caused by: java.lang.ClassNotFoundExc
[statistics] connecting to socket on port 3735
[statistics] connected
here...
[statistics] disconnected
[statistics] disconnected
at java.net.URLClassLoader$1.
at java.net.URLClassLoader$1.
at java.security.AccessContro
at java.net.URLClassLoader.fi
at java.lang.ClassLoader.load
at sun.misc.Launcher$AppClass
at java.lang.ClassLoader.load
... 4 more
Job iseries_db_execute ended at 14:58 19/11/2013. [exit code=1]
good.java
bad.java
If it's never used, why is it there? Even if there are imports that are unused, they must be met or the code will fail with a classpath error. You can solve the problem either by removing unused imports or supplying imported classes
ASKER
CEHJ -
I am trying to remove the unwanted code, and this is causing the failure.
So to re-phrase my question - "for some reason my program won't run unless I include the unused code".
I guess the "unused code" is in fact being used but I cannot see how.
Thanks.
I am trying to remove the unwanted code, and this is causing the failure.
So to re-phrase my question - "for some reason my program won't run unless I include the unused code".
I guess the "unused code" is in fact being used but I cannot see how.
Thanks.
ASKER
CEHJ - Also, I am not talking about any unused imports. I am talking about unused program code.
If you run a file compare between the two samples I sent, you will see the differences. All imports are met in both cases - this is why there are no compile errors. The problem happens at run-time.
If you run a file compare between the two samples I sent, you will see the differences. All imports are met in both cases - this is why there are no compile errors. The problem happens at run-time.
All imports are met in both cases - this is why there are no compile errors. The problem happens at run-time.What you're not getting is that imports must be met at both compile AND runtime
You could be right - the code IS used but you can't see it. If that's the case, only the latter solution is possible
ASKER
CEHJ -
What I am looking for is for someone to tell me exactly which parts of the code are actually important in the "good.java" file, so I can take those lines and only those lines and move them over to the other file. There are quite a few lines of code in the "good.java" code which can probably be removed, but I don't know which ones they are.
Can you point me to the specific line(s) in the "good.java" file which are necessary? I'm sure most of them are not necessary and can be removed.
Thanks.
What I am looking for is for someone to tell me exactly which parts of the code are actually important in the "good.java" file, so I can take those lines and only those lines and move them over to the other file. There are quite a few lines of code in the "good.java" code which can probably be removed, but I don't know which ones they are.
Can you point me to the specific line(s) in the "good.java" file which are necessary? I'm sure most of them are not necessary and can be removed.
Thanks.
Without knowing exactly what the app does and all possible paths through it, it's not easy to say
ASKER
Can anyone else help here? I would think that a file compare utility would highlight the differences and it shouldn't be that difficult to hone in on the important line.
ASKER
I ended up using a library loader to load the jt400.jar file explicitly, and this solved the issue
ASKER
I've requested that this question be closed as follows:
Accepted answer: 0 points for jbaird123's comment #a39660902
for the following reason:
I had to figure out which jar file was missing and explicitly load it.
Accepted answer: 0 points for jbaird123's comment #a39660902
for the following reason:
I had to figure out which jar file was missing and explicitly load it.
I had to figure out which jar file was missing and explicitly load it.
IOW, you did what i suggested above (the 2nd of the two):
You can solve the problem either by removing unused imports or supplying imported classes
ASKER
No. My original question was to compare the two files and explain what was wrong with the one that didn't work. It should not have been necessary to explicitly load the jt400.jar file. In any case, I solved this by guesswork, and no explanation has been given as to what was wrong with my file. I still cannot tell you why one of those programs works and the other does not. Granted, I was able to get my program working, but it was not the solution I was looking for.
If you would like credit for solving this, then please look at the two files I posted and explain to me what needs to be added to the bad.java in order to get it to work.
If you would like credit for solving this, then please look at the two files I posted and explain to me what needs to be added to the bad.java in order to get it to work.
Start with the basics:
One common cause of java.lang.NoClassDefFoundE rror is that the problem class was found at compile time, but not at runtime. So check your runtime classpath and make sure the AS/400 Java Toolbox jar is there.
Could be as simple as that line of code is getting executed in the "bad" code, but not in the good code.
- Gary Patterson
One common cause of java.lang.NoClassDefFoundE
Could be as simple as that line of code is getting executed in the "bad" code, but not in the good code.
- Gary Patterson
ASKER
Gary,
If what you are suggesting is the issue, then it should be evident by comparing the two files I sent.
These two files are actually being generated by Talend, so I don't have much control over how they were written. If you're not familiar with Talend, it is essentailly a GUI interface which writes Java code for you by allowing you to drag and drop components on to a design canvas and visually model your program flow. So I am not writing this code, Talend is generating it for me based on how I arrange various components on the design canvas.
Those two files are actually the same program but the "bad" one essentially has some lines removed. So the way the process works is this: I create a simple Talend job which has 2 components - one is a custom component which allows me to create some custom Java to be executed within the program, and a second component which contains a gui interface to supply credentials to connect to an AS400 database. I don't actually supply any database connection information to this component - I just put it on my design canvas and leave all the fields empty. Then I make sure that there is a condition placed on this component to ensure it never gets executed (by checking "if 1==2"). As long as that component exists on my canvas, the program runs fine. The code which gets generated from this Talend job is the "good.java". Now when I simply disable that AS400 connection component, the job fails with a "no class def found" error. The resulting Java code that gets generated when the AS400 component is disabled is contained in the "bad.java". Both the "good" and "bad" programs contain the import command "import com.ibm.as400.access.*;"
So, when I disable the AS400 component, the program fails at run time. If I simply enable that component the job runs fine even though that component does not get used.
So, from what I can tell the only difference between these two java programs is in the code itself. They both have the same configuration aside from that. This is why I think that someone should be able to spot the issue by comparing the two files. I have tried and unfortunately I have not been able to figure it out. Of course, I am a newbie to Java.
Thanks.
If what you are suggesting is the issue, then it should be evident by comparing the two files I sent.
These two files are actually being generated by Talend, so I don't have much control over how they were written. If you're not familiar with Talend, it is essentailly a GUI interface which writes Java code for you by allowing you to drag and drop components on to a design canvas and visually model your program flow. So I am not writing this code, Talend is generating it for me based on how I arrange various components on the design canvas.
Those two files are actually the same program but the "bad" one essentially has some lines removed. So the way the process works is this: I create a simple Talend job which has 2 components - one is a custom component which allows me to create some custom Java to be executed within the program, and a second component which contains a gui interface to supply credentials to connect to an AS400 database. I don't actually supply any database connection information to this component - I just put it on my design canvas and leave all the fields empty. Then I make sure that there is a condition placed on this component to ensure it never gets executed (by checking "if 1==2"). As long as that component exists on my canvas, the program runs fine. The code which gets generated from this Talend job is the "good.java". Now when I simply disable that AS400 connection component, the job fails with a "no class def found" error. The resulting Java code that gets generated when the AS400 component is disabled is contained in the "bad.java". Both the "good" and "bad" programs contain the import command "import com.ibm.as400.access.*;"
So, when I disable the AS400 component, the program fails at run time. If I simply enable that component the job runs fine even though that component does not get used.
So, from what I can tell the only difference between these two java programs is in the code itself. They both have the same configuration aside from that. This is why I think that someone should be able to spot the issue by comparing the two files. I have tried and unfortunately I have not been able to figure it out. Of course, I am a newbie to Java.
Thanks.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
jbaird123, you've had two experts tell you essentially the same thing. I would urge you to try to understand the classpath in Java, which, incidentally is only going to be made harder by using automated tools.
Far from only being important at compile time (in fact you could argue that the classpath is less important at compile time as for some types of classloading no compile-time resolution is necessary) it is essential that the classpath meet the dependencies of your code, and that means all your code. It's not possible to see whether that from part of your code. What is possible to see is when those dependencies are not loadable, and that is what both of us have seen and told you.
Far from only being important at compile time (in fact you could argue that the classpath is less important at compile time as for some types of classloading no compile-time resolution is necessary) it is essential that the classpath meet the dependencies of your code, and that means all your code. It's not possible to see whether that from part of your code. What is possible to see is when those dependencies are not loadable, and that is what both of us have seen and told you.
ASKER
Gary,
Thank you for taking the time to review my code and address my questions and confusion.
I found the issue based on your insights. Here is what I discovered: In Talend, you cannot edit the classpath directly (maybe you can but it would be a bad idea - your edits would be lost when you moved your code to a new environment ... i.e. promoting to QA or Production). Talend itself determines what should be included in the classpath when it generates the code. This is just the nature of a code-generation tool.
Now you mentioned "Maybe there is a configuration file containing classes to load that gets changed when you add and remove the AS400 connection in Talend." This was the culprit. I checked the compiled code for both the "good" and "bad" programs, and sure enough, Talend decided to include the jt400.jar file in the library and also in the classpath. When I removed that AS400 component from my design canvas, Talend decided it was not necessary to include that .jar file in my library or in my classpath. Bottom line is that Talend is managing my classpath - it is not something I have direct control over.
So... This explains why I had to explicitly load the jt400.jar file. When I used the AS400 component, Talend updated the classpath accordingly. When I removed that component, Talend figured I didn't need it anymore and removed it from the classpath. Fortunately Talend provides an explicit library loader, and if I include the jt400.jar in that loader then the classpath file gets created correct.
Thank you for clarifying the functionality of "import" as well.
Thank you for taking the time to review my code and address my questions and confusion.
I found the issue based on your insights. Here is what I discovered: In Talend, you cannot edit the classpath directly (maybe you can but it would be a bad idea - your edits would be lost when you moved your code to a new environment ... i.e. promoting to QA or Production). Talend itself determines what should be included in the classpath when it generates the code. This is just the nature of a code-generation tool.
Now you mentioned "Maybe there is a configuration file containing classes to load that gets changed when you add and remove the AS400 connection in Talend." This was the culprit. I checked the compiled code for both the "good" and "bad" programs, and sure enough, Talend decided to include the jt400.jar file in the library and also in the classpath. When I removed that AS400 component from my design canvas, Talend decided it was not necessary to include that .jar file in my library or in my classpath. Bottom line is that Talend is managing my classpath - it is not something I have direct control over.
So... This explains why I had to explicitly load the jt400.jar file. When I used the AS400 component, Talend updated the classpath accordingly. When I removed that component, Talend figured I didn't need it anymore and removed it from the classpath. Fortunately Talend provides an explicit library loader, and if I include the jt400.jar in that loader then the classpath file gets created correct.
Thank you for clarifying the functionality of "import" as well.