1

I have the following block of code that works just fine:

<%@page import="java.util.*" %>
<%@page import="java.security.*" %>

<%
String str = "A string to hash.";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update( str.getBytes() );
byte[] digest = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0, j = digest.length; i < j; i++) {
    String tmp = Integer.toHexString(0xFF & digest[i]);
    if (tmp.length() < 2) {
        tmp = "0" + tmp;
    }

    hexString.append(tmp);
}

out.println(hexString.toString());
%>

When I tried to break the hashing code out into a method I got a "NoSuchAlgorithmException" error when defining the MessageDigest object:

<%@page import="java.util.*" %>
<%@page import="java.security.*" %>

<%
String str = "A string to hash";
String md5string = md5hash(str);

out.println(md5string);
%>

<%!
public String md5hash(String str) {
    MessageDigest md = MessageDigest.getInstance("MD5");

    md.update( str.getBytes() );
    byte[] digest = md.digest();
    StringBuffer hexString = new StringBuffer();
    for (int i = 0, j = digest.length; i < j; i++) {
        String tmp = Integer.toHexString(0xFF & digest[i]);
        if (tmp.length() < 2) {
            tmp = "0" + tmp;
        }

        hexString.append(tmp);
    }

    return hexString.toString();
}
%>

To get the JSP to compile, I had to modify it like so:

<%@page import="java.util.*" %>
<%@page import="java.security.*" %>

<%
String str = "A string to hash";
String md5string = md5hash(str);

out.println(md5string);
%>

<%!
public String md5hash(String str) {
    MessageDigest md = null;

    try {
        md = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e) {}

    md.update( str.getBytes() );
    byte[] digest = md.digest();
    StringBuffer hexString = new StringBuffer();
    for (int i = 0, j = digest.length; i < j; i++) {
        String tmp = Integer.toHexString(0xFF & digest[i]);
        if (tmp.length() < 2) {
            tmp = "0" + tmp;
        }

        hexString.append(tmp);
    }

    return hexString.toString();
}
%>

Why did I have to add a useless try/catch to make this code work?

James Sumners
  • 14,485
  • 10
  • 59
  • 77

2 Answers2

7

The normal JSP source code is by itself already placed in one huge try-catch block. Every normal scriptlet <% %> will become part of it, so you don't need to explicitly catch the exceptions. However, a method definition <%! %> will be placed outside the standard try-catch, so you have to handle the exceptions yourself.

Needless to say that this is not the best practice. Rather put the Java code in a real Java class. For this particular purpose, I think an EL function is very useful. See also How to avoid Java code in JSP files?

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • You answered the "why" first, so I will accept this answer when I am allowed. I avoid writing "real" Java classes whenever possible because they have to be compiled, and the server has to be restarted to pick them up. – James Sumners Dec 07 '10 at 19:14
  • 1
    A tip is to remember that the normal scriptlet is a part of one giant method that returns the contents of the page. It has a try-catch, your <%! method does not. Setup your container to leave generated .java files to get a better look at what's happening. – Mike Cornell Dec 07 '10 at 19:15
  • @jsumners: decent IDE's and servers supports auto/hot reloading. Eclipse+Glassfish for example does it in a subsecond. Tomcat takes a bit longer, but it supports it as well. – BalusC Dec 07 '10 at 19:21
  • I'm sure that is the case. My environment, though, is wretched from top to bottom. Put it this way, I have a cluster of 5 servers to run this site. The environment is so fragile and difficult to replicate that I have to remove one of the servers from public access and do all of my development on it. – James Sumners Dec 07 '10 at 19:25
1

The difference is when you encapsulate the code in a method, checked exceptions thrown within in that method have to be propagated or handled. Exceptions thrown by code in a JSP are getting caught and logged by the servlet container.

In the long term it's best to remove Java code from the JSP. In the short term you can change the declaration of the md5hash method in the second snippet to throw NoSuchAlgorithmException, that way you do without the try-catch and don't eat the exception.

By the way the try-catch is not just useless, it is potentially harmful, since you could have a problem and not get notified about it because of the exception getting eaten.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276