Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-define wait method in a Java interface

I would like to use wait(int) as the signature of a method in a fluent API (used for http://www.jooq.org). The goal is to be able to construct SQL queries like this example:

SELECT * FROM T_AUTHOR
WHERE ROWNUM <= 1
FOR UPDATE OF FIRST_NAME, LAST_NAME
WAIT 5

The full FOR UPDATE clause syntax specification (at least for Oracle) can be seen here:

FOR UPDATE [ OF [ [ schema. ] { table | view } . ] column
             [, [ [ schema. ] { table | view } . ] column]...]
[ { NOWAIT | WAIT integer | SKIP LOCKED } ]

http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/img_text/for_update_clause.htm

With jOOQ, I really want to stay close to the SQL syntax. So I'd like to be able to model the above SQL clause with the jOOQ fluent API like this:

Result<Record> result = create.select()
                              .from(T_AUTHOR)
                              .limit(1)
                              .forUpdate()
                              .of(FIRST_NAME, LAST_NAME)
                              .wait(5) // Here's the issue
                              .fetch();

The fetch method is used to render the API's underlying object as SQL and run the SQL statement against an Oracle (or any other) database. The above can be legally specified in an interface:

/**
 * A type that models a "step" in the creation of a query using the fluent API
 */
public interface SelectForUpdateWaitStep extends SelectFinalStep {
    // [...]

    /**
     * Add a "FOR UPDATE .. WAIT n" clause to the query
     */
    SelectFinalStep wait(int seconds);

    // [...]
}

I have some doubts about this, though, because there is a risk of collision with another method:

public class Object {
    // [...]

    public final native void wait(long timeout) throws InterruptedException;

    // [...]
}

Thanks to method-overloading (int vs. long arguments), I can actually do this. But I'm afraid it might confuse my users and lead to mistakes. So this would be wrong:

                              .forUpdate()
                              .of(FIRST_NAME, LAST_NAME)
                              .wait((long) 5) // This doesn't make sense
                              .fetch();       // This doesn't compile

So my questions are:

  1. Can I somehow prevent calling/accessing Object.wait(long) altoghether? I don't think so because it's declared final but maybe someone knows a compiler-trick, or something else?
  2. Do you have a better idea for my API design apart from just renaming the method to something silly like doWait(int) or WAIT(int)?
like image 729
Lukas Eder Avatar asked Jun 18 '11 20:06

Lukas Eder


2 Answers

You might try using a waitFor method instead, which specifies both a time and a "condition" to wait for. The implementation detail would be hidden, but one possible implementation would be to try your action immediately and loop until the specified condition has been met, with an appropriate pause between attempts.

Here's a sample interface for a Condition I use myself (as you can see, it doesn't need to be complex):

public interface Condition {
    public boolean met();
}
like image 51
Ben Hocking Avatar answered Sep 20 '22 01:09

Ben Hocking


Hacking around with core Java for the sake of DSL is simply not a good idea.

Why not make your DSL more expressive?

What does wait(int n) mean anyway? wait for N milliseconds, seconds, minutes?

A better signature would be:

wait(long duration, java.util.concurrent.TimeUnit){ ... }

which reads better, for example:

wait(30, TimeUnit.MILLISECONDS)

like image 40
earcam Avatar answered Sep 22 '22 01:09

earcam