https://bugs.documentfoundation.org/show_bug.cgi?id=150295

            Bug ID: 150295
           Summary: JDBC exception details lost
           Product: LibreOffice
           Version: 7.0.4.2 release
          Hardware: All
                OS: All
            Status: UNCONFIRMED
          Severity: normal
          Priority: medium
         Component: Base
          Assignee: [email protected]
          Reporter: [email protected]

Description:
I am working on a JDBC driver to access CardDAV addresses on a Nextcloud
server.
In the development my code produced a NullPointerException. In LibreOffice Base
there is an error message about a NullPointerException. But what is missing is
the Java stack trace (where in the Java code the NullPointerException has
happened).

Steps to Reproduce:
1. Create a buggy JDBC driver
1a. Compile class Driver, see code below (with javac -d classes
de/greinerinformatik/carddavjdbc/Driver)
(-d classes denotes the target directory)
1.b Create a text file classes/META-INF/services/java.sql.driver containing the
line
de.greinerinformatik.CardDAVxJDBC
1c. (optionally? ...maybe also works by working directly with the classes
directory) create a jar file from the classes directory
2. Register the JDBC driver in LibreOffice: Tools -> Options -> Extended ->
Class Path...
3. Create a odb file with JDBC Database jdbc:CardDAV:Ray
4. Click on tables, and the NullPointerException will come up. You will not see
the stack trace, where in the Java code the Exception occured.

Actual Results:
No stack trace from the Java JDBC code is available.

Expected Results:
The stack trace from Java should be available somewhere, in the error dialog,
or in the console output, to help debug the JDBC driver code.


Reproducible: Always


User Profile Reset: Yes



Additional Info:
package de.greinerinformatik.carddavjdbc;

import java.sql.Connection;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.Properties;

