【问题标题】:Shouldn't a method that receives java.lang.Object as input also receive javax.servlet.jsp.JspWriter as input?接收 java.lang.Object 作为输入的方法不应该也接收 javax.servlet.jsp.JspWriter 作为输入吗?
【发布时间】:2010-10-03 14:09:00
【问题描述】:

我想consolidate two functions

在得到一个可行的解决方案后,我决定更进一步地使用代码,并想出了这个:

package hu.flux.helper;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import javax.servlet.jsp.JspWriter;
import com.objectmentor.library.web.framework.mocks.*;


// A holder for formatting data 
public class NameAndAddress 
{
    public String firstName;
    public String middleName;
    public String lastName;
    public String address1;
    public String address2;
    public String city;
    public String state;
    public String zip;

    public String FormattedString()
    {
        String formattedString = "<PRE>\n" + firstName;

        // Add the middle name only if it contains data.
        if ((middleName != null) && (middleName.length() > 0)) 
            {formattedString += " " + middleName;}

        formattedString += " " + lastName + "\n";

        formattedString += address1  + "\n";

        if ((address2 != null) && (address2.length() > 0))
            formattedString += address2 + "\n";

        formattedString += city + ", " + state + " " + zip + "\n</PRE>";
        return formattedString;
    }

    // Print out the name and address.
    public void print(Writer writer) {
    long now = System.currentTimeMillis();
    System.out.println("--Entering-- " + now);
    PrintWriter p = new PrintWriter (writer);
        p.write(this.FormattedString());
            now = System.currentTimeMillis();
        System.out.println("--Exiting-- "  + now);
    }

    /*
    public void print(JspWriter out) throws java.io.IOException 
    { print (new PrintWriter(out)); }
    */

    @SuppressWarnings("deprecation")
    public static void main (String args[])
    {
        NameAndAddress naa = new NameAndAddress();
        naa.firstName = "Brian";
        naa.middleName = "Matthew";
        naa.lastName = "Kessler";
        naa.address1 = "Tatra u. 15/b V/3";
        naa.city = "Budapest";
        naa.state = "Hungary";
        naa.zip = "HU-1136";

        System.out.println("\nTesting PrintWriter...");
        PrintWriter p = null;
        try { p = new PrintWriter("d:/temp/pwriter_text.txt"); } 
        catch (FileNotFoundException e) 
        { 
            System.err.print ("Can not create new PrintWriter: " + e);
            e.printStackTrace();
        }
        naa.print(p);
        p.flush();

        FileInputStream fis;
        DataInputStream dis;
        try 
        { 
            fis = new FileInputStream("d:/temp/pwriter_text.txt");
            dis = new DataInputStream (fis);
            while (dis.available() != 0)
                { System.out.println(dis.readLine()); }
            dis.close();
        }
        catch (Exception e)
        {
            System.err.println("File input error");
        }


        System.out.println("\nTested PrintWriter...");
        System.out.println("---------------------");

        System.out.println("\nTesting JSPWriter...");
        JspWriter j = null;
        naa.print(j);
        System.out.print("\nTested JSPWriter...");
        System.out.println("---------------------");

        System.out.println("\nTesting MockJspWriter");
        MockJspWriter m = null;
        m = new MockJspWriter(255, true);
        naa.print(m);
        System.out.print(m.getContent());
        System.out.println("\nTested MockJSPWriter...");
        System.out.println("---------------------");
    }
}

我希望 print() 方法可以同时捕获 JspWriter 和 PrintWriter。

虽然此解决方案适用于 PrintWriter,但当我尝试将其作为控制台应用程序运行时,我得到以下输出:

Testing PrintWriter...
--Entering-- 
--Exiting-- 
<PRE>
Brian Matthew Kessler
Tatra u. 15/b V/3
Budapest, Hungary HU-1136
</PRE>

Tested PrintWriter...
---------------------

Testing JSPWriter...
--Entering-- 
Exception in thread "main" java.lang.NullPointerException
    at hu.flux.helper.NameAndAddress.print(NameAndAddress.java:46)
    at hu.flux.helper.NameAndAddress.main(NameAndAddress.java:101)

