Re: Pre-processing during build

From: Christopher BROWN <brown(at)reflexe(dot)fr>
To: pgsql-jdbc(at)postgresql(dot)org
Subject: Re: Pre-processing during build
Date: 2015-06-18 12:27:18
Message-ID: CAHL_zcONo9VdYvB2UAcK2MYsKWiwOH01nKXROg1Zqm0PoJ6azg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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(at)lawinegevaar(dot)nl> wrote:

> On Wed, 17 Jun 2015 22:47:23 +0200, "Markus KARG" <markus(at)headcrashing(dot)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(at)postgresql(dot)org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-jdbc
>

In response to

Responses

Browse pgsql-jdbc by date

  From Date Subject
Next Message Vladimir Sitnikov 2015-06-18 12:38:08 Re: Pre-processing during build
Previous Message Giuseppe Sacco 2015-06-18 08:27:48 Re: Help Reviewing PR's