Recursive calls with Map work, but not List

This is probably been a feature for the 20 years that I have been using OFBiz and Moqui, but I am forgetting a lot these days.

If I pass a Map object as a service parameter, I can pass it recursively and the context is preserved, but not if I pass a list object.

I have demo scripts for both cases, but it would make this a very long post and I am hoping that someone will just explain that it has something to do with ContextStack and tell me how to fix it (I can easily make a workaround, but I would rather do it right)

I’ll add the demo cases here:

List-based calling code:

    <transition name="testParamPass" read-only="true">
        <actions>
            <set field="depth" from="0" type="Integer" />
            <set field="ancestryList" from="new ArrayList()" type="List" />
            <log message="testParamPass (transition), depth: ${depth}, ancestryList: ${ancestryList}" />
            <service-call name="TestServices.testParamPass" in-map="[depth:depth, ancestryList:ancestryList]" out-map="testOut"/>
            <log message="testParamPass (transition-2), depth: ${depth}, ancestryList: ${ancestryList}" />
        </actions>
        <default-response url=".">
        </default-response>
    </transition>

List-based service:

    <service verb="test" noun="ParamPass">
        <description>Isolating problem with recursive call</description>
        <in-parameters>
            <parameter name="depth" type="Integer"/>
            <parameter name="ancestryList" type="List"/>

        </in-parameters>
        <out-parameters>
        </out-parameters>
        <actions>
            <log message="testParamPass context: ${context}" />
            <set field="newDepth" from="++depth" />
            <if condition="newDepth &lt; 4">
                <set field="dummy" from="ancestryList.add(newDepth)" />
                <service-call name="TestServices.testParamPass" in-map="[depth:newDepth, ancestryList:ancestryList]" out-map="testOut"/>
            </if>
            <log message="testParamPass depth: ${newDepth}, ancestryList: ${ancestryList}" />
        </actions>
    </service>

List-based console output:

testParamPass context: [result:[:], depth:0, ec:ExecutionContext, ancestryList:[]]
[result:[:], depth:1, ec:ExecutionContext, ancestryList:[1]]
 [result:[:], depth:2, ec:ExecutionContext, ancestryList:[1, 2]]
[result:[:], depth:3, ec:ExecutionContext, ancestryList:[1, 2, 3]]
testParamPass depth: 4, ancestryList: [1, 2, 3]
testParamPass depth: 3, ancestryList: [1, 2, 3]
testParamPass depth: 2, ancestryList: [1, 2]
depth: 1, ancestryList: [1]
testParamPass (transition-2), depth: 0, ancestryList: [1]

Map-based calling code:

    <transition name="testParamPassMap" read-only="true">
        <actions>
            <set field="testMap" from="[depth:0,ancestryList:[]]" type="Map" />
            <log message="testParamPassMap (transition-1), testMap: ${testMap}" />
            <service-call name="TestServices.testParamPassMap" in-map="[testMap:testMap]" out-map="testOut"/>
            <log message="testParamPassMap (transition-2), testMap: ${testMap}" />
        </actions>
        <default-response url=".">
        </default-response>
    </transition>
 

Map-based service:

    <service verb="test" noun="ParamPassMap">
        <description>Isolating problem with recursive call</description>
        <in-parameters>
            <parameter name="testMap" type="Map"/>
        </in-parameters>
        <out-parameters>
        </out-parameters>
        <actions>
            <log message="testParamPassMap context: ${context}" />
            <set field="newDepth" from="++testMap.depth" />
            <set field="testMap.depth" from="newDepth" />
            <if condition="newDepth &lt; 4">
                <set field="dummy" from="testMap.ancestryList.add(newDepth)" />
                <service-call name="TestServices.testParamPassMap" in-map="[testMap:testMap]" out-map="testOut"/>
            </if>
            <log message="testParamPassMap depth: ${testMap.depth}, ancestryList: ${testMap.ancestryList}" />
        </actions>
    </service>

Map-based console output:

testParamPassMap (transition-1), testMap: [depth:0, ancestryList:[]]
testParamPassMap context: [testMap:[depth:0, ancestryList:[]], result:[:], ec:ExecutionContext]
testParamPassMap context: [testMap:[depth:1, ancestryList:[1]], result:[:], ec:ExecutionContext]
testParamPassMap context: [result:[:], ec:ExecutionContext, testMap:[depth:2, ancestryList:[1, 2]]]
testParamPassMap context: [result:[:], testMap:[depth:3, ancestryList:[1, 2, 3]], ec:ExecutionContext]
testParamPassMap depth: 4, ancestryList: [1, 2, 3]
testParamPassMap depth: 4, ancestryList: [1, 2, 3]
testParamPassMap depth: 4, ancestryList: [1, 2, 3]
testParamPassMap depth: 4, ancestryList: [1, 2, 3]
testParamPassMap (transition-2), testMap: [depth:4, ancestryList:[1, 2, 3]]