1

我想巩固两个功能

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

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 调用?

4

6 回答 6

3

此异常表示您的 JSP 代码在您更改print(JspWriter)为之后没有重新编译print(Object),因此它仍然尝试调用print(JspWriter)并且找不到它。

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

于 2010-10-03T14:23:23.763 回答
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); }

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

于 2010-10-03T14:22:18.300 回答
1

您发布的内容应该可以工作,因为两者PrintWriter都是JspWriter的子类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 页面获取代码并对其进行测试。希望这将帮助您找到问题所在。

于 2010-10-03T16:30:04.007 回答
0

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

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

这个:

public void print(Writer writer) {
    try {
        writer.write(this.FormattedString());
    } catch (IOException e) {
        // log something...
    }
}
于 2010-10-03T14:26:00.663 回答
0

JspWriter 不是 PrintWriter

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

if (out instance of Writer) {
 PrintWriter p = new PrintWriter((Writer) out));
 p.print...
}
于 2010-10-03T14:21:59.517 回答
0

好吧,您通过转换为 a 来开始您的方法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 有一个共同的接口就好了……唉。

于 2010-10-03T14:24:09.883 回答