If we were implementing all of this now, we would not separate AutoloadedDriver from EmbeddedDriver. But Derby co-evolved with the JDK from the start. By the time that Java introduced driver autoloading, we already had legacy customers whose applications we did not want to disturb. We did not completely achieve that goal, but we tried.

Class.forName("org.apache.derby.jdbc.EmbeddedDriver" ) boots the Derby engine, loading its classes into memory. Some legacy applications came to expect this side-effect. However, we did not want to boot the Derby engine and incur all of that classloading as a side-effect of an application trying to connect to another vendor's database driver. That is what would have happened had derby.jar designated EmbeddedDriver as the autoloaded driver. So we created a new, largely vacuous placeholder driver, the AutoloadedDriver, which does NOT boot the Derby engine as a side-effect of simply being faulted into a classloader. That is the driver which derby.jar designates as Derby's autoloaded driver.

This is a great deal of complexity for something which ought to be very straightforward, but it is the cost we paid to keep abreast of an evolving JDBC interface while maintaining backward compatibility.

Hope this helps,
-Rick

On 7/8/20 4:50 PM, Russell Bateman wrote:
The mock driver supports a sort of bogus URL ("jdbc:mock") that it recognizes for its purpose which is only to respond to a single query with canned data (whereas I'll be able to populate Derby with as much and whatever data I ever want). Of course, its driver doesn't ever do anything "real," though it supports a few metadata methods (and the MockConnectionimplements Connectionand supports a whole pile of methods that stub out most actions and unimaginatively return the canned data).

Yes, your suggestion #3 works well and solves that particular problem of an empty driver list. (The list is empty instead of containing the mock driver because I separated the packages. DriverManagerdoes some reflection desperately looking for classes that might have drivers.) The list now has the Derby driver in it:

Down inside DriverManager's private getConnection(), walking the driver list using the IntelliJ IDEA debugger, I see:

   *aDriver* = {DriverInfo@2097}
"driver[className=org.apache.derby.jdbc.*AutoloadedDriver*@6bb4dd34]"
   *con* = {EmbeddedConnection@2585}
   "org.apache.derby.impl.jdbc.*EmbedConnection*@1414013111 (XID =
   164), (SESSIONID = 1), (DATABASE = memory:sys), (DRDAID = null) "

I have to admit that I'm not to the point yet where I grok why I'm seeing AutoloadedDriverwhen I forced Java to verify EmbeddedDriver. I got no errors doing that; I did it just before making the call to getConnection():

   Class.forName( "org.apache.derby.jdbc.EmbeddedDriver" );
   DriverManager.getConnection(
   "jdbc:derby:memory:sampledb;created=true", "sa", "sa" );

I have learned a great deal more about JDBC drivers than I had planned thanks to deciding to use Derby, replacing this old test mock and with your help which I hugely appreciate!

Russ


On 7/8/20 5:15 PM, Rick Hillegas wrote:
It's hard to say what's going on, but the instability in your experiments is hard to reconcile against the deterministic code paths involved in JDBC autoloading.

I can only speculate about what is causing this instability:

1) What JDBC URLs does your MockDriver claim to support?

2) Is something tricky being done to the classpath, creating a situation in which the Derby jars are not visible when you invoke DriverManager.getConnection()?

3) What happens when you do a Class.forName("org.apache.derby.jdbc.EmbeddedDriver")? What are the chain of errors raised? For the record, this is the recommended JDBC way to fault in a driver which was missed at autoloading time. Autoloading occurs on the very first call to DriverManager.getConnection() during the lifetime of the JVM.

Hope this helps,
-Rick

On 7/8/20 10:37 AM, Russell Bateman wrote:
...again, don't know what I changed.* I'm only depending on /derby-10.15.2.0.jar/.

What I think is going on is an artifact of being side-by-side with another JDBC driver implementation.

I was hoping to keep the original mocked test driver working alongside the Derby implementation at least until I'm able to abolish it in every case. Just as used to be the case, it's registered thus:

    DriverManager.registerDriver( new MockDriver() );

However, this is not how it works for Derby. It just happens on the basis of having the JAR linked (in /pom.xml/). The problem comes that, because the MockDriveris explicitly registered, when we go to create a Derby connection:

    java.sql.Connection connection = DriverManager.getConnection( "jdbc:derby:memory:sampledb;create=true" );

...DriverManagertakes as license to create an instance of the old test mock because that is the (only) driver in its registeredDriverslist. *I moved the Derby-based code out of the same Java package to solve this?

Thanks again. I'm sorry for having made this annoying.

Russ







Reply via email to