【问题标题】:Java overloaded method in library fails when not run in web server未在 Web 服务器中运行时,库中的 Java 重载方法失败
【发布时间】:2011-11-07 14:53:57
【问题描述】:

我正在尝试编写一个小型库,它既可以在标准 java 应用程序中使用,也可以作为 servlet 的一部分。

我定义了几个重载方法如下:

// imports etc.

public ExampleLibrary {

    /**
     * This one is meant to be used by a J2SE app
     */
    public String processData(Map headers) throws MyException {
        // process
        // return result
    }

    /**
     * This one is meant to be used by a servlet 
     */
    public String processData(HttpServletRequest request) throws MyException {
        // extract headers from request
        // process
        // return result
    }


    // other methods.....
}

这在用作 Servlet 的一部分时效果很好,但是当用作 J2SE 应用程序的一部分时它起作用。

在我的 J2SE 应用程序中,我执行了以下操作:

ExampleLibrary example = ExampleLibrary.getInstance();

Map headers = new HashMap();
headers.put("someheader1", "someheaderval1");
headers.put("someheader2", "someheaderval2");

String res = example.processData(headers);

我在编译时得到这个: “找不到 javax.servlet.http.HttpServletRequest 无法访问 javax.servlet.http.HttpServletRequest 类文件”

我期待编译器选择正确的 processData() 方法并忽略另一个,因为显然 J2SE 应用程序中没有 Servlet 类文件。任何想法如何解决这个问题?

【问题讨论】:

    标签: java servlets compilation overloading classnotfoundexception


    【解决方案1】:

    您可以通过在编译时在类路径中包含servlet.jar 来解决您的问题。

    这里有一个问题:

    如果您的库的用户调用这两种方法之一,编译器需要确定实际调用这两种方法中的哪一种。如果您有不同的方法名称,一切都很好,编译器确实不需要需要访问HttpServletRequest。但是,如果您有相同的名称,编译器需要访问 HttpServletRequest 才能确定这两种方法中的哪一种最适合调用和参数。

    因此,您的库的用户将不需要需要servlet.jar运行他的程序,但是如果您使用方法重载,他将需要它才能能够编译他的程序。

    这是一个说明这一点的虚拟示例:

    虚拟测试第三方库:

    首先,让我们创建一个虚拟的第三方库 jar(并丢弃源):

    # libtest$ mkdir thirdpartylib
    # libtest$ cat -> thirdpartylib/ThirdPartyClass.java
    package thirdpartylib;
    
    public class ThirdPartyClass {
        public void thirdPartyMethod() {
            System.out.println("Third party method");
        }
    }
    # libtest$ javac thirdpartylib/ThirdPartyClass.java 
    # libtest$ jar cf thirdpartylib.jar thirdpartylib/ThirdPartyClass.class 
    # libtest$ rm -rf thirdpartylib
    

    虚拟测试你的库:

    # libtest$ mkdir mylib
    # libtest$ cat -> mylib/LibClass.java
    package mylib;
    import thirdpartylib.ThirdPartyClass;
    
    public class LibClass {
    
        public void method(String str) {
            System.out.println("method 1");
        }
    
        // Overloaded method taking third party class as argument.
        public void method(ThirdPartyClass tpc) {
            tpc.thirdPartyMethod();
        }
    }
    # libtest$ javac -cp .:thirdpartylib.jar mylib/LibClass.java 
    # libtest$ jar cf mylib.jar mylib/LibClass.class
    # libtest$ rm -rf mylib
    

    测试在没有thirdpartylib.jar 的情况下使用你的库

    # libtest$ cat -> LibUser.java
    import mylib.LibClass;
    
    public class LibUser {
        public static void main(String[] args) {
            new LibClass().method("Hej");
        }
    }
    # libtest$ javac -cp .:mylib.jar LibUser.java
    LibUser.java:5: cannot access thirdpartylib.ThirdPartyClass
    class file for thirdpartylib.ThirdPartyClass not found
            new LibClass().method("Hej");
                          ^
    1 error
    # libtest$ javac -cp .:mylib.jar:thirdpartylib.jar LibUser.java
    # libtest$ java -cp .:mylib.jar LibUser
    method 1
    

    【讨论】:

    • 即使你不调用该方法?
    • 我希望不必将 servlet.jar 放在类路径中。如果我添加一个名为 processDataHeaders(Map headers) 的新方法并使用它而不是重载方法,我可以毫无问题地编译 J2SE 应用程序,但我希望保持方法名称不变。
    • @Thilo,看来我有点不对劲。这确实是一个混乱的局面。
    • 我回答一小时后,您将答案更改为与我的相同。不过,很好的示例代码。
    • 哦,天哪..如果我仔细阅读了你的答案,那我就不用扯头发了……+1 给你……
    【解决方案2】:

    我在编译时得到这个:“无法访问 javax.servlet.http.HttpServletRequest 类文件 javax.servlet.http.HttpServletRequest 未找到”

    从 Tomcat 获取 servlet.jar。它包含 servlet API。这应该会抑制该错误。

    【讨论】:

      【解决方案3】:

      将 rt.jar 和 servlet.jar(或 eclipse 中的 webApp 库)放在类路径中

      【讨论】:

        【解决方案4】:

        由于您的类依赖于javax.servlet.http.HttpServletRequest,您必须提供后者的类定义才能加载您的类。最简单的方法是将 servlet.jar 与您的应用程序捆绑在一起。

        但是请注意,让 JavaSE 应用程序依赖于 JavaEE 库并不是一个好主意。

        更好的解决方案是将 servlet 特定部分隐藏在您自己的界面后面,您的核心应用程序可以安全地提供这些部分。然后在应用程序的 JavaEE 特定部分中将接口实现为相应 servlet 类的简单包装器。

        【讨论】:

        • @aioobe,不知道。我刚刚遇到类似的情况,涉及 indirect 依赖项(即提供的 jar 中的某些类依赖于第三方库,除非我明确提供第三个,否则我的应用程序无法运行派对罐子),所以至少在某些情况下似乎需要它。
        • (抱歉删除我的评论。我现在真的很困惑)
        【解决方案5】:

        我怀疑您的错误与重载方法无关。 如果类路径中没有 servlet-api.jar,您根本无法编译您的类。

        【讨论】:

        • 不调用重载方法可以编译。如果我调用其他方法,它编译得很好。
        【解决方案6】:

        尝试使用不同的名称而不是重载。

        public String processData(Map headers) throws MyException { ... }
        
        public String processServletData(HttpServletRequest request) throws MyException { ... }
        

        现在可以了。

        编辑:或者,您可以在编译时将 servlet.jar 放在类路径中。你不需要它来运行程序,只需要编译它。 java编译器需要类信息来决定选择哪个重载方法。

        【讨论】:

        • 嗯,是的,但我希望有相同的方法名称:)
        • 然后你必须提供必要的类(HttpServletRequest)进行编译。但是,您在运行时不需要它。
        • 这是因为 Java 在编译时决定使用哪个重载方法,并且需要检查类来做出决定。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多