但是,如果我尝试从 JSP 访问 print(Writer writer),则会收到不同的错误:

HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.NoSuchMethodError: hu.flux.helper.NameAndAddress.print(Ljavax/servlet/jsp/JspWriter;)V
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:492)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:407)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause

javax.servlet.ServletException: java.lang.NoSuchMethodError: hu.flux.helper.NameAndAddress.print(Ljavax/servlet/jsp/JspWriter;)V
    org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:898)
    org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:827)
    org.apache.jsp.Address_jsp._jspService(Address_jsp.java:92)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:68)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:376)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause

java.lang.NoSuchMethodError: hu.flux.helper.NameAndAddress.print(Ljavax/servlet/jsp/JspWriter;)V
    org.apache.jsp.Address_jsp._jspService(Address_jsp.java:81)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:68)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:376)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.2 logs.

Apache Tomcat/7.0.2

当从 JSP 调用时,我可以通过添加以下代码来调用具有 JspWriter 工作的类:

public void print(JspWriter out) throws java.io.IOException 
    { print (new PrintWriter(out)); }

但是,当尝试从控制台应用程序中使用 JspWriter 时(为了测试——我认为没有人需要在控制台中使用 JspWriter!),上面的控制台错误被转移到这个函数中。

如果 print(JspWriter out) 可以解决 JSP 的问题,它不应该也解决控制台应用程序的问题吗?

另外,如果 JspWriter 是一个 Writer 对象,它不应该总是一个 Writer 对象,不管是从控制台调用还是从 JSP 调用?

【问题讨论】:

  • 您可能想要了解的一件事是转换对象和转换对象之间的区别。强制转换不会更改实例的类。 Object o = (Object) new Integer(1); 'o' 是一个整数。您可以通过Object o = (Object) new Integer(1); System.out.println(o.getClass().getName()); 看到这一点。因此,在您的print() 方法中,您对 Object 所做的一切就是允许传入任何实例而不会产生编译时错误。您没有做任何任何事情来更改参数的类,以便代码可以工作。
  • 好的,但这是函数内部的代码。为什么 Java 不将 JspWriter 识别为对象?
  • @brian kessler - 这是一个很好的问题。我认为您有多个问题,或者我们误解了堆栈跟踪。创建一个 main(),创建一个 NameAndAddress 实例,然后尝试一下。这将从等式中删除所有 jsp/容器问题。
  • @Tony Ennis - 在制作 NameAndAddress naa 并赋予其属性值之后,我不完全确定在 main() 中放入什么。我创建了一个 PrintWriter p,对其进行了初始化,然后调用 naa.print(p) 没有错误,也没有输出。然后我创建了一个 JspWriter j,但不知道如何实例化它;当我调用 naa.print(j) 时,Java 抱怨 null 值。我将更新上面问题中发布的 NameAndAddress 类,以便我们在同一页面上。
  • 是的,为了让事情变得复杂,JspWriter 是抽象的。恼人的。我得再调查一下。在你的测试中,如果你用一个文件名创建你的 PrintWriter,输出会去哪里:p = new PrintWriter("/Users/tonyennis/Desktop/out.txt"); 别忘了发出flush()

标签: java jsp servlets object printwriter


【解决方案1】:

这个异常是说你把print(JspWriter)改成print(Object)后没有重新编译你的JSP代码,所以它仍然尝试调用print(JspWriter)却找不到。

为了强制重新编译,您可以修改您的 JSP 页面。

【讨论】:

  • 对,要么重新编译,要么只是将所有 Java 代码移到它所属的 servlet 中。除了修改,您还可以选择清理工作目录。大多数 IDE 在服务器条目中提供 Clean 上下文菜单选项。
  • 重新编译多次...不是这样,但为响应欢呼。
  • @Brian:重新编译后 Stacktrace 保持不变?如果是这样,由于某种原因实际上不会发生重新编译。
  • 不完全相同...此外,我可以进行更改以使代码正常运行(尽管我试图使其正常运行时无法正常运行)并且它可以正常工作,然后进行更改以使 Java必须意识到 JspWriter 继承自 Object 或 Writer 并再次中断。
  • 你的环境中有些东西停滞不前。做一个干净的构建。重启你的机器。格式化磁盘。
