This bug seems extremely fundamental to be a real bug so my initial thoughts are that I'm doing something completely wrong. An issue like this would have been discovered by now.
Brian Carr and I were working on some front end development for our project that leverages Quicksilver and Lightwire when we came across an bug in the UI. Whenever a form was submitted that contained form validation errors, it appeared to be returning correctly the first time. However if you were to submit the same form again, we noticed the error messages would continue to duplicate and stack. Initially we thought there was an issue with Quicksilver not configuring the beans correctly or perhaps we tagged our Errors object with a singleton annotation. After some digging into our bean configuration annotations, everything was annotated correctly.
So next step was to switch our dependency injection provider to ColdSpring, which Quicksilver allows you to do with one line. What happened to our surprise? It worked! The errors were displaying correctly. Ok, so now we know that the issue is Lightwire specific but didn't know whether it was a Quicksilver or Lightwire problem so we dug into Quicksilver's injection provider service for Lightwire. Perhaps we're wiring something incorrectly. After a good amount of investigation we verified Quicksilver was setting configuring beans correctly for Lightwire consumption.
Our next step was to completely bypass Quicksilver altogether. If we can configure these beans using just Lightwire and a scratch pad and still seeing this error then we can safely deduce that it was a problem in Lightwire. So here is what we found...
First, here is the jist of the classes involved. Both are TRANSIENT objects.
Simply, a BusinessServiceResponse has an Error object. For this example, the hashcode member is a unique hash that is attached to each unique instance.
Here is the code that we are using to test:
- Line 4 - 14 Configure the two transients - Errors and BusinessServiceResponse
- Line 16-20 Configure setter dependency. BusinessServiceResponse has an Errors property to be injected with the Errors transient object.
- Line 24-38 On the first iteration we are getting the bean for the first time then displaying the hashcode on the BusinessServiceResponse and the Errors. It's important to note that Errors hashcode is accessed through the BusinessServiceResponse on line 37.
Here are the results:
It appears that errors is being handled as a transient as the hashcode are identical across all three BusinessServiceResponse creations. Now that we know what the problem was, we dug into the Lightwire code. We found the issue in Lightwire.cfc. It loads setter dependencies as singletons by default??? Nooo, can't be.
On line 273, its creating each bean as a singleton. After replacing line 273 with an singleton/transient check like so:
It worked. Let's rerun our tests.
Hashcodes are different meaning now they are transients as well.
*** UPDATE 01/09/10 *** Do NOT use the code I posted as a fix as there has since been an official patch to fix this issue. Grab it from here. Many thanks to Peter Bell and Brian Rinaldi for their help and quick response on this!
Please guys, help me see the light...