Wednesday, May 4, 2011

Dealing with a tricky ognl.MethodFailedException

I'm trying to reuse an existing JSP form for both creating and editing an entity.  In my case, it's an entity named Tag (not to be confused with JSP tags).  I had everything in working order with Struts for creating my entities and was just beginning the process of integrating edit / update capability when I encountered the tricky error (actually a warning) described below.

The first thing I did in an attempt to add edit capability was add a hidden "id" field to my JSP form so I can keep track of which entity I'm updating.  Since I'm reusing the same form for both creating and editing my entity, the "id" will be submitted without a value on each post for creating a new Tag. Here's what I added to my JSP:
<s:hidden name="id" />
After making this small change I did a function test to make sure I could still create new Tags and saw the following stack trace in the log as excerpted below:
com.opensymphony.xwork2.ognl.OgnlValueStack - Error setting expression 'id' with value '[Ljava.lang.String;@100ac03'
ognl.MethodFailedException: Method "setId" failed for object org.robbins.flashcards.model.Tag@1b9eb34 [name='null' ]
[java.lang.NoSuchMethodException: org.robbins.flashcards.model.Tag.setId([Ljava.lang.String;)] at ognl.OgnlRuntime.callAppropriateMethod(
It's complaining because ognl is not finding a setId() method on my POJO that takes a String value.  Well, since "id" is an integer, of course my POJO won't accept a String.  Remember, I'm getting this error when trying to create a new Tag and the hidden "id" field is going to be empty at this point.  It gets submitted as empty, I mean literally an empty string ("").  Ognl it trying to assign a string to an integer field and is complaining when it doesn't find an appropriate method on my POJO.  Maybe this is by design.

I wasn't sure how to deal with this issue.  As usual, I did some Googling but this time I didn't find a suitable solution to my problem.  Next, I posted to StackOverflow and the Struts User distribution list.

A response on StackOverflow suggested it might be an old bug in ognl and to try using a newer version of the ognl jar.  I was already using ognl-3.0.jar which is included in the Struts distribution.  In any case, I replaced it with ognl-3.0.1.jar which I obtained from the Maven2 repository and continued receiving the same error.

My post to Struts User didn't garner any traction at first so I decided to try some more Googling.  I found something that sparked a light bulb in my head.  I found a blog post in Chinese which, although I couldn't read the explanation, appeared to suggest modifying the logging level for ognl packages from Warn to Error.

Could it be that simple?  After all, the stack trace in the log was a Warn and not an Error.  Maybe I could just ignore it.

On further inspection, my create code was actually completing successfully even with the stack trace.  I then finished modifying my JSP, Action, and business tier code to enable editing of existing Tag entities.  Lo and behold, when submitting the edit form, which by the way has a value in the hidden "id" form tag, the "id" is successfully set on my POJO.  Ognl was only throwing the stack trace when the "id" field had no value.

The post to the Struts User List later received some responses and one of the folks suggested to "default the value or make sure you supply a value for your hidden field and base your application logic on this value".

In the end I just modified my as follows:
# Struts OgnlUtil issues unimportant warnings 

 What do you think?  Prefer a different approach?  Please feel free to comment.

1 comment:

  1. I also had the same error bro.but i somehow find it
    1.we needn't define getter setter for the input field that are accepting from the jsp page,because it is automatically mapped based on name given.
    2.Make sure the variable fields you are passing shouldn't reduntent.
    3.In mycase i perform a ajax call with passing a field(eg:userId) and on submitting the form (parameters passing also has userId).For this reason the error was thrown.Than i altered the name of ajax call parameter as (eg:userIdTemp),it works well.