-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 19 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Classpath weirdness with Hibernate and HQL/SQL in JUnit
PostPosted: Thu Jun 01, 2006 2:32 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version: 3.0.5

Full stack trace of any exception that occurs:
java.lang.NoClassDefFoundError: /com/whatever/HibernateUtility
at dao.SessionDaoBlt.saveLcmSession(SessionDaoBlt.java:77)
at dao.SessionDaoTest.setUp(SessionDaoTest.java:38)
at junit.framework.TestCase.runBare(TestCase.java:125)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:436)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:311)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)



Name and version of the database you are using: Oracle 9.2


I am developing JUnit tests for classes that access Hibernate mappings and POJOS. I notice some very odd behaviors a couple of times. I use a class very much like the HibernateUtility class from Caveat Emptor for access to Session Factories, Sessions and Transactions. Another thing I should state is that these tests use the Schema Generation facility in the test setUp() method to create a fresh schema every time the test is run.

When certain changes are made to mapping files, which are not illegal (Hibernate maps them) I get NoClassDefFoundError as above.
Reverting the change out of the mapping allows the test to complete successfully (and it does access the HibernateUtility class at several points along the way).

I fail to understand how a mapping file change could cause the HibernateUtility class to not be found?


Last edited by stevecoh2 on Thu Jun 01, 2006 5:12 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 3:08 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
Quote:
I fail to understand how a mapping file change could cause the HibernateUtility class to not be found?


Maybe I do understand. I did not put the entire Hibernate library collection onto my classpath, just the ones that were needed for earlier versions of the mappings. Possibly new mapping constructs kick off the need for other jars to be included when they are run. Is this possibly the cause?

If so, what jars are needed when adding formula attributes to a mapping that previously didn't have them?

Or should I just bite the bullet and put the whole collection on my classpath?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 3:58 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
NO dice. Added every jar in hibernate/lib to classpath and still get error.

Why should adding a formula to a mapping cause this error? I could see some different kind of error if the syntax was bad.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 4:53 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
okay, we are narrowing this down.

Never mind the strange exception, I'll take as a bug that the wrong exception is being reported.

And it's not restricted to the use of formulae.

The following query in the mapping file produces the same exception, thrown in the same place:

Code:
   <query name="findXSessionByCSessionAndTn"><![CDATA[
   from XSession s
   where s.CSessionId=:cs
   and s.tn=:tn
   and s.logged_out_time is null
   ]]></query>


The same query without the last condition does not:

Code:
<query name="findXSessionByCSessionAndTn"><![CDATA[
   from XSession s
   where s.CSessionId=:cs
   and s.tn=:tn
   ]]></query>

logged_out_time is the correct name of the column in the table.

Can anyone give me a clue here?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 5:12 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
Well, I keep coming up with clues.

Converting that query to its criteria-based equivalent resolves the problem.

Is Criteria in general preferred over HQL because of bugs like this?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 5:40 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
HibernateUtil has nothing to do with Hibernate nor HQL - it is a class in *your* project. Fix that and everything will be fine.

HQL is working perfectly fine, and so is Criteria.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 5:52 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
I am well aware that HibernateUtility is my class, thank you very much for pointing out the obvious.

However, I think there is nothing wrong with HibernateUtility, as is proven (I think) by the fact that when the query is replaced by criteria logic, while still using HibernateUtility (again, it's virtually a one-for-one knockoff of Hibernate's CaveatEmptor HibernateUtil sample), the problem disappears.

Again, I would ask, how can a change in a MAPPING file cause a NoClassDefFoundError to appear. How is HibernateUtility found by the classloader in the one case and not in the other.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 6:08 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
when you can point me to anything in that stacktrace that has to do with hibernate then i'll answer you ;)

It is some setup in your project.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 6:55 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
Well, here, think this through with me. If you say there's no such bug in HQL, I believe you and I'm sorry to have implied otherwise.

But I don't think there's anything wrong with the HibernateUtility class PER SE, certainly not that IT can't be found, since one change in the mapping file and my application has no more trouble finding it.

But I have gone back and found a problem in my mapping.

The query I posted above was bad:

