Solved

How to resolve java.lang.NoClassDefFoundError

Posted on 2013-11-19
16
1,868 Views
Last Modified: 2013-11-20
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.NoClassDefFoundError: com/ibm/as400/access/QSYSObjectPathName
      at prj_archintegrate.iseries_db_execute_0_1.iseries_db_execute.tJava_3Process(iseries_db_execute.java:339)
      at prj_archintegrate.iseries_db_execute_0_1.iseries_db_execute.runJobInTOS(iseries_db_execute.java:596)
      at prj_archintegrate.iseries_db_execute_0_1.iseries_db_execute.main(iseries_db_execute.java:464)
Caused by: java.lang.Error: java.lang.NoClassDefFoundError: com/ibm/as400/access/QSYSObjectPathName
      at prj_archintegrate.iseries_db_execute_0_1.iseries_db_execute.tJava_2Process(iseries_db_execute.java:418)
      at prj_archintegrate.iseries_db_execute_0_1.iseries_db_execute.tJava_3Process(iseries_db_execute.java:330)
      ... 2 more
Caused by: java.lang.NoClassDefFoundError: com/ibm/as400/access/QSYSObjectPathName
      at prj_archintegrate.iseries_db_execute_0_1.iseries_db_execute.tJava_2Process(iseries_db_execute.java:376)
      ... 3 more
Caused by: java.lang.ClassNotFoundException: com.ibm.as400.access.QSYSObjectPathName
[statistics] connecting to socket on port 3735
[statistics] connected
here...
[statistics] disconnected
[statistics] disconnected
      at java.net.URLClassLoader$1.run(Unknown Source)
      at java.net.URLClassLoader$1.run(Unknown Source)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.net.URLClassLoader.findClass(Unknown Source)
      at java.lang.ClassLoader.loadClass(Unknown Source)
      at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
      at java.lang.ClassLoader.loadClass(Unknown Source)
      ... 4 more
Job iseries_db_execute ended at 14:58 19/11/2013. [exit code=1]
good.java
bad.java
0
Comment
Question by:jbaird123
  • 9
  • 5
  • 2
16 Comments
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
0
 

Author Comment

by:jbaird123
Comment Utility
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.
0
 

Author Comment

by:jbaird123
Comment Utility
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.
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
0
 

Author Comment

by:jbaird123
Comment Utility
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.
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
Without knowing exactly what the app does and all possible paths through it, it's not easy to say
0
 

Author Comment

by:jbaird123
Comment Utility
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.
0
 

Author Comment

by:jbaird123
Comment Utility
I ended up using a library loader to load the jt400.jar file explicitly, and this solved the issue
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:jbaird123
Comment Utility
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.
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
0
 

Author Comment

by:jbaird123
Comment Utility
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.
0
 
LVL 34

Expert Comment

by:Gary Patterson
Comment Utility
Start with the basics:

One common cause of java.lang.NoClassDefFoundError 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
0
 

Author Comment

by:jbaird123
Comment Utility
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.
0
 
LVL 34

Accepted Solution

by:
Gary Patterson earned 500 total points
Comment Utility
Disclaimer: I'm not a Talend expert.  So I have no idea what is going on in that environment outside of the little bit of code you provided here.

If what you are suggesting is the issue, then it should be evident by comparing the two files I sent.


No - that's a bad assumption on your part..

First of all, you only provided code for the class iseries_db_execute.  There is a lot going on here besides what is coded in that class.  

You also seem to be making the assumption that the code that you removed could have only be called directly from inside iseries_db_execute.  That just isn't true.  They are public methods.  They can be used anywhere.

public void tAS400Connection_1_error
public void tAS400Connection_1_onSubJobError
public void tAS400Connection_1Process

Next, let's clarify "Import".  "Import" doesn't load classes.  It is a convenience function.  All it does is allow you to reference classes in code using just the class name portion instead of the fully-qualified class name:

QSYSObjectPathName
vs
com.ibm.as400.access.QSYSObjectPathName

Import is referenced at "compile time" (bytecode generation) - not at runtime.

At runtime, the class needs to be "findable".  It needs to be in the classpath, or it needs to be loaded through another mechanism (some of those mechanisms look for direction on what to load by inspecting configuration files...).

You didn't provide the runtime classpath for either program.  Is jt400.jar in it?

You didn't provide any configuration files.  Do you see any references to jt400.jar in any config files associated with Talend or this particular job?

In the error thrown by "bad", it can't find the QSYSObjectPathName class at runtime.  So it is likely that:

"Good" and "bad" are running with different classpaths.  Good has jt400.jar in it, and bad doesn't.

OR

When you execute the job, something is causing the QSYSObjectPathName class to get loaded (other than the classpath) when you run "good", but not when you run "bad".  Maybe there is a configuration file containing classes to load that gets changed when you add and remove the AS400 connection in Talend.

You said:  It should not have been necessary to explicitly load the jt400.jar file.

If it isn't in your classpath at runtime (and it apparently isn't), it has to get loaded somehow, since the QSYSObjectPathName is in that jar, and it is clearly referenced.

Finally, you could just get rid of this block of code and solve the need for loading the problem class altogether.  

QSYSObjectPathName pgmName = new QSYSObjectPathName("REPORTS",
                                    "PRINT_IT", "PGM");
System.out.println(pgmName.getPath());

It is just logging the name of a program object to standard output.  Now, maybe there is some downstream process that is parsing this output and actually needs that for something, but there is no way for us to know that unless you tell us.

Hope that helps.

- Gary Patterson
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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.
0
 

Author Closing Comment

by:jbaird123
Comment Utility
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.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now