Friday, June 10, 2011

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

If you see this error:

java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.String When using HttpServletRequest getParameters()

and you're using Liferay 6 with ICEfaces 1.8, then maybe this will help you.

The environment:

Liferay 6.06
Tomcat 6.0.29
Windows 7
ICEfaces 1.8.1 on JSF 1.2

The error is the result of having the out-of-the-box Chat portlet running at the same time as an ICEfaces portlet. I haven't worked out yet exactly why, but what's hapening is the PollerServlet in Liferay is having its getContent() method called and the pollerRequestString is giving it indigestion.

Liferay expects to be able to take the pollerRequestString, deserialize it, and cast it into a Map. For whatever reason, when there's an ICEfaces 1.8 portlet present, it gets a string it can't handle. Since Liferay didn't check the cast in the code for this Servlet, it throws the above error every 60 seconds. This can make for a very full log file in a very short period of time.

The offending line of code:

Map<String, Object>[] pollerRequestChunks =
(Map<String, Object>[])JSONFactoryUtil.deserialize(
pollerRequestString);


What to do?

Well, one suggestion on the Liferay forum for this issue is to remove the Chat portlet. That will make the errors go away, but it isn't much of a solution when you want to actually use the Chat portlet.

What I did was a quick & dirty "fix" using the Ext plugin system Liferay 6 provides.

Now, the Liferay In Action book from Manning has a pretty good section on setting up an Ext plugin and a good overall explanation of how Ext plugins work, but for some reason he seems to be in love with using Struts examples. He even sort of hangs a lampshade on that by saying that its 99% likely that if you're using the Ext plugin it's because you want to modify the Struts behavior.

Well I guess this is that 1% when we're not. What now?

We go in and use brute force, of course!

The author also strongly encourages the reader to extend, not replace, the classes in Liferay. The logic is that if you replace a class, then Liferay subsequently performs an update it will break your code. Well, he also acknowledges that your Ext plugin will probably break anyway so I don't see this as a major risk beyond what we're already doing. Further, all we're doing here is a simple fix, not changing any big functionality, so I'm going ahead and replacing.

Using either your Eclipse Helios (with Liferay plugin) or Liferay 6.0 SDK create a new Ext plugin project.

Know how?

You should have the Liferay 6 SDK set up on your machine. For details on that, you can check out one of my earlier posts. From there, if you're not using Eclipse, you can navigate into the ext folder and type

create uberext "Uber Extension"

(Substitute your own names)

That creates the plugin structure for you in a new folder in the ext folder.

In Eclipse, it's the same idea and it'll even create the plugin folder in your SDK ext folder, exactly as if you'd done it the command line way. (Assuming you've set Eclipse to use your SDK. If not, you need to do that first.)

To set Eclipse to use your SDK:
  1. Open Eclipse
  2. Click the dropdown arrow next to the Create New Server button. It should be right under "Search" on your Menu bar and it's the icon that looks a little like Oscar the Grouch's Trash Can. (Make of that what you will.)
  3. Select "New Liferay SDK"
  4. Follow the prompts to add the new SDK to your Eclipse environment.
Now you can use Eclipse to create your plugins and use the supplied Ant build scripts from the SDK.

Now to create your new Ext project:
  1. Either click the Liferay icon that looks like a power plug or go to File >> New >> Liferay Project
  2. Choose a project name and Display name, entering them in the appropriate fields.
  3. Under Plugin Type, select Ext
Eclipse will, behind the scenes, run the command that creates the project in the ext folder just as if you'd done it there yourself. It also displays the project in the navigation pane at the left.

So, to fix the above error:

In the source code for the plugin, under the docroot/WEB-INF/ext-impl/src folder, create your version of the com.liferay.portal.poller package. Inside it, create your PollerServlet class.

Now copy/paste the code from the original source to your version.

What I did (and this is a quick and dirty solution, I leave a more elegant approach to you) was to take the offending line of code above and replace it with this:

Map<String, Object>[] pollerRequestChunks;

try{
pollerRequestChunks =
(Map<String, Object>[])JSONFactoryUtil.deserialize(
pollerRequestString);
}catch (java.lang.ClassCastException e){
return null;
}

This handles the exception being thrown by the bad cast. Would it be better to check the input and handle it more gracefully? Yes it would, especially because this will still result in a log entry every minute of "Current URL /poller/send generates exception: null" as the method is returning a null value, but the idea here is to show how to do a simple Ext plugin that isn't related to Struts. Besides, it's still better than a stack trace dump every minute.

Now to create the deployable war...

The Liferay SDK has an ant deploy command that you can run from the command line in the folder for your ext project or you can double click it in the Ant window in Eclipse. Either way, if you've configured your SDK environment properly the result will be an Ext plugin that's been compiled, built as a .war file, and copied to the deploy folder in your Liferay instance.

Liferay will install it, but because we're making changes to the compiled code we will need to restart Liferay to make the changes take effect.

This is the quickest, simplest and dirtiest way to build an Ext plugin. Normally we'd do it with more finesse than that but this should be enough to get you started.

2 comments:

  1. i am just developing struts, spring , hibernate portlet project application in Liferay 6.2.0. Whenever I am deploying my portlet in LR at that time I found following exception that...

    07:02:38,858 ERROR [http-bio-8080-exec-29][GZipFilter:81] java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.String
    java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.String

    There is no effect on my project as well as in LR. MY application working well.

    then How can I remove this error??

    e-mail : pradip.bhatt@aspiresoftware.in

    Reply me..

    ReplyDelete
    Replies
    1. Are you seeing this error when yuo first deploy your plugin, but before the actual installation begins?

      Delete