Java 泄漏抽象检查器

发布于 2024-07-13 21:53:27 字数 830 浏览 12 评论 0原文

我正在考虑编写一个程序来检查 Java 中的“抽象泄漏”。 立即浮现在脑海中的一个领域是例外情况:

public class X
{
    // this one is fine, Readers throw IOExceptions so it is 
    // reasonable for the caller to handle it
    public void parse(final Reader r)
        throws IOException
    {
    }

    // This one is bad.  Nothing in the API indicate that JDBC 
    // is being used at all.
    public void process()
        throws SQLException
    {       
    }
}

注意,我不想就已检查/未检查异常的相对优点进行争论。 我正在寻找的是人们拥有的其他示例(不一定是异常处理),这些示例也可以通过检查源代码或类文件来合理捕获。

我知道 checkstyle、findbugs 和 PMD,据我所知,它们都没有处理这个问题(而且我并不反对将检查放入其中一个工具中,而不是编写自己的工具)。

您是否想到了其他可以静态检查的泄漏抽象示例?

编辑:

第二个不好的原因是该方法抛出异常,客户端无法知道正在使用 JDBC(例如,它可以是任何东西)。 所以“抽象泄漏”是使用了 JDBC。 如果底层机制更改为其他内容(例如 JPA,这是一个不同的数据库抽象库),那么所有异常也都需要更改。 所以底层数据库正在被泄露。

I am mulling over the idea of writing a program to check for
"leaky abstractions" in Java. The one area that popped into mind right away is with exceptions:

public class X
{
    // this one is fine, Readers throw IOExceptions so it is 
    // reasonable for the caller to handle it
    public void parse(final Reader r)
        throws IOException
    {
    }

    // This one is bad.  Nothing in the API indicate that JDBC 
    // is being used at all.
    public void process()
        throws SQLException
    {       
    }
}

