问题
I wanted to consolidate two functions.
After getting a viable solution, I decided to play with the code a bit further, and came up with this:
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("---------------------");
}
}
I expected that the print() method would catch both JspWriter and PrintWriter.
While this solution worked fine for PrintWriter, when I tried to run this as a console application, I get this output:
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)
I get a different error, however, if I try to access print(Writer writer) from a JSP:
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
When calling from the JSP, I can make a call to the class with JspWriter work by adding this code:
public void print(JspWriter out) throws java.io.IOException
{ print (new PrintWriter(out)); }
However, when attempting to use JspWriter from a console application (for testing -- I don't think anyone would ever need to use JspWriter in the console!), the above console error is moved to this function.
If print(JspWriter out) can fix the problem for JSPs, shouldn't it also fix the problem for console apps?
Moreover, if JspWriter is a Writer object, shouldn't it always be a Writer object, regardless whether it is called from the console or a JSP?
回答1:
This exception says that your JSP code haven't been recompiled after you changed print(JspWriter)
to print(Object)
, so it still tries to call print(JspWriter)
and can't find it.
In order to force a recompilation you may modify your JSP page.
回答2:
This is because the Java compiler tries to find the PrintWriter.print method on the JspWriter object. Although it has a print method, this method does not match because it is from another class. Java does not support duck-typing and goes to great lengths to prevent it.
It is also considered bad practice to use exceptions in programming logic.
You'll have to do sthg like
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: methods in Java should start with a lowercase letter by convention.
回答3:
What you posted should work since both PrintWriter
and JspWriter
are subclasses of Writer
(and of course both are subclasses of Object
). Something seems to be wrong either with your test code or with your environment.
Maybe you can try a simplified example and see if that works, then build up from there. I can suggest starting here:
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...");
}
}
This should compile and run. The second time test.print()
is called, the JspWriter
being passed in will be null
, but you should not get any NoSuchMethodError
. If this works, take the code and test it from your servlet / JSP pages. Hopefully this will help you find the problem.
回答4:
JspWriter is not a PrintWriter
you can wrap the original writer inside a print writer like this:
if (out instance of Writer) {
PrintWriter p = new PrintWriter((Writer) out));
p.print...
}
回答5:
Well you start your method by casting to a PrintWriter
, so maybe the jvm optimized the method for you. Since JspWriter
does not subclass from PrintWriter
, your best bet is to write two methods:
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
}
}
If only JspWriter and PrintWriter had a common interface... sigh.
回答6:
Your print() casts Object to a PrintWriter. But when you pass in a JspWriter which isn't PrintWriter, the cast fails.
However, PrintWriter and JspWriter are both descended from Writer. Can you change your print()
method to accept a Writer instead of an Object, and then use the Writer.write() method within print()
? This is common to both classes.
This:
public void print(Writer writer) {
try {
writer.write(this.FormattedString());
} catch (IOException e) {
// log something...
}
}
来源:https://stackoverflow.com/questions/3850079/shouldnt-a-method-that-receives-java-lang-object-as-input-also-receive-javax-se