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; } }
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!
Dear Jan Michael Greiner, This bug has been in NEEDINFO status with no change for at least 6 months. Please provide the requested information as soon as possible and mark the bug as UNCONFIRMED. Due to regular bug tracker maintenance, if the bug is still in NEEDINFO status with no change in 30 days the QA team will close the bug as INSUFFICIENTDATA due to lack of needed information. For more information about our NEEDINFO policy please read the wiki located here: https://wiki.documentfoundation.org/QA/Bugzilla/Fields/Status/NEEDINFO If you have already provided the requested information, please mark the bug as UNCONFIRMED so that the QA team knows that the bug is ready to be confirmed. Thank you for helping us make LibreOffice even better for everyone! Warm Regards, QA Team MassPing-NeedInfo-Ping
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