Search code examples
javajpaexceptionderbyopenjpa

Can you get more specific exception or cause of getting PersistenceException when calling createEntityManager while using OpenJPA


While connecting to Derby database using OpenJPA, i have encountered this PersistenceException, which says connection could not be obtained for Derby EmbeddedDriver driver class, but that is not important (i know how to fix it):

77  RegistryManagement  INFO   [JavaFX Application Thread] openjpa.jdbc.JDBC - Using dictionary class "org.apache.openjp
a.jdbc.sql.DerbyDictionary".
<openjpa-3.1.2-r66d2a72 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: There were errors i
nitializing your configuration: <openjpa-3.1.2-r66d2a72 fatal user error> org.apache.openjpa.util.UserException: A conne
ction could not be obtained for driver class "org.apache.derby.jdbc.EmbeddedDriver" and URL "jdbc:derby:db".  You may ha
ve specified an invalid URL.
....

Important is that there is this Caused by in that exception:

....
Caused by: ERROR XJ004: XJ004.C : [0] db
    at 
....

which is one of Derby error codes (https://db.apache.org/derby/docs/10.5/ref/rrefexcept71493.html).

This PersistenceException was thrown when calling .createEntityManager(). Is it pretty long when it comes to text length.

I can catch that PersistenceException by wrapping .createEntityManager() with try-catch, but i can not figure out how to find more information about what is the cause, aka. get the error code, because PersistenceException can be thrown for various reasons. And i can not wrap it with catching SQLException or UserException, because my IDE says that method does not throw these exceptions.

I tried calling .getMessage() or .getCause() on that PersistenceException, but i got almost same long text.

When i called .getCause() it returns RuntimeException and I could see this, that Derby thrown SQLException:

....
Caused by: java.sql.SQLException: XJ004.C : [0] db
    at 
....

calling .getCause() again returns null.

I do not want to search the whole message (String) for occurences of some error codes, because that might be resource heavy. I think this problem might not be specific to Derby and happen while using other sql dbs, which might also throw some exception.

My code:

public class DatabaseManager
{
    private EntityManagerFactory managerFactory;
    private EntityManager manager;

    public DatabaseManager(String persistenceUnitName, Map<String, String> properties)
    {
        managerFactory = Persistence.createEntityManagerFactory(persistenceUnitName, properties);
        try
        {
            manager = managerFactory.createEntityManager();
        }
        catch(PersistenceException e)
        {
            //stuff
        }
    }
....

EntityManagerFactory is an interface from javax.persistence package:

public interface EntityManagerFactory {

    public EntityManager createEntityManager();
....

Solution

  • As i was debugging, found this methods in PersistenceExceptions class, which are from OpenJPA:

    @Override
    public RuntimeException translate(RuntimeException re) {
        return PersistenceExceptions.toPersistenceException(re);
    }
    

    this method translates caught RuntimeException, which is in question's case OpenJPA's UserException caused by SQLException, and then creates new PersistenceException based on it here and returns it:

    /**
     * Translate the given general exception.
     */
    private static Throwable translateGeneralException(OpenJPAException ke) {
       Exception e = new org.apache.openjpa.persistence.PersistenceException
            (ke.getMessage(), getNestedThrowables(ke),
                getFailedObject(ke), ke.isFatal());
        e.setStackTrace(ke.getStackTrace());
        return e;
    }
    

    As you can see creating new org.apache.openjpa.persistence.PersistenceException based on OpenJPAException values (and not itself) causes that it is not possible to retrieve lower cause.

    OpenJPA version 3.1.2