Code:
   <query name="findXSessionByCSessionAndTn"><![CDATA[
   from XSession s
   where s.CSessionId=:cs
   and s.tn=:tn
   and s.logged_out_time is null
   ]]></query>


logged_out_time is the name of a database column, not the name of a pojo class property. OK, I'm an HQL newbie. Correcting this problem as folllows

Code:
   <query name="findXSessionByCSessionAndTn"><![CDATA[
   from XSession s
   where s.CSessionId=:cs
   and s.tn=:tn
   and s.loggedOutTime is null
   ]]></query>


makes the problem go away. The question I still have is why this manifests itself as a java.lang.NoClassDefFoundError on HibernateUtility. I now suspect that it's some exception class that cannot be found.

Perhaps there are two editions of a jar on the classpath and the classloader is getting confused?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 01, 2006 6:57 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
maybe

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: There is indeed a problem with my HibernateUtility class
PostPosted: Thu Jun 01, 2006 11:24 pm 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
but the same problem exists in the sample in the CaveatEmptor sample. This part of the code I stole verbatim from there.

Both rely on static initialization. But the penalty for static initialization failure is that any subsequent access to the class gets a java.lang.NoClassDefFoundError. I think that penalty is too extreme and too confusing to the programmer. Of course, in production you'd probably want to abort the app right away in such a condition, but in the world of a JUnit test suite, that's not what you're after.

So given the following fairly typical DAO method for accessing Hibernate

Code:
public static void saveThingy(Thingy thingy) {
   try {
   Session sess = HibernateUtility.getSession();
                   HibernateUtility.beginTransaction();
      sess.saveOrUpdate(thingy);
      HibernateUtility.commitTransaction();
   } catch (HibernateException e) {
      HibernateUtility.rollbackTransaction();
      throw new InfrastructureException(e);
         
   } catch (InfrastructureException e) {
      HibernateUtility.rollbackTransaction();
      throw e;
   } finally {
      HibernateUtility.closeSession();
   }
    }


If this is the first access of HibernateUtility and something is wrong with the configuration, you'll bomb out on the first line, but then when the finally is executed, the initialization error will cause the NoClassDefFoundError (effectively hiding the original problem from the programmer). Closing the session in the finally clause is good practice, but you can't do it with an uninitialized class.

Better to have a static initialization flag in HibernateUtility and check it before each getSessionFactory call. If false, then run the initialization code. The advantage is that the class is still good, even if it can't do anything because of a bad configuration.

In fact, I added a second flag to indicate a FAILED initialization. Then I added a static method that throws an exception if this flag is true. That way I can put a call to this in my base class setUp() method in JUnit tests and abort each test after the first one fails for this reason.

It works like a charm.

How about some points in my tip jar?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 02, 2006 1:23 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
why does your code ignore static initialization failure ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 02, 2006 9:49 am 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
I don't think I should have to check for a static initialization failure every place I call Hibernate through my Hibernate utility. I want to know about it early, and get the hell out of there if it happens, and I want clear error messages telling me about the configuration problem.

Using a static initializer (and one that is easily prone to failure as we've seen - a single mapping syntax error will cause it) makes the class unusable and gives an error message that doesn't explain the root cause.

By not using a static initializer, the class remains valid as a java class, and can provide useful information about the root cause of the problem. And I don't have to check for initialization failures in every client method that references my utility.

I consider that a cleaner design.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 02, 2006 9:57 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
i think you need to learn how to write a static initializer. If it is written properly it won't hide the error.

Look at the HibernateUtil in caveatemptor how it is done.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 02, 2006 10:28 am 
Regular
Regular

Joined: Tue Mar 21, 2006 11:01 am
Posts: 65
Do you even read my messages?

I initially copied your static initializer verbatim.

The difference between my design and yours is that I want initialzation failure state stored (encapsulated) in the HibernateUtility class itself which can reliably report that fact whenever it might be called, not a cryptic NoClassDefFoundError message.

In a production situation, it might make no difference. You would catch the exception and probably abort the application immediately. In a JUnit test suite, an individual test case does not abort the suite. So you want to report the exception immediately, and then have all succeeding method calls called by other test cases fail quickly with error messages that are also informative.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.