import java.io.IOException;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class Driver implements java.sql.Driver {

    private static Driver registeredDriver;
    private static final Logger PARENT_LOGGER =
Logger.getLogger("de.greinerinformatik.CardDAVxJDBC");
    private static final Logger LOGGER =
Logger.getLogger("de.greinerinformatik.CardDAVxJDBC.Driver");

    static {
        try {
            FileHandler fileHandler;
            try {
                fileHandler = new FileHandler("%t/CardDAV_%g.log", 10000, 5,
true);
                fileHandler.setEncoding("UTF8");
            } catch (IOException ioe) {
                throw new SQLException("Error creating logging FileHandler for
TEMP dir CardDAV_n.log.", ioe);
            }
            fileHandler.setLevel(Level.FINEST);
            fileHandler.setFormatter(new SimpleFormatter());
            fileHandler.publish(new LogRecord(Level.SEVERE, "Test"));
            LOGGER.addHandler(fileHandler);
            LOGGER.setLevel(Level.FINEST);
            LOGGER.log(Level.FINE, "Register database driver for
'jdbc:CardDAV:'.");
            register();
        } catch (SQLException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private class ConnectionInfo {

        Properties info;

        public ConnectionInfo(String url, Properties info) {
            if (info.getProperty("David") != null) {
                this.info = info;
            }
        }

        public String getName() {
            return info.getProperty("name");
        }
    }

    private class CardDAVConnection implements Connection {

        @Override
        public Statement createStatement() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public PreparedStatement prepareStatement(String sql) throws
SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public CallableStatement prepareCall(String sql) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public String nativeSQL(String sql) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setAutoCommit(boolean autoCommit) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public boolean getAutoCommit() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void commit() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void rollback() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void close() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public boolean isClosed() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public DatabaseMetaData getMetaData() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setReadOnly(boolean readOnly) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public boolean isReadOnly() throws SQLException {
            return true;
        }

        @Override
        public void setCatalog(String catalog) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public String getCatalog() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setTransactionIsolation(int level) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getTransactionIsolation() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public SQLWarning getWarnings() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void clearWarnings() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Statement createStatement(int resultSetType, int
resultSetConcurrency) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public PreparedStatement prepareStatement(String sql, int
resultSetType, int resultSetConcurrency) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public CallableStatement prepareCall(String sql, int resultSetType, int
resultSetConcurrency) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Map<String, Class<?>> getTypeMap() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setHoldability(int holdability) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getHoldability() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Savepoint setSavepoint() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Savepoint setSavepoint(String name) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void rollback(Savepoint savepoint) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void releaseSavepoint(Savepoint savepoint) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Statement createStatement(int resultSetType, int
resultSetConcurrency, int resultSetHoldability) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public PreparedStatement prepareStatement(String string, int
resultSetType, int resultSetConcurrency, int resultSetHoldability) throws
SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public CallableStatement prepareCall(String string, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public PreparedStatement prepareStatement(String string, int
autoGeneratedKeys) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public PreparedStatement prepareStatement(String string, int[]
columnIndexes) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public PreparedStatement prepareStatement(String string, String[]
columnNames) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Clob createClob() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Blob createBlob() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public NClob createNClob() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public SQLXML createSQLXML() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public boolean isValid(int timeout) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setClientInfo(String name, String value) throws
SQLClientInfoException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setClientInfo(Properties properties) throws
SQLClientInfoException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public String getClientInfo(String name) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Properties getClientInfo() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Array createArrayOf(String typeName, Object[] elements) throws
SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Struct createStruct(String typeName, Object[] attributes) throws
SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setSchema(String schema) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public String getSchema() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void abort(Executor exctr) throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void setNetworkTimeout(Executor executor, int milliseconds)
throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getNetworkTimeout() throws SQLException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public <T> T unwrap(Class<T> type) throws SQLException {
            throw new SQLException("This class is not a wrapper.");
        }

        @Override
        public boolean isWrapperFor(Class<?> type) throws SQLException {
            return false;
        }
    }

    @Override
    public Connection connect(String url, Properties info) throws SQLException
{
        LOGGER.log(Level.FINE, "Connecting with URL: {0}", url);
        ConnectionInfo ci = new ConnectionInfo(url, info);
        LOGGER.log(Level.FINE, "User name: {0}", ci.getName());
        return new CardDAVConnection();
    }

    @Override
    public boolean acceptsURL(String url) {
        LOGGER.log(Level.FINE, "Checking URL: {0}", url);
        return url.toLowerCase().startsWith("jdbc:carddav:");
    }

    @Override
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
throws SQLException {
        LOGGER.log(Level.FINE, "getPropertyInfo URL: {0}", url);
        if (info == null) {
            throw new SQLException("info may be empty, but must not be null.");
        }
        return new DriverPropertyInfo[0];
    }

    @Override
    public int getMajorVersion() {
        return 0;
    }

    @Override
    public int getMinorVersion() {
        return 1;
    }

    @Override
    public boolean jdbcCompliant() {
        return false;
    }

    @Override
    public java.util.logging.Logger getParentLogger() {
        return PARENT_LOGGER;
    }

    /**
     * Register the driver against {@link DriverManager}. This is done
     * automatically when the class is loaded. Dropping the driver from
     * DriverManager's list is possible using {@link #deregister()} method.
     *
     * @throws IllegalStateException if the driver is already registered
     * @throws SQLException if registering the driver fails
     */
    public static void register() throws SQLException {
        if (isRegistered()) {
            throw new IllegalStateException(
                    "Driver is already registered. It can only be registered
once.");
        }
        Driver registeredDriver = new Driver();
        DriverManager.registerDriver(registeredDriver);
        Driver.registeredDriver = registeredDriver;
    }

    /**
     * According to JDBC specification, this driver is registered against
     * {@link DriverManager} when the class is loaded. To avoid leaks, this
     * method allow unregistering the driver so that the class can be gc'ed if
     * necessary.
     *
     * @throws IllegalStateException if the driver is not registered
     * @throws SQLException if deregistering the driver fails
     */
    public static void deregister() throws SQLException {
        if (registeredDriver == null) {
            throw new IllegalStateException(
                    "Driver is not registered (or it has not been registered
using Driver.register() method)");
        }
        DriverManager.deregisterDriver(registeredDriver);
        registeredDriver = null;
    }

    /**
     * @return {@code true} if the driver is registered against
     * {@link DriverManager}
     */
    public static boolean isRegistered() {
        return registeredDriver != null;
    }

}

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to