Bug 150295 - JDBC exception stack trace lost
Summary: JDBC exception stack trace lost
Status: RESOLVED INSUFFICIENTDATA
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: Base (show other bugs)
Version:
(earliest affected)
7.0.4.2 release
Hardware: All All
: medium normal
Assignee: Not Assigned
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: Database-Connectivity
  Show dependency treegraph
 
Reported: 2022-08-07 23:51 UTC by Jan Michael Greiner
Modified: 2023-12-28 03:11 UTC (History)
2 users (show)

See Also:
Crash report or crash signature:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Michael Greiner 2022-08-07 23:51:01 UTC
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;
    }

}
Comment 1 Stéphane Guillou (stragu) 2023-05-30 17:29:07 UTC
Could you please test version 7.5, which is currently supported?
It would also help if you could attach files that make it easier for us to test the issue.
Thank you!
Comment 2 QA Administrators 2023-11-27 03:12:40 UTC Comment hidden (obsolete)
Comment 3 QA Administrators 2023-12-28 03:11:11 UTC
Dear Jan Michael Greiner,

Please read this message in its entirety before proceeding.

Your bug report is being closed as INSUFFICIENTDATA due to inactivity and
a lack of information which is needed in order to accurately
reproduce and confirm the problem. We encourage you to retest
your bug against the latest release. If the issue is still
present in the latest stable release, we need the following
information (please ignore any that you've already provided):

a) Provide details of your system including your operating
   system and the latest version of LibreOffice that you have
   confirmed the bug to be present

b) Provide easy to reproduce steps – the simpler the better

c) Provide any test case(s) which will help us confirm the problem

d) Provide screenshots of the problem if you think it might help

e) Read all comments and provide any requested information

Once all of this is done, please set the bug back to UNCONFIRMED
and we will attempt to reproduce the issue. Please do not:

a) respond via email 

b) update the version field in the bug or any of the other details
   on the top section of our bug tracker

Warm Regards,
QA Team

MassPing-NeedInfo-FollowUp