Note, I do not want an argument on relative merits of checked/unchecked exceptions. What I am looking for is other examples (doesn't have to be exception handling) that people have that could also be reasonably caught via examining the source code or class files.

I am aware of checkstyle, findbugs, and PMD, and AFAIK none of them deal with this (and I am not opposed to putting the checks into one of those tools rather than write my own).

Are there any other examples of leaky abstractions that you come to mind that could be statically check for?

EDIT:

The reason why the second one is bad is that the method throws an exception where the client has no way of knowing that JDBC (for example, it could be anything) is being used. So the "leaky abstraction" is that JDBC is being used. If the underlying mechanism changed to soemthing else (say JPA which is a different database abstraction library) then the exceptions would all need to change as well. So the underlying database library is being leaked out.

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

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

发布评论

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

评论(4

迷你仙 2024-07-20 21:53:27

所以。

如何检测 API 是否泄漏实现细节或未保持相同的抽象级别。

您可能会观看此演讲。 它解释了良好的 API 的外观和设计方式(您可以从良好实践中推断出哪些是不良实践)

例如

功能应该易于解释。
如果它是一个硬名称,那么通常是一个糟糕的设计。

从中您可以发现,如果方法或返回参数给出了详细说明,则它们与抽象级别不符。

例如,高级方法

 -initProcess(): SGN_MTL

可能会泄漏返回值的实现细节。

这里的困难部分是检测抽象级别何时发生变化。

例如,在您的方法中,如果代码本身是 JDCB 层的实现,则可以抛出 SQLException。

您可以通过此列表查看更多此类主题的其他来源。
http://www.jetbrains.com/idea/documentation/inspections.jsp

请参阅“抽象”下的项目,即。

  • 具体类的实例变量:当实例变量的类型被声明为具体类而不是接口时报告。

经典的例子是:

 private ArrayList list;

什么时候会更好

 private List list;

So.

How to detect if an API leaks implementation details or does not keep the same level of abstraction.

You may probably watch the this talk. It explains how good APIs look like and are designed ( you can deduct from the good practices what are the bad practices )

For instance

Functionality should be easy to explain.
If its a hard name it's generally a bad design.

From that you could discover, if the methods or return parameters give detail instructions they are not along with the level of abstraction.

For instance a high level method

 -initProcess(): SGN_MTL

May be leaking implemntation details on the return value.

The hard part here is to detect when the level of abstraction changes.

For instance in your method it would be ok to throw SQLExceptions all around if the code it self is the implementation of the JDCB layer.

Other source where you can see more of these topics is this list.
http://www.jetbrains.com/idea/documentation/inspections.jsp

See the items under "Abstraction" ie.

  • Instance variable of concrete class: Report when the type of an instance variable is declared as a concrete class rather than an interface.

The classic example is:

 private ArrayList list;

when it will be better

 private List list;
秋日私语 2024-07-20 21:53:27

由于我在原帖中没有发现问题,所以我会闲聊。

任何这样的工具都必须让用户告诉它对于给定的类来说哪些异常符合非泄漏的条件,而任何不在这样的列表中的异常都将是泄漏。

那只是例外。 据我了解,泄漏抽象适用于更多的情况。 考虑一下:

class Client
{
    private Integer ID;

    public Integer ID() { return this.ID; }
}

这是否属于泄漏? 如果以后我需要将 ID 表示为 Long,那么就可以了。 您可以修复这样的场景:

class Client
{
    private ClientID ID;

    public ClientID ID() { return this.ID; }
}

class ClientID
{
    private Integer value;

    public ClientID(String id) { this.value = Integer.parseInt(id); }

    public String asString() { return value.toString(); }

    ... other methods that don't reveal value's type here ...
}

这将解决客户端的泄漏问题,但现在您将在 ClientID 上运行工具。 是否漏水?

如果您必须检查不是简单 getter 的方法,这可能会变得更加复杂。 如果 ClientID 有一个方法对其 ID 进行一些数学运算(纵容我)并返回一个 Integer,会怎样? 这是泄漏吗? 这是否符合泄漏该值是整数的条件?

所以我不确定这是否是机器可以轻易捕捉到的代码味道。

Since I didn't detect a question in the original post, I will ramble.

Any such tool would have to have the user tell it what exceptions qualify as non-leaks for a given class, and anything not on such a list would be a leak.

That's just exceptions. As I understand it, leaky abstractions apply to much more. Consider this:

class Client
{
    private Integer ID;

    public Integer ID() { return this.ID; }
}

Does this qualify as a leak? If later I needed to represent ID as Long, then it does. You might fix such a scenario like this:

class Client
{
    private ClientID ID;

    public ClientID ID() { return this.ID; }
}

class ClientID
{
    private Integer value;

    public ClientID(String id) { this.value = Integer.parseInt(id); }

    public String asString() { return value.toString(); }

    ... other methods that don't reveal value's type here ...
}

This would solve the leak out of Client, but now you'd run your tool on ClientID. Is it leaky?

This could get even more complicated if you have to examine methods that aren't simple getters. What if ClientID had a method that did some mathematical operation on its ID (indulge me) and returned an Integer. Is that a leak? Does this qualify as leaking that value is an Integer?

So I'm not sure if this is a code smell that a machine could easily catch.

瞎闹 2024-07-20 21:53:27

您可以考虑扩展您的示例来检查是否违反里氏替换原则。 有些人会说实现接口的类应该只抛出与接口定义的相同的异常。

如果您可以分析对象的使用情况,最好建议使用更通用的类型(例如,该方法需要 SQLConnection,而 IDBConnection 就可以)。

You could consider extending your example to check for violations to the Liskov Substitution Principle. There are some who would say that a class implementing an interface should only throw the same exceptions as defined by the interface.

If you could analyze the usage of the object, it would be good to suggest that a more general type could be used (e.g., the method requires a SQLConnection, when an IDBConnection would do).

北座城市 2024-07-20 21:53:27

想到了另外一个。 有一个处理非公共类型的公共成员。

class Foo { ... } // local to the package

public class Bar
{
    class Car() { ... }

    public Bar(Foo f) { ... }

    public Car star() { ... }
}

酒吧和明星会漏水。 您可以看到 Bar 构造函数 b,但只能从与 Bar 类相同的包中调用它。 您可以调用 star 方法,但只能将返回值用作 Object。

对于这两种情况,您会发现需要考虑将成员设置为私有或包访问权限,或者将类型设置为公共。

Thought of another one. Having a public member that deals with a non-public type.

class Foo { ... } // local to the package

public class Bar
{
    class Car() { ... }

    public Bar(Foo f) { ... }

    public Car star() { ... }
}

Bar and star would be leaky. You can see the Bar constructor b but can only call it from within the same package as the Bar class. You can call the star method but can only use the return value as an Object.

For both of these you would then see that you need to consider making the member either private or package access or making the type public.

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