No announcement yet.
  • Filter
  • Time
Clear All
new posts

    Combining Client and Server AdvancedCriteria on the Server Side

    SmartClient Version: v12.1p_2021-10-22/PowerEdition Deployment (built 2021-10-22)

    I asked a similar question here:

    I don't really want to go down a recursive parsing solution again.

    I have a complicated (many cases) AdvancedCriteria coming down from the client. So

    AdvancedCriteria c = dsRequest.getAdvancedCriteria();

    gives me the client set.

    I have an additional AdvancedCriteria that I want to add on the server to this client set.

    A simple:

    secCrit = new AdvancedCriteria(DefaultOperators.And.getID(), new Criterion[] {
                        serverCriteria.asCriterion() } );
    seems to have just added "AND '1' = '1' " into the secCrit criteria in the resulting fetch.

    I can see the value of secCrit in the eclipse debugger and it has added the criteria, but likely in the wrong (?) way or place.

    This is what the secCrit contains after the attempt to combine them:

    AdvancedCriteria:[and:[and:[and:[or:[and:[{ProjName iStartsWith BCM721}, {Revision iContains B}], {ProjName iStartsWith BCM31}, {ProjName iStartsWith BCM271}, {ProjName iStartsWith BCM688}, {ProjName iContains BCM339}, and:[{ProjName iStartsWith BCM741}, {Revision iContains 0}], and:[{ProjName iStartsWith DDR16}, {Revision iContains 2}], and:[{ProjName iStartsWith BCM78}, {Revision iContains 0}], and:[{ProjName iContains QA}, {Revision iContains A}]], {ServerGroupBy equals [
    ]}, {treeTitleField equals Signoff_Rundir_Name}], {Parent_Id equals -1}], and:[{FULL_NAV_TREE.ProjName iNotEqual QA_Project}, {FULL_NAV_TREE.Revision iNotEqual A2}]]]
    The value of serverCriteria is: 'and:[{FULL_NAV_TREE.ProjName iNotEqual QA_Project}, {FULL_NAV_TREE.Revision iNotEqual A2}]'

    Is there a proper way of adding the server side criteria to the client side.?

    Just a note that recursive parsing was required before because you wanted to flatten AdvancedCriteria into fieldName <-> criterion, but that's not actually valid since an AdvancedCriteria could contain multiple criteria for the same fieldName.

    As far as this use case, it's straightforward, but your code so far just creates an AdvancedCriteria - presumably you are doing setCriteria() on a DSRequest to actually change the criteria? Note there are also helper methods like dsRequest.addToCriteria() you can use.

    As far as seeing 1=1, this would result from invalid criteria, such as criteria that is being applied to a field that doesn't exist in the target DataSource. The logs will tell you why a specific criterion had to be ignored.


      thanks for the response.

      I have my case almost working - works for adding a SINGLE AdvancedCriteria to the passed client side AdvancedCriteria.

      In this new case I have an ArrayList< AdvancedCriteria> list.

      The members of the list are AdvancedCriteria of the form { AND, {field1 equals val1},{ field2 equals val2} }, there may be 1 or more entries in the array.

      I want to finally generate an AdvancedCriteria of the OR of all the elements of list.

      AdvancedCriteria final = { 'OR' , List[0], List[1], ..... List[n] }

      I have tried this code and get a null:

      secCriteria = AdvancedCriteria.fromCollections(list.toArray(new AdvancedCriteria[list.size()]), DefaultOperators.Or.getID());
      // and this code:
      secCriteria = new AdvancedCriteria( DefaultOperators.Or.getID(),  new Criterion ( list.toArray(new AdvancedCriteria[list.size()]));
      // which throws an exception
      There must be a simple way of adding a list of AdvancedCriteria into a single ORed AdvancedCriteria?


        We might be missing something, but why wouldn't you just create an OrCriterion? The constructor takes a List or Array of Criterion.

        Note that "fromCollections()" is for dealing with the JSON-like "nested Lists of Maps" serialization format that is used to transmit criteria between browser and server. There wouldn't really be a reason to use that unless you happen to like that way of creating criteria.


          If its not one thing then it must be yet another.

          Your suggestion of simply using an OrCriterion worked. The final criterion I create, is a NOT of the OrCriterion [] as an AdvancedCriteria

           secCriteria = new AdvancedCriteria(DefaultOperators.Not.getID(), new Criterion[] { secOrCrit });
          // I then need to save this into the session HttpSession context, for use within the session
          session.setAttribute("secCriteria", secCriteria);
          Here eclipse points out that the session variable should be Serialized. I have attempted to use the utility to encode the secCriteria into JSON, and then to retrieve this session variable as JSON when I later need to use the criteria, but as an AdvancedCriteria. But the simple usage does not work, i.e. GSon.toJson() followed later by GSon.fromJson(session variable as string).

          I'm looking for advice on how to 'Serialize' the secCriteria into the session, and then correctly retrieve it later. I believe I have to encode it going in, and correctly decode it coming out of the session. But the GSON utility is set up to decode standard Java types, List, Map, etc. and the type of the secCriteria is AdvancedCriteria.

          Should I be using the static AdvancedCriteria.decodeClientCriteria() function? How do you recommend I carry out the Serialization and De-Serialization of the AdvancedCriteria?

          If I ignore the eclipse warning about Serialization and simply read the session variable for the "secCriteria" entry, this all works, but....


            You probably already know this, but the warning basically means that since the objects aren't serializable, in a clustered deployment there would be no migrate the session data around.

            We would typically store the criteria in the same JSON format that you can use in JavaScript to declare an AdvancedCriteria - which is the format you see if you look at the request objects in the RPC tab. In Java, each Criterion is a Map with "field", "operator", "value" keys, and then subcriteria (for logical operators) are just Lists of more Maps.

            If you do the conversion from AdvancedCriteria / Criterion objects to this nested List of Maps format, at least the other direction is free, because you can call fromCollections().

            Sorry that this is another recursive algorithm, but, ChatGPT can probably write this one for you (it knows about our APIs).
            Last edited by Isomorphic; 8 Feb 2023, 17:02.


              All working now. I converted the AdvancedCriteria to a Map using the getCriteriaAsMap() api. Then GSon.toJson(Map) as a String, and saved the String to the session context.
              When retrieving the Criterion from the session variable I then made use of the AdvancedCriteria.fromCollections(Map) having decoded the session value from the JSON string to a Map.


                Great! We were actually taking a look at getCriteriaAsMap() and thinking we'd augment it and document it so that it's a clear parallel to fromCollections().

                Just a note that you if you have Date values in the criteria you'll need to carefully consider those, since JSON cannot directly represent dates, and also there is the distinction between date, datetime & time types to consider.