views:

70

answers:

4

I have the following class, which as you will see has rather a rather redundant formatNameAndAddress method:

package hu.flux.helper;
import java.io.PrintWriter;

import javax.servlet.jsp.JspWriter;

// 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;

 // Print out the name and address.
 public void formatNameAndAddress(JspWriter out)
  throws java.io.IOException
  {
   out.println("<PRE>");
    out.print(firstName);

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

    out.println(" " + lastName);

    out.println(" " + address1);

    if ((address2 != null) && (address2.length() > 0))
     out.println(" " + address2);

    out.println(city + ", " + state + " " + zip);
   out.println("</PRE>");
  }

 public void formatName(PrintWriter out) 
 {
  out.println("<PRE>");
  out.print(firstName);

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

  out.println(" " + lastName);

  out.println(" " + address1);

  if ((address2 != null) && (address2.length() > 0))
   out.println(" " + address2);

  out.println(city + ", " + state + " " + zip);
  out.println("</PRE>");
 }
}

I'd like to rewrite the class to use a generic method like:

     // Print out the name and address.
 private void genericFormatNameAndAddress(Object out)
 {
  out.println("<PRE>");
   out.print(firstName);

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

   out.println(" " + lastName);

   out.println(" " + address1);

   if ((address2 != null) && (address2.length() > 0))
    out.println(" " + address2);

   out.println(city + ", " + state + " " + zip);
  out.println("</PRE>");
 }

But, I can't do this exactly like this because Object doesn't have print() and println() methods. If I cast the output to either JspWriter or PrintWriter, I'd be casting it the wrong way sometimes.

I imagine what I need to do is somehow pass the object type as a variable and then use the variable to determine how to cast. Is this possible? If so, how? If not, what would be a good solution?

+3  A: 

This will probably work:

public void formatNameAndAddress(JspWriter out) throws java.io.IOException {
    formatNameAndAddress(new PrintWriter(out));
}
Michael Barker
That works, cheers!
Brian Kessler
Knowing that I could cast JspWriter to PrintWriter, I tried to take my revision a bit further (also incorporating Steve's wisdom)... However, now I have a new problem which I ask about at http://stackoverflow.com/questions/3850079/shouldnt-a-method-that-receives-java-lang-object-as-input-also-receive-javax-ser
Brian Kessler
@Brian, no you couldn't cast, `JspWriter` isn't a subclass of `PrintWriter`.
Colin Hebert
So, the above method, while effectively casting isn't actually casting (at least so far as Java is concerned)?
Brian Kessler
Its not casting, it creates a new object that delegates calls onto the original one.
Michael Barker
I see... Cheers for the clarification.
Brian Kessler
+1  A: 

You're kind of muddling two different tasks with these methods, and breaking the OO principle of specialization. That is, you have methods which are responsible for formatting one of two types of strings... AND responsible for sending them to one of two types of output targets.

A better approach might be to make your methods more specialized. That is, have them ONLY be responsible for building a "Name" string or a "Name and Address" string... and return String as the methods' return type.

At the point in code where you're invoking these methods, you obviously already have a JspWriter or a PrintWriter object... because right now you're passing it as an method argument. So it would be cleaner to simply leave that object where it is in the code, and have it print out the String which is returned by your specialized output-agnostic method.

Steve Perkins
Actually, they both ultimately have the same output target. One method is being called from a servlet, and the other from a JSP page, which I understand is actually changed to a servlet before being served. But, I think I understand what your suggesting. Cheers for the response!
Brian Kessler
A: 

If you want to cast the object to the correct Writer you can try something like:

private void genericFormatNameAndAddress(Object out){
    if (obj instanceof Printwriter){
        //cast to printwriter
    } else {
        //cast to JspWriter
    }

Barkers solution seems to be better suited because a Printwriter can be constructed out of a JspWriter.

kasten
Cheers for the response but I don't think that would really do what I'm looking for since it would just make the code longer and more complicated if I checked before every instance of casting and there wouldn't be much advantaged of passing "out" to this function if it would only be split and processed separately again.
Brian Kessler
A: 

Both JspWriter and PrintWriter are subclasses of java.io.Writer. Since you don't use any functionality that is specific to any of the two, you can declare the method as taking a java.io.Writer:

public void formatNameAndAddress(Writer out) throws java.io.IOException
{
    [...]

Then pass a JspWriter or PrintWriter as required.

Edit: This won't work without actually modifying the code since, as pointed out by others, Writer doesn't have print and println methods, whereas JspWriter and PrintWriter both provide them.

Grodriguez
`println` isn't in `Writer`, it's both in `JspWriter` and `PrintWriter` but it's still specific to each of these classes.
Colin Hebert
Just tried this, but this signature doesn't seem to catch JspWriter. I've been exploring a similar approach and have posted the question resulting from this thus-far-misadventure to http://stackoverflow.com/questions/3850079/shouldnt-a-method-that-receives-java-lang-object-as-input-also-receive-javax-ser
Brian Kessler