接收java.lang.Object作为输入的方法不应该接收javax.servlet.jsp.JspWriter作为输入吗?

时间:2010-10-03 14:09:00

标签: java jsp servlets object printwriter

我想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调用它?

6 个答案:

答案 0 :(得分:3)

此异常表示在将print(JspWriter)更改为print(Object)后,您的JSP代码尚未重新编译,因此它仍会尝试调用print(JspWriter)而无法找到它。

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

答案 1 :(得分:1)

这是因为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); }

BTW:Java中的方法应按惯例以小写字母开头。

答案 2 :(得分:1)

您发布的内容应该有效,因为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页面进行测试。希望这可以帮助您找到问题。

答案 3 :(得分:0)

JspWriter不是PrintWriter

您可以将原始作者包装在这样的打印作者中:

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

答案 4 :(得分:0)

嗯,你通过转换为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有一个共同的界面......叹息。

答案 5 :(得分:0)

您的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...
    }
}