【解决方案2】:

这是因为 Java 编译器试图在 JspWriter 对象上查找 PrintWriter.print 方法。虽然它有一个 print 方法,但是这个方法不匹配,因为它来自另一个类。 Java 不支持鸭子类型,并且竭尽全力防止它。

在编程逻辑中使用异常也被认为是不好的做法。

你必须这样做

    try
    { 
       if (out instanceof PrintWriter) {
          ((PrintWriter) out).print(this.formattedString()); 
       } else if (out instanceof JspWriter) {
          ((JspWriter) out).print(this.formattedString()); 
       } else {
          throw new IllegalArgumentException("NameAndAddress.print expected ether a PrintWriter or a JspWriter but received a " + out.getClass().getName());
       }
    catch (Exception ex)
    { System.err.println("\"out\" is not a printable type: " + ex); }

顺便说一句:Java 中的方法按照约定应该以小写字母开头。

【讨论】:

  • 试过这个,但是Java仍然没有找到执行这些条件的方法。
  • 我仔细检查了: JspWriter.print(String s) 和 PrintWriter.print(String s) 都存在。它应该工作。您遇到了什么错误?
  • 错误是,如上。它的症结是:org.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.NoSuchMethodError: hu.flux.helper.NameAndAddress.print(Ljavax/servlet/jsp/JspWriter;)V,如果我理解正确,意味着 Java 没有将 JspWriter 识别为对象
  • 可能是您传递的对象被加载到与 NameAndAddress 类已加载的类加载器不同的类加载器中。 NameAndAddress 代码是从 servlet 还是从 JspPage 加载的?
  • 我从两个地方给班级打电话。我有一个使用 PrintWriter 调用的 servlet;这很好用。我有一个用 JspWriter 调用的 Jsp 页面;如果我没有明确的 JspWriter 方法,这就是导致问题的原因。
【解决方案3】:

您发布的内容应该可以工作,因为PrintWriterJspWriter 都是Writer 的子类(当然它们都是Object 的子类)。您的测试代码或您的环境似乎有问题。

也许您可以尝试一个简化的示例,看看它是否有效,然后从那里开始构建。我可以建议从这里开始:

public class Test
{
    public void print(Writer writer) throws IOException
    {
        if (writer == null)
            System.out.println("Null writer");
        else
        {
            writer.write("hello");
            writer.flush();
        }
    }

    public static void main(String args[]) throws IOException
    { 
        Test test = new Test();

        System.out.print("Testing PrintWriter...");
        PrintWriter p = new PrintWriter("d:/temp/pwriter_text.txt");
        test.print(p);
        System.out.print("Tested PrintWriter...");

        System.out.print("Testing JspWriter...");
        JspWriter j = null;
        test.print(j);
        System.out.print("Tested JspWriter...");
    }
}

这应该编译并运行。第二次调用test.print(),传入的JspWriter将是null,但你不应该得到任何NoSuchMethodError。如果可行,请从您的 servlet/JSP 页面获取代码并对其进行测试。希望这能帮助您找到问题所在。

【讨论】:

  • 这会编译,但是当它点击 test.print(j) 时我会收到错误,因为它没有被实例化,这不可能是它的抽象。
  • @brian Kessler - 这正是他的观点。您收到的错误看起来是 找不到合适的方法 错误。因此,Grod 的解决方案虽然不会产生您想要的输出,但 会测试未找到该方法的想法。如果仍未找到,则说明您遇到的问题与我们要解决的问题不同。
  • 您不会收到任何错误。正如我在回答中解释的那样,当您调用test.print(j) 时,j 将是null,但这在print 方法的实现中进行了检查。您不应收到任何错误或异常。这样做的唯一目的是证明如果传入JspWriter,则调用test 方法。
  • 确实 得到错误:java.io.Writer.(Unknown Source) 处 java.io.Writer 处的线程“main”java.lang.NullPointerException 中的异常。 PrintWriter.(Unknown Source) at java.io.PrintWriter.(Unknown Source) at hu.flux.helper.NameAndAddress.print(NameAndAddress.java:51) at hu.flux.helper.NameAndAddress.main (NameAndAddress.java:97)
  • @brian Kessler - 你有一些歪斜的东西。如果您还没有这样做,请发布您最新和最伟大的 main()。顺便说一句,我们不知道哪一行是#97。您在指定 PrintWriter 输出文件的代码中是否真的有双引号,还是格式问题?
【解决方案4】:

JspWriter 不是 PrintWriter

您可以像这样将原始作家包装在印刷作家中:

if (out instance of Writer) {
 PrintWriter p = new PrintWriter((Writer) out));
 p.print...
}

