Переопределите метод ожидания в интерфейсе Java

я хотел бы использовать wait(int) как подпись метода в fluent API (используется для http://www.jooq.org). Цель состоит в том, чтобы иметь возможность создавать SQL-запросы, такие как этот пример:

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

полное FOR UPDATE спецификация синтаксиса предложения (по крайней мере, для Oracle) можно увидеть здесь:

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

С jOOQ, я очень хочу оставаться рядом с синтаксисом SQL. Поэтому я хотел бы иметь возможность моделировать вышеуказанное предложение SQL с помощью API jOOQ fluent следующим образом:

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

метод fetch используется для рендеринга базового объекта API как SQL и запуска оператора SQL против базы данных Oracle (или любой другой). Вышесказанное может быть юридически указано в интерфейсе:

/**
 * 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);

    // [...]
}

у меня есть некоторые сомнения по этому поводу, хотя, потому что есть риск столкновения с другим метод:

public class Object {
    // [...]

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

    // [...]
}

благодаря методу перегрузки (int и long аргументы), я действительно могу это сделать. Но я боюсь, что это может запутать пользователей и привести к ошибкам. Так что это было бы неправильно:

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

Итак, мои вопросы:

  1. могу ли я как-то предотвратить вызов/доступ Object.wait(long) altoghether? Я так не думаю, потому что это объявлено final но, может быть, кто-то знает трюк компилятора или что-то еще?
  2. у вас есть лучшая идея для моего дизайна API, кроме просто переименования метода в что-то глупое, как doWait(int) или WAIT(int)?

4 ответов


для этого требуется способ отключить Object метод. И главная причина, похоже, в том, что у него есть хороший имя, которое соответствовало бы целям проприетарного API.

во-первых, это противоречит всей идее наследования - как только вы наследуете от класса, все подклассы должны предоставлять одни и те же не частные поля и метод. Вы всегда можете переопределить метод, за исключением случаев (1), когда он помечен как final и (2) оно имеет несовместимой (не-ковариантные) возвращение тип, оба из которых истинны с void wait(long) метод.

кроме того, поскольку каждый объект является Object в Java, все должно иметь способ void wait(long) и не должно быть никакого способа скрыть/удалить/отключить/перенаправить / переопределить его. Предполагая, что можно скрыть void wait(long) метод, как бы вы могли его вызвать, если вы хотите его вызвать?

однако, предполагая, что вам никогда не понадобится вызывать void wait(long) для ваших конкретных классов всегда существует подход источник / байт-код плетение, что в AspectJ использует для внесения изменений в.байт-код класса Java на основе определенных правил вызова. Вы можете поймать каждый вызов wait(long) и объявить ошибку / предупреждение. Подробнее здесь: http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-decp.html

, собственный метод pointcuts невозможен даже с AspectJ с байт-кодом плетения. Скорее всего, это невозможно даже с ткачеством исходного кода - но, возможно, стоит попробовать.


вы можете попробовать использовать метод, который указывает как время, так и" условие " для ожидания. Детали реализации будут скрыты, но одной из возможных реализаций будет попытка немедленно выполнить действие и цикл, пока не будет выполнено указанное условие, с соответствующей паузой между попытками.

вот пример интерфейса на Condition Я использую себя (как вы можете видеть, это не должно быть сложным):

public interface Condition {
    public boolean met();
}

взлом вокруг с core Java ради DSL просто не является хорошей идеей.

Почему бы не сделать ваш DSL более выразительным?

Что означает wait(int n)? ждать N миллисекунд, секунд, минут?

лучшей подписью было бы:

wait (длинная продолжительность, java.утиль.параллельный.Timeunit / единицы){ ... }

который читает лучше, например:

подождите(30, timeunit / единицы.Миллисекунды)


void wait(long) является частью контракта, предлагаемого Object и поэтому его не следует изменять. Представьте, что кто-то хранит ваш объект и пытается использовать его для wait/notify нитку логики. Так что полностью изменить логику-это просто играть против правил. Поэтому вам придется придумать другое имя.

С другой стороны, кажется, что имея forUpdate параметр взятия показывая время ожидания приспособит счет. Вы можете просто иметь другую версию forUpdate В дополнение к существующему.