Search code examples
hashcollectionssequencefreemarker

Retrieving values from an extended hash in freemarker


I have a data set that looks like this:

{
    "dataSet": [{
        "@etag": "2020-02-21T09:11:19.408         ",
        "text": "customer-old (ts001233)",
        "archived": true,
        "id": "932654d6-3f3b-452d-b256-66b9902a8952"
    }, {
        "@etag": "2021-12-21T21:12:13.648         ",
        "text": "customer (ts001234)",
        "archived": false,
        "id": "932654d6-3f3b-452d-b256-66b9902a8952"
    }, {
        "@etag": "2021-12-17T21:07:36.587         ",
        "text": "customer-test (ts001235)",
        "archived": false,
        "id": "85533cc2-320c-4d74-87e6-3233d26c8351"
    }],
    "templates": []
}

I'm trying to extract the value "customer (ts001234)", which I can do using the following code:

<#list dataSet as environments><#if environments.archived=false && !environments.text?contains('-test')>${environments.text}</#if></#list>

The problem is that this code relies on filtering a text value (-test) which I'd rather not use since the text values may vary. Instead, I want to retrieve the first non archived environment.

I tried using ?first :

<#list dataSet as environments><#if environments.archived=false && !environments.text?contains('-test')>${environments?first.text}</#if></#list>

But that leads to an error:

For "?first" left-hand operand: Expected a sequence or collection, but this has evaluated to an extended_hash (LinkedHashMap wrapped into f.t.DefaultMapAdapter):
==> environments  [in nameless template at line 1, column 119]

Can someone please give me some pointers on how to retrieve this value without filtering the text?


Solution

  • Assuming environments corresponds to [{"@etag": ...}, ...] in your example, what you tried to do, I guess, is this:

    <#assign firstUnarchived = environments?filter(it -> !it.archived)[0]>
    

    This will fail if you have no unarchived entry though. So probably you want just assign environments?filter(it -> !it.archived) to a variable (without the [0]), let's say unarchivedEnvs, and then check if unarchivedEnvs?size != 0, etc.

    In case you are using a FreeMarker version older than 2.3.29, where you will have to use #list for this, when you find the first match with #if, you can exit the loop with <#break>.