Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Dodge the traps hiding in the URLConnection class

The URLConnection class's generic design causes snags when posting to a URL

  • Print
  • Feedback

Page 3 of 6

E:\classes\com\javaworld\jpitfalls\article3>java -Djava.compiler=NONE 
com.javaworld.jpitfalls.article3.BadURLPost 
http://localhost/cgi-bin/echocgi.exe
Received a : sun.net.www.protocol.http.HttpURLConnection
Getting an input stream...
Getting an output stream...
java.net.ProtocolException: Can't reset method: already connected
        at 
java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:10
2)
        at 
sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLCo
nnection.java:349)
        at 
com.javaworld.jpitfalls.article2.BadURLPost.main(BadURLPost.java:38)


When we try to obtain the HttpURLConnection class's output stream, the program informs us that we cannot reset the method because we are already connected. The Javadoc for the HttpURLConnection class contains no reference to setting a method. The program is referring to the HTTP method, which should be POST when we send data to the URL and GET when we retrieve data from the URL.

The getOutputStream() method causes the program to throw a ProtocolException with the error message "Can't reset the method." The JDK source code reveals that the error message results because the getInputStream() method has the side effect of sending the request (whose default request method is GET) to the Web server. This is similar to a side effect in the ObjectInputStream and ObjectOutputStream constructors, detailed in my book, Java Pitfalls: Time Saving Solutions and Workarounds to Improve Programs (John Wiley & Sons, 2000).

The pitfall is the assumption that the getInputStream() and getOutputStream() methods behave just as they do for a Socket connection. Since the underlying mechanism for communicating to the Web server actually is a Socket, it is not an unreasonable assumption. A better implementation of HttpURLConnection would postpone the side effects until the initial read or write to the respective input or output stream. You can do that by creating an HttpInputStream and an HttpOutputStream, which would keep the Socket model intact. You could argue that HTTP is a request/response stateless protocol, and the Socket model does not fit. Nevertheless, the API should fit the conceptual model; if the current model is identical to a Socket connection, it should behave as such. If it does not, you have stretched the bounds of abstraction too far.

In addition to the error message, there are two problems with the above code:

  • The setRequestProperty() method parameters are not checked, which we demonstrate by setting a property called stupid with a value of nonsense. Since those properties actually go into the HTTP request and are not validated by the method (as they should be), you must take extra care to ensure that the parameter names and values are correct.
  • Although the code is commented out, it is also illegal to attempt to set a request property after obtaining an input or output stream. The documentation for URLConnection indicates the sequence to set up a connection, although it does not state that it is a mandatory sequence.


If we did not have the luxury of examining the source code -- which should definitely not be a requirement to use an API -- we would be reduced to trial and error, the absolute worst way to program. Neither the documentation nor the API of the HttpURLConnection class afford us any understanding of how the protocol is implemented, so we feebly attempt to reverse the order of calls to getInputStream() and getOutputStream(). Listing 5.2, BadURLPost1.java, is an abbreviated version of that program.

  • Print
  • Feedback

Resources