
Typesafe database interaction with Java 8 - benjiweber
http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-with-java-8/
======
falloutfar
Hi Benji, there is a way to avoid CGlib proxy for what you want to do. It's
clearly a hack but I think it's a better hack than using CGlib because it
doesn't require code generation.

By default, a method reference or a lambda doesn't carry a reflective
description of itself to be lightweight. This description is generated by the
compiler, pass to the metafactory but once the method reference object is
created the recipe of the method reference is lost. That is true but in one
case, if the lambda or the method reference is Serializable, in that case, the
recipe need to be kept in order that the runtime can deserialize the method
reference. There are several ways to force a method reference to be
serializable, the easiest way is to declare the functional interface that will
receive the method reference as inheriting from Serializable. This means you
can not use java.util.function.Function, you have to create your own interface
that inherits from Serializable. Once you have done that, you just have to
serialize the method reference to an array and deserialize it by hand to
extract the recipe. So the only thing you need is a code that simulate de-
serialization withtout using the classical ObjectInputStream of Java because
it will not let you sneak at the recipe. The code here [1], do what you want.

cheers,

[1]
[https://github.com/forax/jayspec/blob/master/jayspec/src/com...](https://github.com/forax/jayspec/blob/master/jayspec/src/com/github/forax/jayspec/SerializationDecoder.java)

------
mbell
This looks really nice.

I wish Java would do something about getters and setters. It's very awkward
that they are not incorporated into the language but so many libraries assume
they exist that it's a defacto requirement to generate the same boilerplate
constantly. I wish the language itself would provide default 'simple'
getters/setters the way Groovy does and incorporate them throughout so I could
use e.g.

    
    
        .set(Person::firstName)  //Reference a default setter method for the firstName member if one isn't explicitly defined 
    

instead of

    
    
        .set(Person::setFirstName)

~~~
ed_blackburn
As a C# developer I urge caution. When getters and setters become as trivial
as

public int Age { get; set; }

Code becomes less OO and more procedural filled with anaemic models / bags of
state. Practices like Tell don't Ask, Information Hiding and Rich Models, slip
away.

~~~
mbell
> Code becomes less OO

Frankly...good. If there is one thing Java desperately needs, it's less OO
code.

------
unclebucknasty
Sorry, but this is ugly. Reminds me a bit of entity beans and all of the extra
code hoops required in order to "automate" some functionality.

Here, we are really just using code declaratively, then doing extra work to
map, etc. Then, folding in CGLib too? And, given that the queries are written
in code, modifications to columns manipulated and so forth require re-
compilation anyway.

Accessing the DB is not rocket science. I am not sure why we find new ways to
complicate it so much. It is primarily just grunt work when done by hand. So,
I do understand the desire to avoid that part of it.

This being the case, I will stick with my homegrown code generation tools for
DB interfacing. Over the years, new tools have come and gone, which simply
seem to move the problems around (Hibernate, anyone?) And, during that time, I
haven't found anything simpler or more straightforward than a tool I wrote
over ten years ago to generate the (typesafe) base DAO layer from simple
queries.

~~~
edandersen
The problem with homegrown DB interfacing stuff is that no other developers
want to learn to use it, instead of standard using ORMs. Fine if you are a
lone wolf but using a 10 year old homemade DAO layer wouldn't fly in a team.

~~~
unclebucknasty
Perhaps, but I think that's actually part of the fallacy here. That is, this
mindset "let's all adopt and learn to use something obtuse and wildly overly-
complicated, so that it at least becomes a standard that we can use (and
further propagate) elsewhere." I noticed, for instance, that you didn't refute
the ugliness of the OP. Your reply instead seems to be saying, "at least we
can get the team to use it".

Now, this is really reminding me of EJB. Seriously, it's how we end up with
these insane "standards", the embrace of which is probably at least partly
responsible for Java's reputation as an inefficient language in which to
develop.

And, there are certainly ways to approach code generation in a team
environment, especially if the team was willing to put a fraction of the
effort into such an approach, as they would put into learning and maintaining
something like the OP. At the end of the day, you just need to get data in and
out of the DB. Whether it is ten years old or homegrown shouldn't matter so
much if it is clean, easily maintained, and efficient. Teams adopt project-
specific patterns all the time for other parts of development. Why not for the
DB access?

But, I just offered up my solution as a way to say that, in all of these
years, I have yet to see a truly attractive alternative to something homegrown
and "old". Many seem to agree as here we are with yet another proposal. But,
things seem to be getting worse, as the OP is an example that borders on
parody of previous offerings. Dynamic proxies and CGLib? Really?

When I read the title, I thought maybe someone had nailed it. But, we start
with ugly, somewhat declarative code that surfaces SQL syntax, pass around
some function names, throw in some mapping, get some dynamic proxies in the
mix and, oh yeah, you're also gonna need CGLib, etc. I literally thought it
was a joke. Then, I come here and the first comment is "This looks really
nice".

So, aside from what I have decided to do to solve the problem, I would just
ask why the OP approach should be considered a viable alternative and why we
favor coalescing around such complicated anti-patterns instead of guiding our
"teams" toward saner choices that work.

~~~
lukaseder
I can see what you mean and I think you have a couple of valid points there.
Developers tend to think that anything aged more than 5 years is automatically
"legacy", and thus very bad. They rewrite things from scratch with the next
fancy-tech-du-jour, just to make the exact same mistakes again.

I've worked on a medium-sized 12-year-old "legacy" E-Banking system and it was
just awesome to learn how the "old masters" had been coding so many years ago.

Nonetheless, JDBC is a low-level standard, JPA a high-level one. Both with
their merits. However, there _is_ room for a solution in between

> When I read the title, I thought maybe someone had nailed it.

If that's what you're after, then _do_ have a look at jOOQ:
[http://www.jooq.org](http://www.jooq.org)

~~~
unclebucknasty
> _They rewrite things from scratch with the next fancy-tech-du-jour, just to
> make the exact same mistakes again._

Exactly. That is certainly part of it. There is a tendancy to replace one
thing with another, simply because we can.

> _However, there is room for a solution in between_

Making improvements, abstracting ugly details, etc., can definitely be a good
thing and there are certainly projects that do this well. What I have learned
to dislike is "solutions" that make the problem worse and that abstract the
problem rather than the solution. The data access layer seems to suffer
disproportionately here. For instance, with the OP, we now we have ugly
database code with added layers. Over-engineering at its worst. Not sure why
we don't just ask the simple question: is this really the simplest, most
efficient, maintainable, way to do _x_?

jOOQ: thanks for the pointer. I will have a closer look, but at first blush,
it is quite a bit like what I wrote all of those years ago. Perhaps I should
have just pushed to standardize it. edandersen would have it on his resume,
and we wouldn't be having this discussion. ;)

~~~
lukaseder
> it is quite a bit like what I wrote all of those years ago. Perhaps I should
> have just pushed to standardize it. edandersen would have it on his resume,
> and we wouldn't be having this discussion. ;)

Could be. The idea isn't novel. But no one has (publicly) gone as far as jOOQ
before, from my marketing research. Here's what I mean by going "far":

[http://blog.jooq.org/2013/05/03/sql-query-transformation-
fun...](http://blog.jooq.org/2013/05/03/sql-query-transformation-fun-
predicates-with-row-value-expressions/)

------
zastrowm
As a .NET programmer, it's great to see the changes that are coming to Java.
Method references and lambdas should make for some really nice + typesafe
fluent apis.

Although waiting for Android to support the new features will still be a pain
(it just got support for 7 with the release of KitKat).

~~~
clhodapp
The Android tools now have essentially-fake support for Java 7. Basically,
they updated dx (the classfile-to-dex converter) to not throw exceptions
immediately upon encountering a v51-format (Java 7) classfile, but, rather, to
throw exceptions whenever such a file actually contains Java 7-specific
bytecode features (MethodHandles, InvokeDynamic, and related features). This
means that Android has support for the syntax-only features of Java 7 (the
ones implemented entirely upstream in javac), but falls short of implementing
any of the actually-interesting platform features that would have required
changes to the phone-side VM.

Edit: The reason I bring this up (apart from being a little bit sore about it,
personally), is that this means that Android is actually really far from Java
8 support, as these features were added in Java 7 at least partially to
facilitate lambda support in Java 8 (see
[http://cr.openjdk.java.net/~briangoetz/lambda/lambda-
transla...](http://cr.openjdk.java.net/~briangoetz/lambda/lambda-
translation.html)).

~~~
falloutfar
It's not as far as you think it is :) see
[https://bitbucket.org/jpilliet/android-292](https://bitbucket.org/jpilliet/android-292)

------
ZitchDog
This ends up looking a lot like JOOQ - but JOOQ doesn't require Java8

[http://www.jooq.org](http://www.jooq.org)

~~~
benjiweber
Indeed. JOOQ is nice. However, it does rely on code generation to do some of
the nicer things [http://www.jooq.org/doc/3.2/manual/code-
generation/](http://www.jooq.org/doc/3.2/manual/code-generation/)

Now that there are new language features it may not be required.

~~~
lukaseder
Many jOOQ users appreciate code generation for the simple reason to keep Java
code in sync with the database schema... This is crucial if you have 500+
tables with dozens of columns, each

------
revetkn
How does it handle operations more complex than "select * from user"? For
example, joins and subqueries. And wouldn't it be nicer to have the database
layer figure out properties for you instead of writing mapping code by hand?

For example (this uses SQL, I am not big on ORMs):

    
    
      User user = database.queryForObject("SELECT * FROM user WHERE user_id=?", User.class, userId);

~~~
lukaseder
This boils down to whether you prefer SQL to be an external or internal DSL in
your host environment.

External DSL = Actual target language, no simulation thereof, but String-
based, no typesafety, detached bind variables, SQL injection, etc.

Internal DSL = Typesafe, compiled, but only a simulation of the real language,
limited by the host language

~~~
revetkn
BTW, I just checked out jOOQ. I think you did a great job with it. This is the
first ORM I've seen that really embraces SQL. Nice work

~~~
lukaseder
Thanks. And it will stay that way. Unlike many competitor products, there are
no plans to support / unify any NoSQL, LDAP, or other data stores. If they
don't implement the SQL language first, they won't be integrated.

------
lukaseder
Congrats to your tool. Using method references is quite clever, reminds me of
a couple of tools that did something with instrumentation and advanced
reflection (cglib, I guess). These come to my mind:

OhmDB ([http://www.ohmdb.com](http://www.ohmdb.com))

LambdaJ
([https://code.google.com/p/lambdaj/](https://code.google.com/p/lambdaj/))

JaQu
([http://www.h2database.com/html/jaqu.html](http://www.h2database.com/html/jaqu.html))

JIRM, I think, also played around with similar ideas
([https://github.com/agentgt/jirm](https://github.com/agentgt/jirm))

Comparing this approach with jOOQ
([http://www.jooq.org](http://www.jooq.org)), I think that method references
might be somewhat limited in a SQL sense of thinking. How would you handle
aliases? E.g. how would you perform a self-join, such as:

    
    
        FROM person p1
        JOIN person p2 ON p1.parent_id = p2.id

------
batbomb
I wrote something in Java 7 I call zerorm that has some similar functionality.
The type safety is mostly optional, but it can be enforced in a few ways,
either through the compiler or at "bind time". It's similar to jOOq, korma,
etc... but one nice benefit is it doesn't try to do everything, it has no
dependencies, and the core part of the code is around 3k LoC IIRC.

[http://github.com/zerorm/zerorm](http://github.com/zerorm/zerorm)

~~~
lukaseder
From the GitHub docs:

    
    
        $( colName ) is also unsafe in the sense that whatever
        colName is will be thrown out directly to SQL. However,
        $$( colName ) is a bit safer because it removes double
        quotes and wraps the identifier 
    

Gotta love that :-) It's obviously safer, given the amount of $. What does
$$$( colName ) do?

~~~
batbomb
haha yeah. I'm not sold on that yet, it was a design decision I made so that I
personally could do some crazy things with column names. The lack of safety
would only come if you had a string that was somehow modifiable by a user and
that was to be used as a column name. So the $$ just means make the name use
ANSI quotes, instead of an unquoted identified (column name). The single $
lets users implement whatever they want for a column name, which is useful if
you want to keep a tiny library and not worry about database specific features
like functions, etc...

~~~
lukaseder
Yes, I agree, that is one way to solve this problem. Another would be to check
if the column name matches

    
    
        [A-Za-z_][A-Za-z_0-9]*
    

If not, then quote. Another reason to quote things is the madness around
various SQL dialect's understanding of case-insensitivity. When quoted, case-
sensitivity is enforced.

------
drdaeman
Is it a language- or platform-side feature? I mean, is this something that
needs additional support from JVM side or could be done on existing JVMs (i.e.
a compiler for Java 8 could be written that would produce code that'd run on
older JDK without need for upgrade)?

~~~
ZitchDog
It requires JDK 8 - but there is a project to backport the lambda syntax back
to Java 7:
[https://github.com/orfjackal/retrolambda](https://github.com/orfjackal/retrolambda)

------
ww520
I wrote something similar (Jsoda) for AWS's databases a while back,
[https://github.com/williamw520/jsoda](https://github.com/williamw520/jsoda).
It just uses plain Java.

------
mpweiher
Looks a lot like what was done in ROE or Gemstone, which both execute
blocks/lambdas against recording proxies and then translate the messages to DB
queries. (I did something similar with Higher Order Messages).

------
bsaul
I'm not a java expert, so i'm wondering : is the fact that this example still
has to rely on cglib a downside ?

~~~
lmm
Yes. If you're willing to use cglib or some other code generation (or
reflection) you can already achieve the same thing, and there are projects
like QueryDSL that do it.