【讨论】:

  • JspWriter 可以转换为 PrinterWriter。如果我添加这个小方法,问题就会消失: public void print(JspWriter out) throws java.io.IOException { print (new PrintWriter(out)); }
  • @brian kessler - 问题并没有消失。如果将 IOException 更改为 Exception,则问题只是被隐藏了。如果您使用 PrintWriter 尝试,您在上面发布的评论将在运行时失败。
  • 上面的代码在 PrintWriter 上运行良好。只有 JspWriter 失败了,至少最初是因为 Java 没有将 JspWriter 识别为对象(尽管我认为每个类都继承自对象?)。如果我添加上面的方法,PrintWriter 和 JspWriter 都可以工作......但我试图理解为什么 Java 似乎没有将 JspWriter 视为一个对象,以及是否可以在不使用其他方法的情况下使上面的代码工作处理 JspWriter。
  • @Brian Kessler JspWriter 和 PrintWriter 都是从 Writer 扩展而来的。你想如何将它们相互投射?
  • 我想看看我可以将两种类型相同的代码整合到多远。由于代码在其他方面是相同的,我想用一个函数捕获这两种类型,并使用一个条件处理它们。现在,用一个函数同时捕获它们似乎更让人头疼。
【解决方案5】:

你通过转换为PrintWriter 来开始你的方法,所以jvm 可能会为你优化方法。由于JspWriter 不是PrintWriter 的子类,最好的办法是编写两个方法:

public void print(JspWriter out) 
{ 
    if (out == null) return;
    try {
        out.print(this.FormattedString());
    } Except (IOException e) {
        // handle error 
    }
}

public void print(PrintWriter out) 
{ 
    if (out == null) return;
    try {
        out.print(this.FormattedString());
    } Except (IOException e) {
        // handle error 
    }
}

要是 JspWriter 和 PrintWriter 有一个共同的接口就好了……唉。

【讨论】:

  • 他们都是作家的后代。
  • JspWriter can 可以转换为 PrinterWriter。如果我添加这个小方法,问题就会消失: public void print(JspWriter out) throws java.io.IOException { print (new PrintWriter(out)); }
  • @brian kessler - Java 将允许我们将类转换为其他类,但这并不意味着当该代码执行时它就会运行。在传入一个 Object 并将它真正的任何内容投射到 PrintWriter 的情况下,这意味着我们只是关闭了设计人员对语言进行的错误检查。
  • @Tony Ennis:Writer 没有 print() 方法,所以使用 writer 接口是行不通的。
【解决方案6】:

您的 print() 将 Object 转换为 PrintWriter。但是当你传入一个不是 PrintWriter 的 JspWriter 时,转换失败。

但是,PrintWriter 和 JspWriter 都是 Writer 的后代。你能改变你的print()方法来接受一个Writer而不是一个Object,然后在print()中使用Writer.write()方法吗?这对两个类都是通用的。

这个:

public void print(Writer writer) {
    try {
        writer.write(this.FormattedString());
    } catch (IOException e) {
        // log something...
    }
}

【讨论】:

  • 试过了,但结果似乎一样:找不到方法,所以它永远不会进行强制转换。
  • 等等,哪个方法没找到。
  • 如上:org.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.NoSuchMethodError: hu.flux.helper.NameAndAddress.print(Ljavax/servlet/jsp/JspWriter;) V
  • 插入我发布的代码,并注释掉当前存在的print(Object out) 方法。走着瞧吧。考虑在你的类中放置一个 main(),这样你就可以从 IDE/命令行运行测试(更快),或者更好的是,添加 junit 测试。
  • 仍然只识别 PrintWriter,不识别 JspWriter。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多