Affects: 6.0.8


Language: Kotlin Spring Version: 6.0.8

I am using data binding for parsing form data into a form object. When using a singly nested map (Map<String, Map<String, String>), I find that using the key property[map1key][map2key] works as expected to set the nested value, but when adding another layer, e.g. Map<String, Map<String, Map<String, String>>> with key property[map1key][map2key][map3key] this fails with an exception cannot access indexed value of property referenced in indexed property path nested map.

Looking into the source code, I believe I tracked it down to the AbstractNestablePropertyAccessor.getPropertyValue(PropertyTokenHolder tokens) method which seems to only set the default value on the first token which explains why this works for a singly nested map but not a double or greater one. I suspect this affects any type of auto growing collection as well.

relevant snippet:

            if (tokens.keys != null) {
                if (value == null) {
                    if (isAutoGrowNestedPaths()) {
                        value = setDefaultValue(new PropertyTokenHolder(tokens.actualName));
                    }
                    else {
                        throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
                                "Cannot access indexed value of property referenced in indexed " +
                                        "property path '" + propertyName + "': returned null");
                    }
                }
                StringBuilder indexedPropertyName = new StringBuilder(tokens.actualName);
                // apply indexes and map keys
                for (int i = 0; i < tokens.keys.length; i++) {
                    String key = tokens.keys[i];
                    if (value == null) {
                        throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
                                "Cannot access indexed value of property referenced in indexed " +
                                        "property path '" + propertyName + "': returned null");
                    }

As a workaround, I'm using a single map with a custom key that I deserialize manually and then convert to a nested map in application code, but it would be nice if this was supported as part of the data binding.

Comment From: jhoeller

As far as I was able to reproduce this, the case only applies to multi-nested Map values. There is a dedicated code path for auto-growing map values in getPropertyHoldingValue which currently assumes one level only.