Re: Pre-processing during build - Mailing list pgsql-jdbc

From Christopher BROWN
Subject Re: Pre-processing during build
Date
Msg-id CAHL_zcONo9VdYvB2UAcK2MYsKWiwOH01nKXROg1Zqm0PoJ6azg@mail.gmail.com
Whole thread Raw
In response to Re: Pre-processing during build  (Mark Rotteveel <mark@lawinegevaar.nl>)
Responses Re: Pre-processing during build  (Vladimir Sitnikov <sitnikov.vladimir@gmail.com>)
Re: Pre-processing during build  ("Markus KARG" <markus@headcrashing.eu>)
List pgsql-jdbc
The entry point into a JDBC driver is, unsurprisingly, its implementation of java.sql.Driver (and javax.sql.DataSource if you want).  These are very straightforward and stable interfaces (there's only a new "getParentLogger()" method in 1.7), and they act as factories providing access to Connection objects.  Implementations of Driver, given that they are just factories for Connection objects, should never be on a critical performance path.

I see nothing wrong with implementing Driver using java.reflect.Proxy, and if we want to be paranoid about classloading, using reflection (within the implementation of the Proxy-based Driver) to instantiate and invoke methods on a version-specific implementation of Driver.  That way, even when using reflection, discovering an "unresolvable future type" is just impossible.  The Proxy-based Driver would delegate to some PGDriver6 / PGDriver7 / PGDriver8 which could be compiled in steps (as I described in an earlier message on this thread) and not to some PGSuperDriver, where PGDriver8 extends PGDriver7, and PGDriver7 extends PGDriver6, and where PGDriver8 returns (from the "connect" method) a PGConnection8 (extending PGConnection7), PGDriver7 returns PGConnection7, and so on.  So, even using reflection, it would be impossible to work with mismatched versions; the only exception being (for example in Java6 code) doing an explicit Class.forName("PGDriver8") but that sort of code just isn't possible except when the client is incompetent or malicious.  And, as I suggested in my previous message, it requires no code generation, just an extra compilation step per supported version.

As a side note, about the discussion on interpretations of the JLS, I've not yet encountered any JVM that attempts to fully-resolve all signatures as soon as it loads a class.  Does such a JVM exist?  I would assume that it would have poor performance for classloading (and a high memory overhead for class metadata, such as permgen/metaspace usage) because it would need to be recursive (for each type discovered in a method signature or body, it would need to load that type and all of its referenced types, recursively).  I'd be very interested to know how it deals with circular references (for example A refers to B and vice-versa ; it can't resolve A before B, and vice-versa), such as Object.toString() because String can't be loaded before Object, but Object would need to resolve String.

Getting back to the original discussion, I'm neutral on the Ant vs Maven debate, but it I'm sure that driver developers would benefit (readability and reliability) from plain old source code, simple class extending and step-by-step compilation to handle API evolution without trying relying on JVM behavior to have an all-in-one single implementation that may contain more than is advertised by specific interface versions.  This approach should also keep the build process deterministic and relatively straightforward and be able to produce a single driver artifact compatible with all JDBC versions, with no burden on driver users.

Hope that helps,
Christopher


On 18 June 2015 at 08:31, Mark Rotteveel <mark@lawinegevaar.nl> wrote:
On Wed, 17 Jun 2015 22:47:23 +0200, "Markus KARG" <markus@headcrashing.eu>
wrote:
> Sorry but you're wrong here.
>
> Vladimir's example was invalid. See
> https://gist.github.com/mkarg/88a89ae0dbffcfb7543e instead.
>
> Resolution will not fail. Even early static resolution won't. Check
again
> the chapter of JLS about the critera to throw the listed exceptions.
None
> of them is met with the corrected example
> https://gist.github.com/mkarg/88a89ae0dbffcfb7543e.
>
> The direct example will NOT fail on Java 7 as the method is not changed,
> but added. The original method is still in place. Both methods exist at
the
> same time and differ by signature, hence the linker of the old program
> finds the old method in the new class. No problem at all.
>
> The indirect example will NOT fail on Java 7 as a JRE 7 client will
never
> pass in an instance of a JRE 8 type (how should even know of its
> existence?), and the Java 6 machine executing the invoked method will
never
> INSTANTIATE that type so it will not fail. No problem at all.
>
> Still should work. You'd possibly like to set up a proof using the
> corrected example https://gist.github.com/mkarg/88a89ae0dbffcfb7543e.
:-)

Sorry, but you're the one that is wrong, it is not only about actually
calling methods with types, it is about the presence or absence of those
types when the JVM does decide to resolve the symbolic reference (eg when
you reflect the declared methods). I am about done with this discussion. I
think the onus is on you to prove this scheme will work, not for us to
prove it won't work (which we already did). Your prove should not only
include simple direct instance access, but also when using reflection
**which is very common with JDBC drivers** (eg connection pools,
tools/libraries that bridge differences in JDBC implementations, etc).

It sounds like you want to trade minor complexity in the build/IDE process
for a world of hurt for the users of your driver. I don't think that is a
good way forward.

Mark


--
Sent via pgsql-jdbc mailing list (pgsql-jdbc@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-jdbc

pgsql-jdbc by date:

Previous
From: Giuseppe Sacco
Date:
Subject: Re: Help Reviewing PR's
Next
From: Vladimir Sitnikov
Date:
Subject: Re: Pre-processing during build