OFBiz
  1. OFBiz
  2. OFBIZ-3486

In some cases when you pass a list of GenericValues to <list-option in form widget you get an error saying GenericValues are not Map

    Details

    • Type: Wish Wish
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: Trunk
    • Fix Version/s: Trunk
    • Component/s: ALL APPLICATIONS
    • Labels:
      None

      Description

      In some cases when you pass a list of GenericValues to <list-option in form widget you get an error saying GenericValue is not Map.
      Of course this is true. But also this was working some days ago. At least it was working with the 909312 revision.

      It's easy to reproduce. In any OOTB form widget add these snippets:

      <set field="states" value="${groovy: org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)}" type="List"/>
      
      <field name="stateProvinceGeoId" >
          <drop-down allow-empty="false">
              <list-options list-name="states" key-name="geoId" description="${geoName}"/>
          </drop-down>
      </field>
      

      The error is
      ---- cause ---------------------------------------------------------------------
      Exception: java.lang.ClassCastException
      Message: Not a map
      ---- stack trace ---------------------------------------------------------------
      java.lang.ClassCastException: Not a map
      org.ofbiz.base.util.UtilGenerics.checkMap(UtilGenerics.java:77)
      org.ofbiz.widget.form.ModelFormField$ListOptions.addOptionValues(ModelFormField.java:1648)
      org.ofbiz.widget.form.ModelFormField$FieldInfoWithOptions.getAllOptionValues(ModelFormField.java:1529)
      org.ofbiz.widget.form.MacroFormRenderer.renderDropDownField(MacroFormRenderer.java:666)
      org.ofbiz.widget.form.ModelFormField$DropDownField.renderFieldString(ModelFormField.java:3043)
      org.ofbiz.widget.form.ModelFormField.renderFieldString(ModelFormField.java:595)
      org.ofbiz.widget.form.ModelForm.renderSingleFormString(ModelForm.java:1054)
      org.ofbiz.widget.form.ModelForm.renderFormString(ModelForm.java:837)
      org.ofbiz.widget.screen.ModelScreenWidget$Form.renderWidgetString(ModelScreenWidget.java:841)
      org.ofbiz.widget.screen.MacroScreenRenderer.renderScreenletSubWidget(MacroScreenRenderer.java:704)
      org.ofbiz.widget.screen.ModelScreenWidget$Screenlet.renderWidgetString(ModelScreenWidget.java:408)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$DecoratorSection.renderWidgetString(ModelScreenWidget.java:704)
      org.ofbiz.widget.screen.ModelScreenWidget$SectionsRenderer.render(ModelScreenWidget.java:167)
      org.ofbiz.widget.screen.ModelScreenWidget$DecoratorSectionInclude.renderWidgetString(ModelScreenWidget.java:736)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:228)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$DecoratorSection.renderWidgetString(ModelScreenWidget.java:704)
      org.ofbiz.widget.screen.ModelScreenWidget$SectionsRenderer.render(ModelScreenWidget.java:167)
      org.ofbiz.widget.screen.ModelScreenWidget$DecoratorSectionInclude.renderWidgetString(ModelScreenWidget.java:736)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$Container.renderWidgetString(ModelScreenWidget.java:296)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:228)
      org.ofbiz.widget.screen.ModelScreen.renderScreenString(ModelScreen.java:394)
      org.ofbiz.widget.screen.ModelScreenWidget$IncludeScreen.renderWidgetString(ModelScreenWidget.java:576)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:228)
      org.ofbiz.widget.screen.ModelScreen.renderScreenString(ModelScreen.java:394)
      org.ofbiz.widget.screen.ModelScreenWidget$DecoratorScreen.renderWidgetString(ModelScreenWidget.java:672)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:228)
      org.ofbiz.widget.screen.ModelScreen.renderScreenString(ModelScreen.java:394)
      org.ofbiz.widget.screen.ModelScreenWidget$DecoratorScreen.renderWidgetString(ModelScreenWidget.java:672)
      org.ofbiz.widget.screen.ModelScreenWidget.renderSubWidgetsString(ModelScreenWidget.java:137)
      org.ofbiz.widget.screen.ModelScreenWidget$Section.renderWidgetString(ModelScreenWidget.java:228)
      org.ofbiz.widget.screen.ModelScreen.renderScreenString(ModelScreen.java:394)
      org.ofbiz.widget.screen.ScreenRenderer.render(ScreenRenderer.java:135)
      org.ofbiz.widget.screen.ScreenRenderer.render(ScreenRenderer.java:97)
      org.ofbiz.widget.screen.MacroScreenViewHandler.render(MacroScreenViewHandler.java:104)
      org.ofbiz.webapp.control.RequestHandler.renderView(RequestHandler.java:835)
      org.ofbiz.webapp.control.RequestHandler.doRequest(RequestHandler.java:554)
      org.ofbiz.webapp.control.ControlServlet.doGet(ControlServlet.java:223)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
      org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      org.ofbiz.webapp.control.ContextFilter.doFilter(ContextFilter.java:266)
      org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
      org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
      org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
      org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
      org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:568)
      org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
      org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
      org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
      org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
      java.lang.Thread.run(Thread.java:619)
      --------------------------------------------------------------------------------

        Activity

        Hide
        Adrian Crum added a comment -

        It appears the List of Maps is being converted to a List of Strings. From ModelFormField.java line 1648:

        data = java.lang.String: {[GenericEntity:GeoAssocAndGeoTo][abbreviation,AA(java.lang.String)][geoAssocTypeId,REGIONS(java.lang.String)][geoCode,AA(java.lang.String)][geoId,AA(java.lang.String)][geoIdFrom,USA(java.lang.String)][geoName,Armed Forces Americas(java.lang.String)][geoSecCode,null()][geoTypeId,STATE(java.lang.String)][wellKnownText,null()], [GenericEntity:GeoAssocAndGeoTo][abbreviation,AE(java.lang.String)][geoAssocTypeId,REGIONS(java.lang.String)][geoCode,AE(java.lang.String)][geoId,AE(java.lang.String)][geoIdFrom,USA(java.lang.String)][geoName,Armed Forces Europe(java.lang.String)][geoSecCode,null()][geoTypeId,STATE(java.lang.String)][wellKnownText,null()], [GenericEntity:GeoAssocAndGeoTo][abbreviation,AK(java.lang.String)][geoAssocTypeId,REGIONS(java.lang.String)][geoCode,AK(java.lang.String)][geoId,AK(java.lang.String)][geoIdFrom,USA(java.lang.String)][geoName,Alaska(java.lang.String)][geoSecCode,null()][geoTypeI

        I don't have time to look into this right away.

        Show
        Adrian Crum added a comment - It appears the List of Maps is being converted to a List of Strings. From ModelFormField.java line 1648: data = java.lang.String: { [GenericEntity:GeoAssocAndGeoTo] [abbreviation,AA(java.lang.String)] [geoAssocTypeId,REGIONS(java.lang.String)] [geoCode,AA(java.lang.String)] [geoId,AA(java.lang.String)] [geoIdFrom,USA(java.lang.String)] [geoName,Armed Forces Americas(java.lang.String)] [geoSecCode,null()] [geoTypeId,STATE(java.lang.String)] [wellKnownText,null()] , [GenericEntity:GeoAssocAndGeoTo] [abbreviation,AE(java.lang.String)] [geoAssocTypeId,REGIONS(java.lang.String)] [geoCode,AE(java.lang.String)] [geoId,AE(java.lang.String)] [geoIdFrom,USA(java.lang.String)] [geoName,Armed Forces Europe(java.lang.String)] [geoSecCode,null()] [geoTypeId,STATE(java.lang.String)] [wellKnownText,null()] , [GenericEntity:GeoAssocAndGeoTo] [abbreviation,AK(java.lang.String)] [geoAssocTypeId,REGIONS(java.lang.String)] [geoCode,AK(java.lang.String)] [geoId,AK(java.lang.String)] [geoIdFrom,USA(java.lang.String)] [geoName,Alaska(java.lang.String)] [geoSecCode,null()] [geoTypeI I don't have time to look into this right away.
        Hide
        Adam Heath added a comment -

        This is a not an issue. ModelScreenAction.SetField uses FlexibleStringExpander for the value, the result of which will always be a string, period. If you were trying to return some random object, then what would occur previously is that said object would be turned into a String, and ObjectType would then turn it back into the final object. This is very very broken.

        I see several instances of forms that use <set> to create a list of things, which gets converted to a string, then parsed out of the string, back into real objects. This is so very very broken.

        Show
        Adam Heath added a comment - This is a not an issue. ModelScreenAction.SetField uses FlexibleStringExpander for the value, the result of which will always be a string, period. If you were trying to return some random object, then what would occur previously is that said object would be turned into a String, and ObjectType would then turn it back into the final object. This is very very broken. I see several instances of forms that use <set> to create a list of things, which gets converted to a string, then parsed out of the string, back into real objects. This is so very very broken.
        Hide
        Adam Heath added a comment -

        Oops, remove that first 'This is not an issue". Instead, this is an issue, but not because of what you think.

        It may have worked for you before that commit, but that is because I changed the conversion system to use json when converting to/from map/list, but this was a change that Adrian said shouldn't be done(and I agree with him).

        Show
        Adam Heath added a comment - Oops, remove that first 'This is not an issue". Instead, this is an issue, but not because of what you think. It may have worked for you before that commit, but that is because I changed the conversion system to use json when converting to/from map/list, but this was a change that Adrian said shouldn't be done(and I agree with him).
        Hide
        Adam Heath added a comment -

        I also made the mistake of putting the set into the screen definition, but my analysis still holds for form actions too, ModelFormAction.SetField also uses FlexibleStringExpander for the value.

        Show
        Adam Heath added a comment - I also made the mistake of putting the set into the screen definition, but my analysis still holds for form actions too, ModelFormAction.SetField also uses FlexibleStringExpander for the value.
        Hide
        David E. Jones added a comment -

        This is maybe unfortunate, but there is an easy work-around (a hack) that I'll admit I've used a number of times:

        <set field="foo" value="$

        {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)}

        "/>

        With this the states variable is set in the groovy script and not by the set action. It's basically a hack for running an inline script (which would be nice to support under the script action, but that currently only support calling external scripts).

        Jacques: HTH

        Show
        David E. Jones added a comment - This is maybe unfortunate, but there is an easy work-around (a hack) that I'll admit I've used a number of times: <set field="foo" value="$ {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)} "/> With this the states variable is set in the groovy script and not by the set action. It's basically a hack for running an inline script (which would be nice to support under the script action, but that currently only support calling external scripts). Jacques: HTH
        Hide
        Adrian Crum added a comment -

        Adam,

        Thanks to your comments, I think I know what happened. The original code would convert the script result (a List) to a String using the home-grown serialization code. You changed that to convert the List to a JSON String. When you reverted your change, you didn't put it back to converting a List to the home-grown serialization - probably because of my comment about wanting predictable behavior and any Object converted to a String is the same as calling that Object's toString method.

        To maintain backward compatibility, I think we need to change the List to String conversion back to the way it was.

        Show
        Adrian Crum added a comment - Adam, Thanks to your comments, I think I know what happened. The original code would convert the script result (a List) to a String using the home-grown serialization code. You changed that to convert the List to a JSON String. When you reverted your change, you didn't put it back to converting a List to the home-grown serialization - probably because of my comment about wanting predictable behavior and any Object converted to a String is the same as calling that Object's toString method. To maintain backward compatibility, I think we need to change the List to String conversion back to the way it was.
        Hide
        Adrian Crum added a comment -

        Okay, never mind. I just tried it in R 9.04 and it doesn't work there either.

        This has nothing to do with converter code changes.

        Show
        Adrian Crum added a comment - Okay, never mind. I just tried it in R 9.04 and it doesn't work there either. This has nothing to do with converter code changes.
        Hide
        Adam Heath added a comment -

        I have this working locally, exactly as you would like to use it. It'll take me a bit to get something committed tho, as I want to have full test cases for FlexibleStringExpander first.

        Basically, I added an expand method to FSE, similiar to expandString, that doesn't convert the object to a String, then modified SetField to call the new method.

        Show
        Adam Heath added a comment - I have this working locally, exactly as you would like to use it. It'll take me a bit to get something committed tho, as I want to have full test cases for FlexibleStringExpander first. Basically, I added an expand method to FSE, similiar to expandString, that doesn't convert the object to a String, then modified SetField to call the new method.
        Hide
        Jacques Le Roux added a comment -

        Hi Guys,

        Back from the moutain, no sport but good hikes

        It seems that there is a solution, and a workaround for the meantime, more than enough to keep me happy. Thank you!

        Show
        Jacques Le Roux added a comment - Hi Guys, Back from the moutain, no sport but good hikes It seems that there is a solution, and a workaround for the meantime, more than enough to keep me happy. Thank you!
        Hide
        Jacques Le Roux added a comment -

        Hi,

        I tried David's tip this morning, not successful so far (I tried some variations): does not seem to work with list. From Adam's comment in svn log it seems he got it working. I'm updating and trying...

        Show
        Jacques Le Roux added a comment - Hi, I tried David's tip this morning, not successful so far (I tried some variations): does not seem to work with list. From Adam's comment in svn log it seems he got it working. I'm updating and trying...
        Hide
        Jacques Le Roux added a comment -

        For the moment (at r912531) I get a class cast exception

        ---- cause ---------------------------------------------------------------------
        Exception: java.lang.ClassCastException
        Message: null
        ---- stack trace ---------------------------------------------------------------
        java.lang.ClassCastException
        java.lang.Class.cast(Unknown Source)
        org.ofbiz.base.util.UtilGenerics.checkCollectionCast(UtilGenerics.java:39)
        org.ofbiz.base.util.UtilGenerics.checkList(UtilGenerics.java:67)
        org.ofbiz.widget.form.ModelFormField$ListOptions.addOptionValues(ModelFormField.java:1640)

        I have no time to look at it yet, I just saw that maybe something/somewere should transforms from a

        {[GenericEntity:GeoAssocAndGeoTo]....[GenericEntity:GeoAssocAndGeoTo]}

        to a list of GenericEntity:GeoAssocAndGeoTo

        before calling UtilGenerics.checkList() at ModelFormField.java:1640

        Show
        Jacques Le Roux added a comment - For the moment (at r912531) I get a class cast exception ---- cause --------------------------------------------------------------------- Exception: java.lang.ClassCastException Message: null ---- stack trace --------------------------------------------------------------- java.lang.ClassCastException java.lang.Class.cast(Unknown Source) org.ofbiz.base.util.UtilGenerics.checkCollectionCast(UtilGenerics.java:39) org.ofbiz.base.util.UtilGenerics.checkList(UtilGenerics.java:67) org.ofbiz.widget.form.ModelFormField$ListOptions.addOptionValues(ModelFormField.java:1640) I have no time to look at it yet, I just saw that maybe something/somewere should transforms from a {[GenericEntity:GeoAssocAndGeoTo]....[GenericEntity:GeoAssocAndGeoTo]} to a list of GenericEntity:GeoAssocAndGeoTo before calling UtilGenerics.checkList() at ModelFormField.java:1640
        Hide
        Jacques Le Roux added a comment -

        Actually the above came from one of my try with this line

        <set field="states" value="$

        {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)}

        "/>

        If I add <<type="List">> at EOL, I still get the "Not a map" exception

        <set field="states" value="$

        {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)}

        " type="List"/>

        If I use the line David suggested

        <set field="void" value="$

        {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)}

        "/>

        it looks like states is empty but
        <set field="size" value="$

        {groovy: states.isEmpty()}

        " type="Boolean"/>
        is false. Tough if I try to get the 1st element using .get(0), I get anything. Still looking at that because it sounds weird to me...

        Show
        Jacques Le Roux added a comment - Actually the above came from one of my try with this line <set field="states" value="$ {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)} "/> If I add <<type="List">> at EOL, I still get the "Not a map" exception <set field="states" value="$ {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)} " type="List"/> If I use the line David suggested <set field="void" value="$ {groovy: states = org.ofbiz.common.CommonWorkers.getAssociatedStateList(delegator, null)} "/> it looks like states is empty but <set field="size" value="$ {groovy: states.isEmpty()} " type="Boolean"/> is false. Tough if I try to get the 1st element using .get(0), I get anything. Still looking at that because it sounds weird to me...
        Hide
        Jacques Le Roux added a comment -

        Also for the last case, if I use
        <set field="state" value="$

        {states[0].abbreviation}

        "></set>
        I get nothing when displaying state

        Show
        Jacques Le Roux added a comment - Also for the last case, if I use <set field="state" value="$ {states[0].abbreviation} "></set> I get nothing when displaying state
        Hide
        Adam Heath added a comment -

        My guess as to why David's suggestion doesn't work, is that the assigned states variable has a scope that is active for just the compiled groovy line.

        In any event, I have this working now for you in 912645.

        Show
        Adam Heath added a comment - My guess as to why David's suggestion doesn't work, is that the assigned states variable has a scope that is active for just the compiled groovy line. In any event, I have this working now for you in 912645.
        Hide
        Jacques Le Roux added a comment -

        Sorry to say that this bug has reappeared (using r915869)

        Show
        Jacques Le Roux added a comment - Sorry to say that this bug has reappeared (using r915869)
        Hide
        Adam Heath added a comment -

        I reverted the new version in 912645, as this broke logging into /ap or /ar, the front page had a bad exception after logging in.

        Since this is a new feature, it was better to turn it off until it can be investigated further.

        Show
        Adam Heath added a comment - I reverted the new version in 912645, as this broke logging into /ap or /ar, the front page had a bad exception after logging in. Since this is a new feature, it was better to turn it off until it can be investigated further.
        Hide
        Jacques Le Roux added a comment -

        Thanks Adam,

        I will then certainly investigate on the AP/AR issue...

        Show
        Jacques Le Roux added a comment - Thanks Adam, I will then certainly investigate on the AP/AR issue...
        Hide
        Jacques Le Roux added a comment -

        Fixed at r918476

        Show
        Jacques Le Roux added a comment - Fixed at r918476

          People

          • Assignee:
            Adam Heath
            Reporter:
            Jacques Le Roux
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development