-
Notifications
You must be signed in to change notification settings - Fork 38.5k
SpringBeanELResolver - setValue throws PropertyNotWritableException [SPR-11502] #16127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Amit commented
|
Juergen Hoeller commented ELResolvers are getting chained, so all we have to do here is to identify a (base, property) pair that is meant to be handled by us, and to react accordingly. It seems that we are mis-identifying a pair as ours there when it is rather meant to be handled by a different ELResolver... Could you please share details about when this is being invoked like that? Which expression triggers a setValue call with those parameter values? Juergen |
Amit commented We have a composite component defined that requires an handle to the parent backing bean. By parent backing bean I mean the backing bean of the page in which the composite component is rendered. The exception is seen for the expression where we inject the parent backing bean in the composite component backing bean. |
Amit commented Did the above comment help? |
Juergen Hoeller commented I have yet to dive further into the EL API here... It's still unclear to me why we get a setValue call with those parameter values in such a scenario. So in the debugger, you've seen that the 'value' parameter is identical to beanName? I suppose we could explicitly skip that case through a beanName.equals(value) check... Juergen |
Amit commented I tried jumping into the composite component code to get more details (sorry for not doing this earlier). We have overridden the processUpdates method of the UIComponentBase class in our composite component. We fetch the bindings and verify if any of the TagValueExpression's are readOnly(). If not, we try to set the value on it. The strange part is isReadOnly() returns true while setValue() throws an exception (both of them have similar method implementation in SpringBeanELResolver. Below is the composite component code.
About your question on debugging, yes the 'value' parameter refers to the backing bean instance which is identical to the string 'beanName'. I didn't completely follow what you meant by "explicitly skip that case through a beanName.equals(value) check". Do you refer to modifying setValue() method implementation? |
Juergen Hoeller commented Indeed, I was referring to relaxing setValue's assertion a bit. The general contract for an ELResolver requires us to find out whether the current resolver is applicable to the given (base, property) pair and to react accordingly. If we relax our assertion, i.e. don't throw an exception and let the call be propagated to the next ELResolver, we can't do much harm except for making debugging harder if the call fails later on. For that reason, we could selectively relax it for specific incoming parameters, along the lines of:
or, preventing propagation to further ELResolvers:
So it looks like you're checking isReadOnly() there first. However, if this returns true, that's exactly where setValue is supposed to throw a PropertyNotWritableException subsequently. Which makes me wonder: What exactly is that setValue call with property=beanName and value=beanName supposed to achieve? Technically, it suggests to set the beanName variable to itself? Is this simply a side effect of a general iteration algorithm and can effectively be ignored like in the second code sketch above? Juergen |
Amit commented
|
Juergen Hoeller commented OK, so the 'value' is the bean instance for the given bean name... We'd have to call getBean and check for equality against the instance then. The reason why setValue throws an exception is that we can't change the bean instance that a Spring bean name points to. So if a different value comes in for a Spring bean name here, we have to raise an exception. However, if the same instance is being specified for the bean name, we can effectively ignore the setValue call, since no actual state change is requested... Juergen |
Amit commented Ok, so would it be possible for you to add the above check in Spring ELResolver and provide a snapshot build that could be tested? |
Juergen Hoeller commented Alright, I've committed this to master, comparing the provided value to the current bean instance and not throwing a PropertyNotWritableException if they are identical. This will be available in the next 4.0.3 snapshot (see http://projects.spring.io/spring-framework/ for Maven coordinates). Juergen |
Amit opened SPR-11502 and commented
I am trying to upgrade spring from 3.2.1 to 4.0.2 which requires us to use <el-resolver> instead of <variable-resolver> (it was deprecated from quite sometime). The upgrade throws an PropertyNotWritableException after using SpringBeanFacesELResolver. The exception is thrown by the setValue() method which checks if the requested bean is present in the BeanFactory. If found, a PropertyNotWritableException is thrown. I would like to understand the root cause of the exception which is not clear from its implementation.
The setValue() implementation doesn't set the value but just do a check. On debugging I found the value of beanName, value and property refer to the same backing bean. Does that cause the issue? If so why?
Affects: 3.2.2
Backported to: 3.2.9
The text was updated successfully, but these errors were encountered: