Solved

How to resolve java.lang.NoClassDefFoundError

Posted on 2013-11-19
16
2,038 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 5
  • 2
16 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 39660505
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
ID: 39660528
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
ID: 39660537
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
What Is Transaction Monitoring and who needs it?

Synthetic Transaction Monitoring that you need for the day to day, which ensures your business website keeps running optimally, and that there is no downtime to impact your customer experience.

 
LVL 86

Expert Comment

by:CEHJ
ID: 39660553
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
ID: 39660573
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
ID: 39660633
Without knowing exactly what the app does and all possible paths through it, it's not easy to say
0
 

Author Comment

by:jbaird123
ID: 39660639
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
ID: 39660902
I ended up using a library loader to load the jt400.jar file explicitly, and this solved the issue
0
 

Author Comment

by:jbaird123
ID: 39660925
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
ID: 39660926
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
ID: 39660965
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 35

Expert Comment

by:Gary Patterson
ID: 39661410
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
ID: 39662345
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 35

Accepted Solution

by:
Gary Patterson earned 500 total points
ID: 39663158
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
ID: 39663345
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
ID: 39663472
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

Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Viewers learn about the third conditional statement “else if” and use it in an example program. Then additional information about conditional statements is provided, covering the topic thoroughly. Viewers learn about the third conditional statement …
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.

689 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