开发者

Keep Hibernate Initializer from Crashing Program

I have a Java program using a basic Hibernate session factory. I had an issue with a hibernate hbm.xml mapping file and it crashed my program even though I had the getSessionFactory() call in a try catch

                try
                {
                    session = SessionFactoryUtil.getSessionFactory().openStatelessSession();    
                    session.beginTransaction();
                    rh = getRunHistoryEntry(session);
                    if(rh == null)
                    {
                        throw new Exception("No run history information found in the database for run id " + runId_ + "!");
                    }
                }
                catch(Exception ex)
                {
                    logger.error("Error initializing hibernate");
                }

It still manages to break out of this try/catch and crash the main thread. How do I keep it from doing this? The main issue is I have a bunch of cleanup commands that NEED to be run before the main thread shuts down and need to be able to guarantee that even after a failure it still cleans up and goes down somewhat gracefully. The session factory looks like this:

public class SessionFactoryUtil {
    private static final SessionFactory sessionFactory;  

    static {  
        try 
        {  
            // Create the SessionFactory from hibernate.cfg.xml  
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } 
        catch (Throwable ex) 
        {  
            // Make sure you log the exception, as it might be swallowed  
            System.err.println("Initial SessionFactory creation failed." + ex);  
            throw new ExceptionInInitializerError(ex);  
        }  
    }  

    public static SessionFactory getSessionFactory() 
    {   try
        {
            return sessionFactory;
        }
        catch(Exception ex)
        {
            return null;
        }
    }  
}

The error thrown is the following, and I have fixed it, but I would like to safeguard against any hibernate initializing error from stopping the main thread.

Initial SessionFactory creation failed.org.hibernate.InvalidMappingException: Could not parse mapping document from resource hibernate/TmdIndataLine.hbm.xml
Exception in thread "main" java.lang.ExceptionInInitializerError
    at com.ryanco.db.SessionFactoryUtil.<clinit>(SessionFactoryUtil.java:19)
    at com.ryanco.rta.RtaMain.main(RtaMain.java:148)
Caused by: org.hibernate.InvalidMappingException: Could not parse mapping document from resource hibernate/TmdIndataLine.hbm.xml
    at org.hibernate.cfg.Configuration.addResource(Configuration.java:616)
    at org.hibernate.cfg.Configuration.parseMappingElement(Configuration.java:1635)
    at org.hibernate.cfg.Configuration.parseSessionFactory(Configuration.java:1603)
    at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1582)
    at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1556)
    at org.hibernate.cfg.Configuration.configure(Configuration.java:1476)
    at org.hibernate.cfg.Configuration.configure(Configuration.java:1462)
    at com.ryanco.db.SessionFactoryUtil.<clinit>(SessionFactoryUtil.java:13)
    ... 1 more
Caused by: org.hibernate.InvalidMappingException: Could not parse mapping document from input stream
    at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:555)
    at org.hibernate.cfg.Configuration.addResource(Configuration.java:613)
    ... 8 more
Caused by: org.dom4j.开发者_Go百科DocumentException: Error on line 114 of document  : The element type "class" must be terminated by the matching end-tag "</class>". Nested exception: The element type "class" must be terminated by the matching end-tag "</class>".
    at org.dom4j.io.SAXReader.read(SAXReader.java:482)
    at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:546)
    ... 9 more


The static initializer in SessionFactoryUtil has a try/catch for all instances of Throwable but your main try/catch block only catches Exceptions. I'd change it to catch Throwables as well and see if that solves the problem.


Well, depending on what type of application you write, static initializers doing anything that reaches outside of the JVM are usually a bad idea.

To the problem: if I read you code correctly, you first catch all Throwables in the static initalizer of SessionFactoryUtil, write an error message to standard error an then throw a new ExceptionInInitializerError yourself, wrapping the catched Throwable in it.

IIRC static initializers are invoked first thing after the class was loaded. The stack trace tells us this happens probably from the main method in class RtaMain, as SessionFactoryUtil.getSessionFactory() seems to be invoked from there, which triggers the class load.

To catch this error you need a try/catch surrounding the call to getSessionFactory() in the main method of your class RtaUtil, catching Throwable, or at least the specific throwable you throw in your static initializer yourself, which is ExceptionInInitializerError.

HTH


It still manages to break out of this try/catch and crash the main thread.

As mentioned, this bloc in your main method won't catch the ExceptionInInitializerError thrown in your static initializer:

catch(Exception ex) {
    logger.error("Error initializing hibernate")
}

If you want to catch both Exception and Error, you should catch (Throwable t) (by the way, I noticed you said you changed that but I'd like to see what you changed exactly and the error you get.

But to be honest, if the SessionFactory fails at being initialized, I wonder what you're going to do in your main method and it's actually a common practice to let the program fail in that case.

Last thing, the try/catch in this part seems totally useless:

public static SessionFactory getSessionFactory() {
    try {
        return sessionFactory;
    } catch(Exception ex) {
        return null;
    }
} 

You can remove it safely.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