Skip to content

Commit 500205e

Browse files
authored
Add painless method getByPath, get value from nested collections with dotted path (#43170) (#43606)
Given a nested structure composed of Lists and Maps, getByPath will return the value keyed by path. getByPath is a method on Lists and Maps. The path is string Map keys and integer List indices separated by dot. An optional third argument returns a default value if the path lookup fails due to a missing value. Eg. ['key0': ['a', 'b'], 'key1': ['c', 'd']].getByPath('key1') = ['c', 'd'] ['key0': ['a', 'b'], 'key1': ['c', 'd']].getByPath('key1.0') = 'c' ['key0': ['a', 'b'], 'key1': ['c', 'd']].getByPath('key2', 'x') = 'x' [['key0': 'value0'], ['key1': 'value1']].getByPath('1.key1') = 'value1' Throws IllegalArgumentException if an item cannot be found and a default is not given. Throws NumberFormatException if a path element operating on a List is not an integer. Fixes #42769
1 parent 2fa6bc5 commit 500205e

File tree

6 files changed

+430
-1
lines changed

6 files changed

+430
-1
lines changed

docs/painless/painless-api-reference/painless-api-reference-score/packages.asciidoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ See the <<painless-api-reference-score, Score API>> for a high-level overview of
3030
* List findResults(Function)
3131
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
3232
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
33+
* Object getByPath(String)
34+
* Object getByPath(String, Object)
3335
* int getLength()
3436
* Map groupBy(Function)
3537
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -84,6 +86,8 @@ See the <<painless-api-reference-score, Score API>> for a high-level overview of
8486
* List findResults(Function)
8587
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
8688
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
89+
* Object getByPath(String)
90+
* Object getByPath(String, Object)
8791
* int getLength()
8892
* Map groupBy(Function)
8993
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -138,6 +142,8 @@ See the <<painless-api-reference-score, Score API>> for a high-level overview of
138142
* List findResults(Function)
139143
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
140144
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
145+
* Object getByPath(String)
146+
* Object getByPath(String, Object)
141147
* int getLength()
142148
* Map groupBy(Function)
143149
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()

docs/painless/painless-api-reference/painless-api-reference-shared/packages.asciidoc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4335,6 +4335,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
43354335
* List findResults(Function)
43364336
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
43374337
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
4338+
* Object getByPath(String)
4339+
* Object getByPath(String, Object)
43384340
* int getLength()
43394341
* Map groupBy(Function)
43404342
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -4386,6 +4388,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
43864388
* List findResults(BiFunction)
43874389
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
43884390
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
4391+
* Object getByPath(String)
4392+
* Object getByPath(String, Object)
43894393
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
43904394
* Map groupBy(BiFunction)
43914395
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -4500,6 +4504,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
45004504
* List findResults(Function)
45014505
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
45024506
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
4507+
* Object getByPath(String)
4508+
* Object getByPath(String, Object)
45034509
* int getLength()
45044510
* Map groupBy(Function)
45054511
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -4666,6 +4672,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
46664672
* List findResults(Function)
46674673
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
46684674
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
4675+
* Object getByPath(String)
4676+
* Object getByPath(String, Object)
46694677
* int getLength()
46704678
* Map groupBy(Function)
46714679
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -5367,6 +5375,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
53675375
* List findResults(BiFunction)
53685376
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
53695377
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
5378+
* Object getByPath(String)
5379+
* Object getByPath(String, Object)
53705380
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
53715381
* Map groupBy(BiFunction)
53725382
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -5457,6 +5467,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
54575467
* List findResults(BiFunction)
54585468
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
54595469
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
5470+
* Object getByPath(String)
5471+
* Object getByPath(String, Object)
54605472
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
54615473
* Map groupBy(BiFunction)
54625474
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -5502,6 +5514,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
55025514
* List findResults(BiFunction)
55035515
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
55045516
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
5517+
* Object getByPath(String)
5518+
* Object getByPath(String, Object)
55055519
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
55065520
* Map groupBy(BiFunction)
55075521
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -5668,6 +5682,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
56685682
* List findResults(BiFunction)
56695683
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
56705684
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
5685+
* Object getByPath(String)
5686+
* Object getByPath(String, Object)
56715687
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
56725688
* Map groupBy(BiFunction)
56735689
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -5764,6 +5780,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
57645780
* List findResults(Function)
57655781
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
57665782
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
5783+
* Object getByPath(String)
5784+
* Object getByPath(String, Object)
57675785
* def {java11-javadoc}/java.base/java/util/Deque.html#getFirst()[getFirst]()
57685786
* def {java11-javadoc}/java.base/java/util/Deque.html#getLast()[getLast]()
57695787
* int getLength()
@@ -5836,6 +5854,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
58365854
* List findResults(Function)
58375855
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
58385856
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
5857+
* Object getByPath(String)
5858+
* Object getByPath(String, Object)
58395859
* int getLength()
58405860
* Map groupBy(Function)
58415861
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -6056,6 +6076,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
60566076
* List findResults(BiFunction)
60576077
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
60586078
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
6079+
* Object getByPath(String)
6080+
* Object getByPath(String, Object)
60596081
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
60606082
* Map groupBy(BiFunction)
60616083
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -6157,6 +6179,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
61576179
* def {java11-javadoc}/java.base/java/util/NavigableMap.html#floorKey(java.lang.Object)[floorKey](def)
61586180
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
61596181
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
6182+
* Object getByPath(String)
6183+
* Object getByPath(String, Object)
61606184
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
61616185
* Map groupBy(BiFunction)
61626186
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -6642,6 +6666,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
66426666
* def {java11-javadoc}/java.base/java/util/SortedMap.html#firstKey()[firstKey]()
66436667
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
66446668
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
6669+
* Object getByPath(String)
6670+
* Object getByPath(String, Object)
66456671
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
66466672
* Map groupBy(BiFunction)
66476673
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -6844,6 +6870,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
68446870
* def {java11-javadoc}/java.base/java/util/Vector.html#firstElement()[firstElement]()
68456871
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
68466872
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
6873+
* Object getByPath(String)
6874+
* Object getByPath(String, Object)
68476875
* int getLength()
68486876
* Map groupBy(Function)
68496877
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -6988,6 +7016,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
69887016
* def {java11-javadoc}/java.base/java/util/NavigableMap.html#floorKey(java.lang.Object)[floorKey](def)
69897017
* void {java11-javadoc}/java.base/java/util/Map.html#forEach(java.util.function.BiConsumer)[forEach](BiConsumer)
69907018
* def {java11-javadoc}/java.base/java/util/Map.html#get(java.lang.Object)[get](def)
7019+
* Object getByPath(String)
7020+
* Object getByPath(String, Object)
69917021
* def {java11-javadoc}/java.base/java/util/Map.html#getOrDefault(java.lang.Object,java.lang.Object)[getOrDefault](def, def)
69927022
* Map groupBy(BiFunction)
69937023
* int {java11-javadoc}/java.base/java/lang/Object.html#hashCode()[hashCode]()
@@ -7158,6 +7188,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
71587188
* def {java11-javadoc}/java.base/java/util/Vector.html#firstElement()[firstElement]()
71597189
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
71607190
* def {java11-javadoc}/java.base/java/util/List.html#get(int)[get](int)
7191+
* Object getByPath(String)
7192+
* Object getByPath(String, Object)
71617193
* int getLength()
71627194
* Map groupBy(Function)
71637195
* int {java11-javadoc}/java.base/java/util/List.html#hashCode()[hashCode]()
@@ -8016,6 +8048,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
80168048
* List findResults(Function)
80178049
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
80188050
* Boolean get(int)
8051+
* Object getByPath(String)
8052+
* Object getByPath(String, Object)
80198053
* int getLength()
80208054
* boolean getValue()
80218055
* Map groupBy(Function)
@@ -8071,6 +8105,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
80718105
* List findResults(Function)
80728106
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
80738107
* BytesRef get(int)
8108+
* Object getByPath(String)
8109+
* Object getByPath(String, Object)
80748110
* int getLength()
80758111
* BytesRef getValue()
80768112
* Map groupBy(Function)
@@ -8126,6 +8162,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
81268162
* List findResults(Function)
81278163
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
81288164
* JodaCompatibleZonedDateTime get(int)
8165+
* Object getByPath(String)
8166+
* Object getByPath(String, Object)
81298167
* int getLength()
81308168
* JodaCompatibleZonedDateTime getValue()
81318169
* Map groupBy(Function)
@@ -8181,6 +8219,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
81818219
* List findResults(Function)
81828220
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
81838221
* Double get(int)
8222+
* Object getByPath(String)
8223+
* Object getByPath(String, Object)
81848224
* int getLength()
81858225
* double getValue()
81868226
* Map groupBy(Function)
@@ -8240,6 +8280,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
82408280
* double geohashDistance(String)
82418281
* double geohashDistanceWithDefault(String, double)
82428282
* GeoPoint get(int)
8283+
* Object getByPath(String)
8284+
* Object getByPath(String, Object)
82438285
* double getLat()
82448286
* double[] getLats()
82458287
* int getLength()
@@ -8301,6 +8343,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
83018343
* List findResults(Function)
83028344
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
83038345
* Long get(int)
8346+
* Object getByPath(String)
8347+
* Object getByPath(String, Object)
83048348
* int getLength()
83058349
* long getValue()
83068350
* Map groupBy(Function)
@@ -8356,6 +8400,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
83568400
* List findResults(Function)
83578401
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
83588402
* String get(int)
8403+
* Object getByPath(String)
8404+
* Object getByPath(String, Object)
83598405
* int getLength()
83608406
* String getValue()
83618407
* Map groupBy(Function)
@@ -8415,6 +8461,8 @@ See the <<painless-api-reference-shared, Shared API>> for a high-level overview
84158461
* List findResults(Function)
84168462
* void {java11-javadoc}/java.base/java/lang/Iterable.html#forEach(java.util.function.Consumer)[forEach](Consumer)
84178463
* String get(int)
8464+
* Object getByPath(String)
8465+
* Object getByPath(String, Object)
84188466
* int getLength()
84198467
* String getValue()
84208468
* Map groupBy(Function)

modules/lang-painless/src/main/java/org/elasticsearch/painless/api/Augmentation.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Collection;
2626
import java.util.LinkedHashMap;
2727
import java.util.List;
28+
import java.util.Locale;
2829
import java.util.Map;
2930
import java.util.TreeMap;
3031
import java.util.function.BiConsumer;
@@ -34,6 +35,7 @@
3435
import java.util.function.Function;
3536
import java.util.function.ObjIntConsumer;
3637
import java.util.function.Predicate;
38+
import java.util.function.Supplier;
3739
import java.util.function.ToDoubleFunction;
3840
import java.util.regex.Matcher;
3941
import java.util.regex.Pattern;
@@ -552,4 +554,115 @@ public static String[] splitOnToken(String receiver, String token, int limit) {
552554
// O(N) or faster depending on implementation
553555
return result.toArray(new String[0]);
554556
}
557+
558+
/**
559+
* Access values in nested containers with a dot separated path. Path elements are treated
560+
* as strings for Maps and integers for Lists.
561+
* @throws IllegalArgumentException if any of the following:
562+
* - path is empty
563+
* - path contains a trailing '.' or a repeated '.'
564+
* - an element of the path does not exist, ie key or index not present
565+
* - there is a non-container type at a non-terminal path element
566+
* - a path element for a List is not an integer
567+
* @return object at path
568+
*/
569+
public static <E> Object getByPath(List<E> receiver, String path) {
570+
return getByPathDispatch(receiver, splitPath(path), 0, throwCantFindValue(path));
571+
}
572+
573+
/**
574+
* Same as {@link #getByPath(List, String)}, but for Map.
575+
*/
576+
public static <K,V> Object getByPath(Map<K,V> receiver, String path) {
577+
return getByPathDispatch(receiver, splitPath(path), 0, throwCantFindValue(path));
578+
}
579+
580+
/**
581+
* Same as {@link #getByPath(List, String)}, but with a default value.
582+
* @return element at path or {@code defaultValue} if the terminal path element does not exist.
583+
*/
584+
public static <E> Object getByPath(List<E> receiver, String path, Object defaultValue) {
585+
return getByPathDispatch(receiver, splitPath(path), 0, () -> defaultValue);
586+
}
587+
588+
/**
589+
* Same as {@link #getByPath(List, String, Object)}, but for Map.
590+
*/
591+
public static <K,V> Object getByPath(Map<K,V> receiver, String path, Object defaultValue) {
592+
return getByPathDispatch(receiver, splitPath(path), 0, () -> defaultValue);
593+
}
594+
595+
// Dispatches to getByPathMap, getByPathList or returns obj if done. See handleMissing for dealing with missing
596+
// elements.
597+
private static Object getByPathDispatch(Object obj, String[] elements, int i, Supplier<Object> defaultSupplier) {
598+
if (i > elements.length - 1) {
599+
return obj;
600+
} else if (elements[i].length() == 0 ) {
601+
String format = "Extra '.' in path [%s] at index [%d]";
602+
throw new IllegalArgumentException(String.format(Locale.ROOT, format, String.join(".", elements), i));
603+
} else if (obj instanceof Map<?,?>) {
604+
return getByPathMap((Map<?,?>) obj, elements, i, defaultSupplier);
605+
} else if (obj instanceof List<?>) {
606+
return getByPathList((List<?>) obj, elements, i, defaultSupplier);
607+
}
608+
return handleMissing(obj, elements, i, defaultSupplier);
609+
}
610+
611+
// lookup existing key in map, call back to dispatch.
612+
private static <K,V> Object getByPathMap(Map<K,V> map, String[] elements, int i, Supplier<Object> defaultSupplier) {
613+
String element = elements[i];
614+
if (map.containsKey(element)) {
615+
return getByPathDispatch(map.get(element), elements, i + 1, defaultSupplier);
616+
}
617+
return handleMissing(map, elements, i, defaultSupplier);
618+
}
619+
620+
// lookup existing index in list, call back to dispatch. Throws IllegalArgumentException with NumberFormatException
621+
// if index can't be parsed as an int.
622+
private static <E> Object getByPathList(List<E> list, String[] elements, int i, Supplier<Object> defaultSupplier) {
623+
String element = elements[i];
624+
try {
625+
int elemInt = Integer.parseInt(element);
626+
if (list.size() >= elemInt) {
627+
return getByPathDispatch(list.get(elemInt), elements, i + 1, defaultSupplier);
628+
}
629+
} catch (NumberFormatException e) {
630+
String format = "Could not parse [%s] as a int index into list at path [%s] and index [%d]";
631+
throw new IllegalArgumentException(String.format(Locale.ROOT, format, element, String.join(".", elements), i), e);
632+
}
633+
return handleMissing(list, elements, i, defaultSupplier);
634+
}
635+
636+
// Split path on '.', throws IllegalArgumentException for empty paths and paths ending in '.'
637+
private static String[] splitPath(String path) {
638+
if (path.length() == 0) {
639+
throw new IllegalArgumentException("Missing path");
640+
}
641+
if (path.endsWith(".")) {
642+
String format = "Trailing '.' in path [%s]";
643+
throw new IllegalArgumentException(String.format(Locale.ROOT, format, path));
644+
}
645+
return path.split("\\.");
646+
}
647+
648+
// A supplier that throws IllegalArgumentException
649+
private static Supplier<Object> throwCantFindValue(String path) {
650+
return () -> {
651+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Could not find value at path [%s]", path));
652+
};
653+
}
654+
655+
// Use defaultSupplier if at last path element, otherwise throw IllegalArgumentException
656+
private static Object handleMissing(Object obj, String[] elements, int i, Supplier<Object> defaultSupplier) {
657+
if (obj instanceof List || obj instanceof Map) {
658+
if (elements.length - 1 == i) {
659+
return defaultSupplier.get();
660+
}
661+
String format = "Container does not have [%s], for non-terminal index [%d] in path [%s]";
662+
throw new IllegalArgumentException(String.format(Locale.ROOT, format, elements[i], i, String.join(".", elements)));
663+
}
664+
String format = "Non-container [%s] at [%s], index [%d] in path [%s]";
665+
throw new IllegalArgumentException(
666+
String.format(Locale.ROOT, format, obj.getClass().getName(), elements[i], i, String.join(".", elements)));
667+
}
555668
}

0 commit comments

Comments
 (0)