Friday, January 05, 2007

java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.String

Very simply, you get the exception
java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.String
when you try to cast an array kind of a class to the linear type. In this case, attempting to cast String -> String[] or vice versa will cause the JVM to throw this particular exception at runtime. Compilers cannot catch this oversight.
As an example, consider an attempt to read all parameters passed to a servlet using the request object. The parameter map can be obtained with:
Map parameters = request.getParameterMap();

From HTML basics, we know that parameters are passed as key/value pairs of Strings to the web server, so the temptation is to assume that the generics mapping for parameters is <String, String>. In fact, compilers will allow you to use this generic:
Map<String,String> parameters = request.getParameterMap();
for(String key: parameters.keySet()) {
String value = parameters.get(key); // error happens here
System.out.println(key + "=" + value);
}

This code snippet will compile and run fine, producing results that look like:
firstName=[Ljava.lang.String;@1fe49b5
lastName=[Ljava.lang.String;@1993b4f
This is assuming parameters passed to the servlet (or JSP) include ones named 'firstName' and 'lastName', of course.

As it turns out, the value side of the parameter map is actually a String[] type. So the proper generic for this map is
<String, String[]>. When you call request.getParameter("firstName");, it simply returns the equivalent of parameters.get(key)[0];, which reads the first value associated with the key. This happens even if your form might have sent single-dimension parameters for processing.
So, just remembering the map's generics mapping may save you a lot of headaches down the road. This is simple Java internals - but a look at forums on the web shows how much of a problem this is for programmers out there. You's get the same kind of exception if you attempted to cast Date to Date[] (which would throw java.lang.ClassCastException: java.util.Date cannot be cast to [Ljava.util.Date;).