Uploaded image for project: 'Kuali Rice Development'
  1. Kuali Rice Development
  2. KULRICE-6845

Problems with UifBeanFactoryPostProcessor expression handling that is causing bean property overrides (such as fieldInquiry.render) to not work

    Details

    • Type: Bug Fix
    • Status: Closed
    • Priority: Critical
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 2.2.0-rc1, 2.2
    • Component/s: Development
    • Security Level: Public (Public: Anyone can view)
    • Labels:
      None
    • Rice Module:
      KRAD
    • KAI Review Status:
      Not Required
    • KTI Review Status:
      Not Required

      Description

      The UifBeanFactoryPostProcessor is a Spring bean post processor (http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-factory-extension-bpp) that is used to handle expressions defined in beans. These are special property values that contain the @

      {...}

      syntax that the UIF framework uses to evaluate conditional statements. These are allowed for any property type (string, boolean, integer). However, Spring does not know how to handle them. So when spring creates the objects from a bean definition and tries to set a value containing one of these for a non-string type (like boolean) an exception will be thrown (of course the string '@

      {foo}

      ' is not a valid boolean). Therefore we pull these expressions out before Spring creates the objects.

      Basically the post processor iterates through all the container beans and finds ones that implement the Configurable interface. For those that do, it then iterates through all the configured properties and inspects the configured value. If the value has the expression placeholder, it pulls the expression out to a Map. The Map key gives the property name that contained the expression and the Map value is the expression. This Map is then set as a property on the object (named 'propertyExpressions'). The original configured property is then removed (so it appears to Spring as if it was never set). When the view is being processed in code, the expressions are then evaluated and the evaluation result is used to set the property value.

      This sounds simple but is actually very complicated due to bean inheritance. Consider the following example:

      <bean id="MyBean" class="MyClass">
      <property name="field1" value="@

      {1 eq 1}"/>
      </bean>

      <bean id="YourBean" parent="MyBean">
      <property name="field1" value="false"/>
      </bean>

      The UIF processor will first process MyBean, finds the expression, and changes the bean definition to:

      <bean id="MyBean" class="MyClass">
      <property name="propertyExpressions">
      <map>
      <entry key="field1" value="@{1 eq 1}

      "/>
      </map>
      </property>
      </bean>

      Now YourBean doesn't have any expressions, so it is left alone. Spring will now merge these definitions and YourBean becomes:

      <bean id="YourBean" class="MyClass">
      <property name="field1" value="false"/>
      <property name="propertyExpressions">
      <map>
      <entry key="field1" value="@

      {1 eq 1}

      "/>
      </map>
      </property>
      </bean>

      These are two separate properties, so Spring populates them both on the object. Field1 is initially set to false (what we expect it to be). However, since there is an expression in the view processing it will get evaluated, in this case (1 does equal 1) will result in true, so the framework sets field1 to true.

      Therefore when doing the post processing we need to look at the parent bean definition, and if there are any keys of the propertyExpressions Map which match a property configured on the child bean, remove the expression so it does not override the child setting. That is in place and appears to be working.

      But then it gets more complicated, and that is do to nested property configuration. Consider this example:

      <bean id="HisBean" class="HisClass">
      <property name="myBeanRef">
      <bean parent="MyBean"/>
      </property>
      </bean>

      <bean id="HerBean" parent="HisBean">
      <property name="myBeanRef.field1" value="false"/>
      </bean>

      The MyBean is nested in His and Her Beans. The same thing should happen in the nested HerBean object, the expression inherited needs to be cleared. These nested beans though are processed as part of the parent bean, and thus don't have their own standalone bean definition in the container. Furthermore the nested path can be more than two levels, so the beans at each level need to be checked for expressions to clear. This process was started but due to time constraints not finished. (By the way this is why setting fieldInquiry.render to false is not working)

      In UifBeanFactoryPostProcessor there is a method named removeParentExpressionsOnNested whose call is currently commented out. We need to finish the logic on this (if the current logic is doable, needs reviewed) and enable the call.

      I would recommend coming up with many different examples and documenting the post processing. It gets very confusing to keep straight and to make sure we are covering everything.

        Attachments

          Issue Links

            Activity

            Hide
            jkneal Jerry Neal (Inactive) added a comment -

            Mostly done, one minor issue with maps

            Show
            jkneal Jerry Neal (Inactive) added a comment - Mostly done, one minor issue with maps
            Hide
            jkneal Jerry Neal (Inactive) added a comment -

            Work left:

            • spring support of nested map merging
            • expressions in primitive (string) lists not handled correctly
            Show
            jkneal Jerry Neal (Inactive) added a comment - Work left: spring support of nested map merging expressions in primitive (string) lists not handled correctly
            Hide
            jcoltrin Jessica Coltrin (Inactive) added a comment -

            moving m4 criticals and blockers to rc1

            Show
            jcoltrin Jessica Coltrin (Inactive) added a comment - moving m4 criticals and blockers to rc1
            Hide
            jkneal Jerry Neal (Inactive) added a comment -

            Hey Matt,

            Would you create another issue for the problems we have with the Spring framework and link the spring Jiras. Then we can close this one.

            thanks,
            Jerry

            Show
            jkneal Jerry Neal (Inactive) added a comment - Hey Matt, Would you create another issue for the problems we have with the Spring framework and link the spring Jiras. Then we can close this one. thanks, Jerry
            Hide
            matthew.wuertz Matthew Wuertz (Inactive) added a comment -

            I added a new issue (KULRICE-8425) to address the nesting problems that rely upon Spring fixing their framework.

            Show
            matthew.wuertz Matthew Wuertz (Inactive) added a comment - I added a new issue ( KULRICE-8425 ) to address the nesting problems that rely upon Spring fixing their framework.

              People

              • Assignee:
                matthew.wuertz Matthew Wuertz (Inactive)
                Reporter:
                jkneal Jerry Neal (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                0 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: