在Java接口中重新定义等待方法

发布于 2024-11-16 06:04:38 字数 2596 浏览 0 评论 0原文

我想使用 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 } ]

完整 oracle.com/docs/cd/B28359_01/server.111/b28286/img_text/for_update_clause.htm" rel="nofollow">http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/img_text/for_update_clause.htm

使用jOOQ,我真的很想接近SQL语法。因此,我希望能够使用 jOOQ Fluent API 对上述 SQL 子句进行建模,如下所示:

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,并针对 Oracle(或任何其他)数据库运行 SQL 语句。上面的内容可以在接口中合法地指定:

/**
 * 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 vs. long 参数),我实际上可以做到这一点。但我担心这可能会让我的用户感到困惑并导致错误。所以这是错误的:

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

所以我的问题是:

  1. 我可以以某种方式阻止调用/访问 Object.wait(long) 吗?我不这么认为,因为它被声明为最终的,但也许有人知道编译器技巧,或者其他什么?
  2. 除了将方法重命名为像 doWait(int)WAIT(int) 这样愚蠢的名称之外,您对我的 API 设计还有更好的想法吗?

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)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

嗳卜坏 2024-11-23 06:04:38

您可以尝试改用 waitFor 方法,该方法指定要等待的时间和“条件”。实现细节将被隐藏,但一种可能的实现是立即尝试您的操作并循环,直到满足指定的条件,并在尝试之间适当暂停。

这是我自己使用的 Condition 的示例接口(如您所见,它不需要很复杂):

public interface Condition {
    public boolean met();
}

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();
}
孤芳又自赏 2024-11-23 06:04:38

void wait(long)Object 提供的合约的一部分,因此不应更改。想象一下,有人存储您的对象并尝试将其用于等待/通知线程逻辑。所以完全改变它的逻辑就是违反规则。所以你必须想出不同的名字。

另一方面,似乎让 forUpdate 接受指示等待时间的参数将符合要求。除了现有版本之外,您还可以拥有另一个版本的 forUpdate

void wait(long) is a part of the contract offered by Object and therefore it should not be changed. Imagine that someone stores your object and attempts to use it for wait/notify threading logic. So completely changing it's logic is just playing against the rules. So you will have to come up with different name.

On the other hand, it seems that having forUpdate take parameter indicating wait time will fit the bill. You could just have another version of forUpdate in addition to existing one.

南街九尾狐 2024-11-23 06:04:38

这需要一种禁用 Object 方法的方法。主要原因似乎是因为它有一个名称,适合专有 API 的用途。

首先,这与继承的整个概念相矛盾——一旦从一个类继承,所有子类都必须公开相同的非私有字段和私有字段。方法。您始终可以重写方法,除非 (1) 它被标记为 final 并且 (2) 它具有不兼容(非协变)的返回类型,这两种情况对于 都是正确的void wait(long) 方法。

此外,由于Java中每个对象都是一个Object,所以所有东西都必须有一个方法void wait(long),并且不应该有办法隐藏/删除/禁用/转发/覆盖它。假设可以隐藏 void wait(long) 方法,您将如何调用它?您是否希望调用它?

但是,假设您永远不需要为特定类调用 void wait(long),则 AspectJ 始终使用按顺序使用的源代码/字节代码编织方法根据某些调用规则更改 .class Java 字节码。您可以捕获对 wait(long) 的每次调用并声明错误/警告。在此处查看更多信息: http://www.eclipse.org/aspectj /doc/released/adk15notebook/annotations-decp.html

但是,即使使用具有字节码编织的 AspectJ,本机方法切入点也是不可能的。即使使用源代码编织,这很可能也是不可能的——但可能值得一试。

What this requires is a way to disable an Object method. And main reason seems to be because it has a nice name that would fit the purposes of a proprietary API.

At first, this contradicts the entire idea of inheritance -- once you inherit from a class, all subclasses must expose the same non-private fields & method. You can always override a method, except when (1) it is marked as final and (2) it has an incompatible (non-covariant) return type, both of which are true with the void wait(long) method.

Furthermore, since every object is an Object in Java, everything must have a method void wait(long) and there should be no way to hide/delete/disable/forward/override it. Assuming it were possible to hide the void wait(long) method, how would you go about invoking it, should you wish to invoke it?

However, assuming you would never need to invoke void wait(long) for your particular classes, there is always the approach of source/byte-code weaving that AspectJ uses in order to make changes to the .class Java bytecode based on certain invocation rules. You could trap every call to wait(long) and declare an error/warning. See more here: http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-decp.html

However, native method pointcuts are not possible even with AspectJ with byte-code weaving. Most likely, this is not possible even with source-code weaving -- but it might be worth a try.

第几種人 2024-11-23 06:04:38

为了 DSL 而使用核心 Java 根本不是一个好主意。

为什么不让你的 DSL 更具表现力呢?

wait(int n) 到底是什么意思?等待N毫秒、秒、分钟?

更好的签名是:

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

读起来更好,例如:

wait(30, TimeUnit.MILLISECONDS)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文