001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate;
018
019import static java.util.Objects.requireNonNull;
020import static org.spongepowered.configurate.AbstractConfigurationNode.storeDefault;
021import static org.spongepowered.configurate.util.Types.makeListType;
022
023import io.leangen.geantyref.TypeFactory;
024import io.leangen.geantyref.TypeToken;
025import org.checkerframework.checker.nullness.qual.Nullable;
026import org.spongepowered.configurate.loader.ConfigurationLoader;
027import org.spongepowered.configurate.serialize.Scalars;
028import org.spongepowered.configurate.serialize.SerializationException;
029import org.spongepowered.configurate.serialize.TypeSerializer;
030
031import java.lang.reflect.Type;
032import java.util.Collection;
033import java.util.List;
034import java.util.Map;
035import java.util.NoSuchElementException;
036import java.util.function.Supplier;
037import java.util.stream.Collector;
038
039/**
040 * A node in the configuration tree.
041 *
042 * <p>All aspects of a configurations structure are represented using instances
043 * of {@link ConfigurationNode}, and the links between them.</p>
044 *
045 * <p>{@link ConfigurationNode}s can hold different types of value. They can:</p>
046 *
047 * <ul>
048 *     <li>Hold a single "scalar" value (accessed by {@link #rawScalar()}</li>
049 *     <li>Represent a "list" of child {@link ConfigurationNode}s (accessed by {@link #isList()} and {@link #childrenList()})</li>
050 *     <li>Represent a "map" of child {@link ConfigurationNode}s (accessed by {@link #isMap()} and {@link #childrenMap()})</li>
051 *     <li>Hold no value at all (when {@link #virtual()} is true)</li>
052 * </ul>
053 *
054 * <p>The overall configuration stems from a single "root" node, which is
055 * provided by the {@link ConfigurationLoader}, or by other means programmatically.</p>
056 *
057 * @since 4.0.0
058 */
059public interface ConfigurationNode {
060
061    /**
062     * Default value for unknown number results.
063     *
064     * @since 4.0.0
065     */
066    int NUMBER_DEF = 0;
067
068    /**
069     * Gets the "key" of this node.
070     *
071     * <p>The key determines this {@link ConfigurationNode}s position within
072     * the overall configuration structure.</p>
073     *
074     * <p>If this node is currently {@link #virtual() virtual}, this method's
075     * result may be inaccurate.</p>
076     *
077     * <p>Note that this method only returns the nearest "link" in the
078     * hierarchy, and does not return a representation of the full path. See
079     * {@link #path()} for that.</p>
080     *
081     * <p>The {@link ConfigurationNode}s returned as values from
082     * {@link #childrenMap()} will have keys derived from their pairing in
083     * the map node.</p>
084     *
085     * <p>The {@link ConfigurationNode}s returned from
086     * {@link #childrenList()} will have keys derived from their position
087     * (index) in the list node.</p>
088     *
089     * @return the key of this node
090     * @since 4.0.0
091     */
092    @Nullable Object key();
093
094    /**
095     * Gets the full path of {@link #key() keys} from the root node to this
096     * node.
097     *
098     * <p>Node implementations may not keep a full path for each node, so this
099     * method may be somewhat complex to calculate. Most uses should not need to
100     * calculate the full path unless providing debug information</p>
101     *
102     * @return an array compiled from the keys for each node up the hierarchy
103     * @since 4.0.0
104     */
105    NodePath path();
106
107    /**
108     * Gets the parent of this node.
109     *
110     * <p>If this node is currently {@link #virtual() virtual}, this method's
111     * result may be inaccurate.</p>
112     *
113     * @return the nodes parent
114     * @since 4.0.0
115     */
116    @Nullable ConfigurationNode parent();
117
118    /**
119     * Gets the node at the given (relative) path, possibly traversing multiple
120     * levels of nodes.
121     *
122     * <p>This is the main method used to navigate through
123     * the configuration.</p>
124     *
125     * <p>The path parameter effectively consumes an array of keys, which locate
126     * the unique position of a given node within the structure. Each element
127     * will navigate one level down in the configuration hierarchy</p>
128     *
129     * <p>A node is <b>always</b> returned by this method. If the given node
130     * does not exist in the structure, a {@link #virtual() virtual} node will
131     * be returned which represents the position.</p>
132     *
133     * @param path the path to fetch the node at
134     * @return the node at the given path, possibly virtual
135     * @since 4.0.0
136     */
137    ConfigurationNode node(Object... path);
138
139    /**
140     * Gets the node at the given (relative) path, possibly traversing multiple
141     * levels of nodes.
142     *
143     * <p>This is the main method used to navigate through
144     * the configuration.</p>
145     *
146     * <p>The path parameter effectively consumes an array of keys, which locate
147     * the unique position of a given node within the structure.</p>
148     *
149     * <p>A node is <b>always</b> returned by this method. If the given node
150     * does not exist in the structure, a {@link #virtual() virtual} node will
151     * be returned which represents the position.</p>
152     *
153     * @param path the path to fetch the node at
154     * @return the node at the given path, possibly virtual
155     * @since 4.0.0
156     */
157    ConfigurationNode node(Iterable<?> path);
158
159    /**
160     * Checks whether or not a non-virtual node is present at the relative
161     * path {@code path}.
162     *
163     * <p>This allows checking for more remote nodes in the configuration
164     * hierarchy without having to instantiate new unattached node objects.</p>
165     *
166     * @param path path to search at
167     * @return if a non-virtual child is present
168     * @since 4.0.0
169     */
170    boolean hasChild(Object... path);
171
172    /**
173     * Checks whether or not a non-virtual node is present at the relative
174     * path {@code path}.
175     *
176     * <p>This allows checking for more remote nodes in the configuration
177     * hierarchy without having to instantiate new unattached node objects.</p>
178     *
179     * @param path path to search at
180     * @return if a non-virtual child is present
181     * @since 4.0.0
182     */
183    boolean hasChild(Iterable<?> path);
184
185    /**
186     * Gets if this node is virtual.
187     *
188     * <p>Virtual nodes are nodes which are not attached to a wider
189     * configuration structure.</p>
190     *
191     * <p>A node is primarily "virtual" when it has no set value.</p>
192     *
193     * @return {@code true} if this node is virtual
194     * @since 4.0.0
195     */
196    boolean virtual();
197
198    /**
199     * Gets the options that currently apply to this node.
200     *
201     * @return the {@link ConfigurationOptions} instance controlling the functionality
202     *          of this node.
203     * @since 4.0.0
204     */
205    ConfigurationOptions options();
206
207    /**
208     * Get if this node has a 'null' value.
209     *
210     * <p>This generally overlaps with the value of {@link #virtual()}, but may
211     * be distinct in situations where the node has additional metadata
212     * (comment, attributes, etc).</p>
213     *
214     * @return whether this node
215     * @since 4.1.0
216     */
217    boolean isNull();
218
219    /**
220     * Gets if this node has "list children".
221     *
222     * @return if this node has children in the form of a list
223     * @since 4.0.0
224     */
225    boolean isList();
226
227    /**
228     * Gets if this node has "map children".
229     *
230     * @return if this node has children in the form of a map
231     * @since 4.0.0
232     */
233    boolean isMap();
234
235    /**
236     * Return true when this node has a null or empty value.
237     *
238     * <p>Values that may result in this method returning true include:
239     *
240     * <ul>
241     *     <li><code>null</code></li>
242     *     <li>the empty string</li>
243     *     <li>an empty map</li>
244     *     <li>an empty list</li>
245     *     <li>Any other type of empty collection</li>
246     * </ul>
247     *
248     * <p>This is a separate value from {@link #virtual()}. Emptiness refers
249     * to the value of this node itself, while virtuality refers to whether or
250     * not this node is attached to a configuration structure.
251     *
252     * @return whether this node is empty
253     * @since 4.0.0
254     */
255    boolean empty();
256
257    /**
258     * Gets the "list children" attached to this node, if it has any.
259     *
260     * <p>If this node does not {@link #isList() have list children}, an empty
261     * list is returned.</p>
262     *
263     * @return the list children currently attached to this node
264     * @since 4.0.0
265     */
266    List<? extends ConfigurationNode> childrenList();
267
268    /**
269     * Gets the "map children" attached to this node, if it has any.
270     *
271     * <p>If this node does not {@link #isMap() have map children}, an empty map
272     * returned.</p>
273     *
274     * @return the map children currently attached to this node
275     * @since 4.0.0
276     */
277    Map<Object, ? extends ConfigurationNode> childrenMap();
278
279    /**
280     * Create a collector that appends values to this node as map children.
281     *
282     * <p>This collector does not accept values in parallel.</p>
283     *
284     * @param valueType marker for value type
285     * @param <V> value type
286     * @return a new collector
287     * @since 4.0.0
288     */
289    default <V> Collector<Map.Entry<?, V>, ? extends ConfigurationNode, ? extends ConfigurationNode> toMapCollector(final TypeToken<V> valueType) {
290        return Collector.of(() -> this, (node, entry) -> {
291            try {
292                node.node(entry.getKey()).set(valueType, entry.getValue());
293            } catch (SerializationException e) {
294                throw new IllegalArgumentException(e);
295            }
296        }, ConfigurationNode::mergeFrom);
297    }
298
299    /**
300     * Create a collector that appends values to this node as map children.
301     *
302     * <p>This collector does not accept values in parallel.</p>
303     *
304     * @param valueType marker for value type
305     * @param <V> value type
306     * @return a new collector
307     * @since 4.0.0
308     */
309    default <V> Collector<Map.Entry<?, V>, ? extends ConfigurationNode, ? extends ConfigurationNode> toMapCollector(final Class<V> valueType) {
310        return Collector.of(() -> this, (node, entry) -> {
311            try {
312                node.node(entry.getKey()).set(valueType, entry.getValue());
313            } catch (SerializationException e) {
314                throw new IllegalArgumentException(e);
315            }
316        }, ConfigurationNode::mergeFrom);
317    }
318
319    /**
320     * Create a collector that appends values to this node as list children.
321     *
322     * <p>This collector does not accept values in parallel.</p>
323     *
324     * @param valueType marker for value type
325     * @param <V> value type
326     * @return a new collector
327     * @since 4.0.0
328     */
329    default <V> Collector<V, ? extends ConfigurationNode, ? extends ConfigurationNode> toListCollector(final TypeToken<V> valueType) {
330        return Collector.of(() -> this, (node, value) -> {
331            try {
332                node.appendListNode().set(valueType, value);
333            } catch (SerializationException e) {
334                throw new IllegalArgumentException(e);
335            }
336        }, ConfigurationNode::mergeFrom);
337    }
338
339    /**
340     * Create a collector that appends values to this node as list children.
341     *
342     * <p>This collector does not accept values in parallel.</p>
343     *
344     * @param valueType marker for value type
345     * @param <V> value type
346     * @return a new collector
347     * @since 4.0.0
348     */
349    default <V> Collector<V, ? extends ConfigurationNode, ? extends ConfigurationNode> toListCollector(final Class<V> valueType) {
350        return Collector.of(() -> this, (node, value) -> {
351            try {
352                node.appendListNode().set(valueType, value);
353            } catch (SerializationException e) {
354                throw new IllegalArgumentException(e);
355            }
356        }, ConfigurationNode::mergeFrom);
357    }
358
359    /**
360     * Get the current value associated with this node, asserting that it
361     * is non-null.
362     *
363     * <p>This method can be used when it is known that a certain key exists, or
364     * when implicit initialization is enabled for the expected {@code type}</p>
365     *
366     * <p>This method will perform deserialization using the appropriate
367     * {@link TypeSerializer} for the given type, or attempting to cast if no
368     * type serializer is found.</p>
369     *
370     * @param type the type to deserialize to
371     * @param <V> the type to get
372     * @return the value if present and of the proper type
373     * @throws NoSuchElementException if the returned value is null
374     * @throws SerializationException if the value fails to be converted to the
375     *                                requested type
376     * @since 4.1.0
377     */
378    default <V> V require(final TypeToken<V> type) throws SerializationException {
379        final @Nullable V ret = this.get(type);
380        if (ret == null) {
381            throw new NoSuchElementException("Node value was null when a non-null node was require()d");
382        }
383
384        return ret;
385    }
386
387    /**
388     * Get the current value associated with this node, asserting that it
389     * is non-null.
390     *
391     * <p>This method can be used when it is known that a certain key exists, or
392     * when implicit initialization is enabled for the expected {@code type}</p>
393     *
394     * <p>This method will also perform deserialization using the appropriate
395     * {@link TypeSerializer} for the given type, or casting if no type
396     * serializer is found.</p>
397     *
398     * @param type the type to deserialize to
399     * @param <V> the type to get
400     * @return the value if present and of the proper type
401     * @throws NoSuchElementException if the returned value is null
402     * @throws SerializationException if the value fails to be converted to the
403     *                                requested type
404     * @since 4.1.0
405     */
406    default <V> V require(final Class<V> type) throws SerializationException {
407        final @Nullable V ret = this.get(type);
408        if (ret == null) {
409            throw new NoSuchElementException("Node value was null when a non-null node was require()d");
410        }
411
412        return ret;
413    }
414
415    /**
416     * Get the current value associated with this node, asserting that it
417     * is non-null.
418     *
419     * <p>This method can be used when it is known that a certain key exists, or
420     * when implicit initialization is enabled for the expected {@code type}</p>
421     *
422     * <p>This method will attempt to deserialize the node's value to the
423     * provided {@link Type} using a configured {@link TypeSerializer} for
424     * the given type, or casting if no type serializer is found.</p>
425     *
426     * @param type the type to deserialize to
427     * @return the value if present and of the proper type
428     * @throws NoSuchElementException if the returned value is null
429     * @throws SerializationException if the value fails to be converted to the
430     *                                requested type
431     * @since 4.1.0
432     */
433    default @Nullable Object require(final Type type) throws SerializationException {
434        final @Nullable Object ret = this.get(type);
435        if (ret == null) {
436            throw new NoSuchElementException("Node value was null when a non-null node was require()d");
437        }
438
439        return ret;
440    }
441
442    /**
443     * Get the current value associated with this node.
444     *
445     * <p>This method will perform deserialization using the appropriate
446     * {@link TypeSerializer} for the given type, or attempting to cast if no
447     * type serializer is found.</p>
448     *
449     * @param type the type to deserialize to
450     * @param <V> the type to get
451     * @return the value if present and of the proper type, else null
452     * @throws SerializationException if the value fails to be converted to the
453     *                                requested type
454     * @since 4.0.0
455     */
456    @SuppressWarnings("unchecked") // type token
457    default <V> @Nullable V get(TypeToken<V> type) throws SerializationException {
458        return (V) get(type.getType());
459    }
460
461    /**
462     * Get the current value associated with this node.
463     *
464     * <p>This method will also perform deserialization using the appropriate
465     * {@link TypeSerializer} for the given type, or casting if no type
466     * serializer is found.</p>
467     *
468     * @param type the type to deserialize as.
469     * @param def value to return if {@link #virtual()} or value is not of
470     *            appropriate type
471     * @param <V> the type to get
472     * @return the value if of the proper type, else {@code def}
473     * @throws SerializationException if the value fails to be converted to the
474     *                                requested type
475     * @since 4.0.0
476     */
477    @SuppressWarnings("unchecked") // type is verified by the token
478    default <V> V get(TypeToken<V> type, V def) throws SerializationException {
479        return (V) get(type.getType(), def);
480    }
481
482    /**
483     * Get the current value associated with this node.
484     *
485     * <p>This method will also perform deserialization using the appropriate
486     * TypeSerializer for the given type, or casting if no type serializer is
487     * found.</p>
488     *
489     * @param type the type to deserialize to
490     * @param defSupplier the function that will be called to calculate a
491     *                    default value only if there is no existing value of
492     *                    the correct type
493     * @param <V> the type to get
494     * @return the value if of the proper type, else {@code def}
495     * @throws SerializationException if the value fails to be converted to the
496     *                                requested type
497     * @since 4.0.0
498     */
499    @SuppressWarnings("unchecked") // type is verified by the token
500    default <V> V get(TypeToken<V> type, Supplier<V> defSupplier) throws SerializationException {
501        return (V) get(type.getType(), defSupplier);
502    }
503
504    /**
505     * Get the current value associated with this node.
506     *
507     * <p>This method will also perform deserialization using the appropriate
508     * {@link TypeSerializer} for the given type, or casting if no type
509     * serializer is found.</p>
510     *
511     * @param type the type to deserialize to
512     * @param <V> the type to get
513     * @return the value if present and of the proper type, else null
514     * @throws SerializationException if the value fails to be converted to the
515     *                                requested type
516     * @since 4.0.0
517     */
518    @SuppressWarnings("unchecked") // type is verified by the class parameter
519    default <V> @Nullable V get(Class<V> type) throws SerializationException {
520        return (V) get((Type) type);
521    }
522
523    /**
524     * Get the current value associated with this node.
525     *
526     * <p>This method will also perform deserialization using the appropriate
527     * {@link TypeSerializer} for the given type, or casting if no type
528     * serializer is found.</p>
529     *
530     * @param type the type to deserialize as.
531     * @param def value to return if {@link #virtual()} or value is not of
532     *            appropriate type
533     * @param <V> the type to get
534     * @return the value if of the proper type, else {@code def}
535     * @throws SerializationException if the value fails to be converted to the
536     *                                requested type
537     * @since 4.0.0
538     */
539    @SuppressWarnings("unchecked") // type is verified by the class parameter
540    default <V> V get(Class<V> type, V def) throws SerializationException {
541        return (V) get((Type) type, def);
542    }
543
544    /**
545     * Get the current value associated with this node.
546     *
547     * <p>This method will also perform deserialization using the appropriate
548     * TypeSerializer for the given type, or casting if no type serializer is
549     * found.</p>
550     *
551     * @param type the type to deserialize to
552     * @param defSupplier the function that will be called to calculate a
553     *                    default value only if there is no existing value of
554     *                    the correct type
555     * @param <V> the type to get
556     * @return the value if of the proper type, else {@code def}
557     * @throws SerializationException if the value fails to be converted to the
558     *                                requested type
559     * @since 4.0.0
560     */
561    @SuppressWarnings("unchecked") // type is verified by the class parameter
562    default <V> V get(Class<V> type, Supplier<V> defSupplier) throws SerializationException {
563        return (V) get((Type) type, defSupplier);
564    }
565
566    /**
567     * Get the current value associated with this node.
568     *
569     * <p>This method will attempt to deserialize the node's value to the
570     * provided {@link Type} using a configured {@link TypeSerializer} for
571     * the given type, or casting if no type serializer is found.</p>
572     *
573     * @param type the type to deserialize to
574     * @return the value if present and of the proper type, else null
575     * @throws SerializationException if the value fails to be converted to the
576     *                                requested type
577     * @since 4.0.0
578     */
579    @Nullable Object get(Type type) throws SerializationException;
580
581    /**
582     * Get the current value associated with this node.
583     *
584     * <p>This method will attempt to deserialize the node's value to the
585     * provided {@link Type} using a configured {@link TypeSerializer} for
586     * the given type, or casting if no type serializer is found.</p>
587     *
588     * @param type the type to deserialize as
589     * @param def value to return if {@link #virtual()} or value is not of
590     *            appropriate type
591     * @return the value if of the proper type, else {@code def}
592     * @throws SerializationException if the value fails to be converted to the
593     *                                requested type
594     * @since 4.0.0
595     */
596    default Object get(Type type, Object def) throws SerializationException {
597        final @Nullable Object value = get(type);
598        return value == null ? storeDefault(this, type, def) : value;
599    }
600
601    /**
602     * Get the current value associated with this node.
603     *
604     * <p>This method will attempt to deserialize the node's value to the
605     * provided {@link Type} using a configured {@link TypeSerializer} for
606     * the given type, or casting if no type serializer is found.</p>
607     *
608     * @param type the type to deserialize to
609     * @param defSupplier the function that will be called to calculate a
610     *                    default value only if there is no existing value of
611     *                    the correct type
612     * @return the value if of the proper type, else {@code def}
613     * @throws SerializationException if the value fails to be converted to the
614     *                                requested type
615     * @since 4.0.0
616     */
617    default Object get(Type type, Supplier<?> defSupplier) throws SerializationException {
618        final @Nullable Object value = get(type);
619        return value == null ? storeDefault(this, type, defSupplier.get()) : value;
620    }
621
622    /**
623     * If this node has list values, this function unwraps them and converts
624     * them to an appropriate type based on the provided function.
625     *
626     * <p>If this node has a scalar value, this function treats it as a list
627     * with one value.</p>
628     *
629     * @param type the expected type
630     * @param <V> the expected type
631     * @return an immutable copy of the values contained
632     * @throws SerializationException if any value fails to be converted to the
633     *                                requested type
634     * @since 4.0.0
635     */
636    default <V> @Nullable List<V> getList(TypeToken<V> type) throws SerializationException { // @cs-: NoGetSetPrefix (not a bean method)
637        return get(makeListType(type));
638    }
639
640    /**
641     * If this node has list values, this function unwraps them and converts
642     * them to an appropriate type based on the provided function.
643     *
644     * <p>If this node has a scalar value, this function treats it as a list
645     * with one value.</p>
646     *
647     * @param elementType expected type
648     * @param def default value if no appropriate value is set
649     * @param <V> expected type
650     * @return an immutable copy of the values contained that could be
651     *         successfully converted, or {@code def} if no values could be
652     *         converted.
653     * @throws SerializationException if any value fails to be converted to the
654     *                                requested type
655     * @since 4.0.0
656     */
657    default <V> List<V> getList(TypeToken<V> elementType, List<V> def) throws SerializationException { // @cs-: NoGetSetPrefix (not a bean method)
658        final TypeToken<List<V>> type = makeListType(elementType);
659        final @Nullable List<V> ret = get(type, def);
660        return ret == null || ret.isEmpty() ? storeDefault(this, type.getType(), def) : ret;
661    }
662
663    /**
664     * If this node has list values, this function unwraps them and converts
665     * them to an appropriate type based on the provided function.
666     *
667     * <p>If this node has a scalar value, this function treats it as a list
668     * with one value.</p>
669     *
670     * @param elementType expected type
671     * @param defSupplier function that will be called to calculate a default
672     *                    value only if there is no existing value of the
673     *                    correct type
674     * @param <V> expected type
675     * @return an immutable copy of the values contained that could be
676     *         successfully converted, or {@code def} if no values could be
677     *         converted.
678     * @throws SerializationException if any value fails to be converted to the
679     *                                requested type
680     * @since 4.0.0
681     */
682    // @cs-: NoGetSetPrefix (not a bean method)
683    default <V> List<V> getList(TypeToken<V> elementType, Supplier<List<V>> defSupplier) throws SerializationException {
684        final TypeToken<List<V>> type = makeListType(elementType);
685        final List<V> ret = get(type, defSupplier);
686        return ret.isEmpty() ? storeDefault(this, type.getType(), defSupplier.get()) : ret;
687    }
688
689    /**
690     * If this node has list values, this function unwraps them and converts
691     * them to an appropriate type based on the provided function.
692     *
693     * <p>If this node has a scalar value, this function treats it as a list
694     * with one value.</p>
695     *
696     * @param type the expected type
697     * @param <V> the expected type
698     * @return an immutable copy of the values contained
699     * @throws SerializationException if any value fails to be converted to the
700     *                                requested type
701     * @since 4.0.0
702     */
703    @SuppressWarnings("unchecked")
704    default <V> @Nullable List<V> getList(Class<V> type) throws SerializationException { // @cs-: NoGetSetPrefix (not a bean method)
705        return (List<V>) get(TypeFactory.parameterizedClass(List.class, type));
706    }
707
708    /**
709     * If this node has list values, this function unwraps them and converts
710     * them to an appropriate type based on the provided function.
711     *
712     * <p>If this node has a scalar value, this function treats it as a list
713     * with one value.</p>
714     *
715     * @param elementType expected type
716     * @param def default value if no appropriate value is set
717     * @param <V> expected type
718     * @return an immutable copy of the values contained that could be
719     *         successfully converted, or {@code def} if no values could be
720     *         converted.
721     * @throws SerializationException if any value fails to be converted to the
722     *                                requested type
723     * @since 4.0.0
724     */
725    @SuppressWarnings("unchecked")
726    default <V> List<V> getList(Class<V> elementType, List<V> def) throws SerializationException { // @cs-: NoGetSetPrefix (not a bean method)
727        final Type type = TypeFactory.parameterizedClass(List.class, elementType);
728        final @Nullable List<V> ret = (List<V>) get(type, def);
729        return ret == null || ret.isEmpty() ? storeDefault(this, type, def) : ret;
730    }
731
732    /**
733     * If this node has list values, this function unwraps them and converts
734     * them to an appropriate type based on the provided function.
735     *
736     * <p>If this node has a scalar value, this function treats it as a list
737     * with one value.</p>
738     *
739     * @param elementType expected type
740     * @param defSupplier function that will be called to calculate a default
741     *                    value only if there is no existing value of the
742     *                    correct type
743     * @param <V> expected type
744     * @return an immutable copy of the values contained that could be
745     *         successfully converted, or {@code def} if no values could be
746     *         converted.
747     * @throws SerializationException if any value fails to be converted to the
748     *                                requested type
749     * @since 4.0.0
750     */
751    @SuppressWarnings({"unchecked", "checkstyle:NoGetSetPrefix"})
752    default <V> List<V> getList(Class<V> elementType, Supplier<List<V>> defSupplier) throws SerializationException {
753        final Type type = TypeFactory.parameterizedClass(List.class, elementType);
754        final List<V> ret = (List<V>) get(type, defSupplier);
755        return ret.isEmpty() ? storeDefault(this, type, defSupplier.get()) : ret;
756    }
757
758    /**
759     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
760     *
761     * @return the value coerced to a {@link String}, or null if no value
762     * @see #raw()
763     * @since 4.0.0
764     */
765    default @Nullable String getString() { // @cs-: NoGetSetPrefix (not a bean method)
766        return Scalars.STRING.tryDeserialize(rawScalar());
767    }
768
769    /**
770     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
771     *
772     * @param def the default value if no appropriate value is set
773     * @return the value coerced to a {@link String}, or {@code def} if no value
774     * @see #raw()
775     * @since 4.0.0
776     */
777    default String getString(final String def) { // @cs-: NoGetSetPrefix (not a bean method)
778        requireNonNull(def, "def");
779        final @Nullable String value = getString();
780        if (value != null) {
781            return value;
782        }
783        if (options().shouldCopyDefaults()) {
784            Scalars.STRING.serialize(float.class, def, this);
785        }
786        return def;
787    }
788
789    /**
790     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
791     *
792     * @return the value coerced to a float, or {@link #NUMBER_DEF} if not a float
793     * @see #raw()
794     * @since 4.0.0
795     */
796    default float getFloat() { // @cs-: NoGetSetPrefix (not a bean method)
797        return getFloat(NUMBER_DEF);
798    }
799
800    /**
801     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
802     *
803     * @param def the default value if no appropriate value is set
804     * @return the value coerced to a float, or {@code def} if not a float
805     * @see #raw()
806     * @since 4.0.0
807     */
808    default float getFloat(float def) { // @cs-: NoGetSetPrefix (not a bean method)
809        final @Nullable Float val = Scalars.FLOAT.tryDeserialize(rawScalar());
810        if (val != null) {
811            return val;
812        }
813        if (options().shouldCopyDefaults() && def != NUMBER_DEF) {
814            Scalars.FLOAT.serialize(float.class, def, this);
815        }
816        return def;
817    }
818
819    /**
820     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
821     *
822     * @return the value coerced to a double, or {@link #NUMBER_DEF} if
823     *         coercion failed
824     * @see #raw()
825     * @since 4.0.0
826     */
827    default double getDouble() { // @cs-: NoGetSetPrefix (not a bean method)
828        return getDouble(NUMBER_DEF);
829    }
830
831    /**
832     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
833     *
834     * @param def the default value if no appropriate value is set
835     * @return the value coerced to a double, or {@code def} if coercion failed
836     * @see #raw()
837     * @since 4.0.0
838     */
839    default double getDouble(double def) { // @cs-: NoGetSetPrefix (not a bean method)
840        final @Nullable Double val = Scalars.DOUBLE.tryDeserialize(rawScalar());
841        if (val != null) {
842            return val;
843        }
844        if (options().shouldCopyDefaults() && def != NUMBER_DEF) {
845            Scalars.DOUBLE.serialize(double.class, def, this);
846        }
847        return def;
848    }
849
850    /**
851     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
852     *
853     * @return value coerced to an integer, or {@link #NUMBER_DEF} if coercion failed.
854     * @see #raw()
855     * @since 4.0.0
856     */
857    default int getInt() { // @cs-: NoGetSetPrefix (not a bean method)
858        return getInt(NUMBER_DEF);
859    }
860
861    /**
862     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
863     *
864     * @param def the default value if no appropriate value is set
865     * @return value coerced to an integer, or {@code def} if coercion failed.
866     * @see #raw()
867     * @since 4.0.0
868     */
869    default int getInt(int def) { // @cs-: NoGetSetPrefix (not a bean method)
870        final @Nullable Integer val = Scalars.INTEGER.tryDeserialize(rawScalar());
871        if (val != null) {
872            return val;
873        }
874        if (options().shouldCopyDefaults() && def != NUMBER_DEF) {
875            Scalars.INTEGER.serialize(int.class, def, this);
876        }
877        return def;
878    }
879
880    /**
881     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
882     *
883     * @return value coerced to a long, or {@link #NUMBER_DEF} if coercion failed
884     * @see #raw()
885     * @since 4.0.0
886     */
887    default long getLong() { // @cs-: NoGetSetPrefix (not a bean method)
888        return getLong(NUMBER_DEF);
889    }
890
891    /**
892     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
893     *
894     * @param def the default value if no appropriate value is set
895     * @return value coerced to a long, or {@code def} if coercion failed
896     * @see #raw()
897     * @since 4.0.0
898     */
899    default long getLong(long def) { // @cs-: NoGetSetPrefix (not a bean method)
900        final @Nullable Long val = Scalars.LONG.tryDeserialize(rawScalar());
901        if (val != null) {
902            return val;
903        }
904        if (options().shouldCopyDefaults() && def != NUMBER_DEF) {
905            Scalars.LONG.serialize(long.class, def, this);
906        }
907        return def;
908    }
909
910    /**
911     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
912     *
913     * @return value coerced to a boolean, or false if coercion failed
914     * @see #raw()
915     * @since 4.0.0
916     */
917    default boolean getBoolean() { // @cs-: NoGetSetPrefix (not a bean method)
918        return getBoolean(false);
919    }
920
921    /**
922     * Gets the value typed using the appropriate type conversion from {@link Scalars}.
923     *
924     * @param def the default value if no appropriate value is set
925     * @return value coerced to a boolean, or {@code def} if coercion failed
926     * @see #raw()
927     * @since 4.0.0
928     */
929    default boolean getBoolean(boolean def) { // @cs-: NoGetSetPrefix (not a bean method)
930        final @Nullable Boolean val = Scalars.BOOLEAN.tryDeserialize(rawScalar());
931        if (val != null) {
932            return val;
933        }
934        if (options().shouldCopyDefaults()) {
935            Scalars.BOOLEAN.serialize(boolean.class, def, this);
936        }
937        return def;
938    }
939
940    /**
941     * Set this node's value to the given value.
942     *
943     * <p>The value type will be taken from the provided value's class and used
944     * to determine a serializer. To set a value of a parameterized type, the
945     * parameters must be explicitly specified.</p>
946     *
947     * @param value the value to set
948     * @return this node
949     * @since 4.0.0
950     */
951    ConfigurationNode set(@Nullable Object value) throws SerializationException;
952
953    /**
954     * Set this node's value to the given value.
955     *
956     * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into
957     * the appropriate configuration node structure.</p>
958     *
959     * <p>This method will also perform serialization using the appropriate
960     * {@link TypeSerializer} for the given type, or casting if no type
961     * serializer is found.</p>
962     *
963     * @param type the type to use for serialization type information
964     * @param value the value to set
965     * @param <V> the type to serialize to
966     * @return this node
967     * @throws SerializationException if the value fails to be converted to the
968     *                                requested type. No change will be made to
969     *                                the node.
970     * @since 4.0.0
971     */
972    <V> ConfigurationNode set(TypeToken<V> type, @Nullable V value) throws SerializationException;
973
974    /**
975     * Set this node's value to the given value.
976     *
977     * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into
978     * the appropriate configuration node structure.</p>
979     *
980     * <p>This method will also perform serialization using the appropriate
981     * {@link TypeSerializer} for the given type, or casting if no type
982     * serializer is found.</p>
983     *
984     * <p>This method will fail if a raw type
985     * (i.e. a parameterized type without its type parameters) is passed.</p>
986     *
987     * @param type the type to use for serialization type information
988     * @param value the value to set
989     * @param <V> the type to serialize to
990     * @return this node
991     * @throws IllegalArgumentException if a raw type is passed
992     * @throws SerializationException if the value fails to be converted to the
993     *                                requested type. No change will be made to
994     *                                the node.
995     * @since 4.0.0
996     */
997    <V> ConfigurationNode set(Class<V> type, @Nullable V value) throws SerializationException;
998
999    /**
1000     * Set this node's value to the given value.
1001     *
1002     * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into
1003     * the appropriate configuration node structure.</p>
1004     *
1005     * <p>This method will also perform serialization using the appropriate
1006     * {@link TypeSerializer} for the given type, or casting if no type
1007     * serializer is found.</p>
1008     *
1009     * <p>This method will fail if a raw type
1010     * (i.e. a parameterized type without its type parameters) is passed.</p>
1011     *
1012     * <p>Because this method accepts a non-parameterized {@link Type} parameter,
1013     * it has no compile-time type checking. The variants that take
1014     * {@link #set(TypeToken, Object) TypeToken} and
1015     * {@link #set(Class, Object)} should be preferred where possible.</p>
1016     *
1017     * @param type the type to use for serialization type information
1018     * @param value the value to set
1019     * @return this node
1020     * @throws IllegalArgumentException if a raw type is passed
1021     * @throws IllegalArgumentException if {@code value} is not either
1022     *                                  {@code null} or of type {@code type}
1023     * @throws SerializationException if the value fails to be converted to the
1024     *                                requested type. No change will be made to
1025     *                                the node.
1026     * @since 4.0.0
1027     */
1028    ConfigurationNode set(Type type, @Nullable Object value) throws SerializationException;
1029
1030    /**
1031     * Set the node's value to the provided list.
1032     *
1033     * <p>This method provides a helper for constructing the appropriate
1034     * {@link Type} for serializing a {@link List}</p>
1035     *
1036     * @param elementType the type of the list elements. This must not be
1037     *         a raw type.
1038     * @param items the list to serializer
1039     * @param <V> list element type, the {@code T} in {@code List<T>}
1040     * @return this node
1041     * @throws SerializationException if the value fails to be converted to the
1042     *         requested type.
1043     * @see #set(TypeToken, Object) for details on restrictions.
1044     * @since 4.0.0
1045     */
1046    @SuppressWarnings("checkstyle:NoGetSetPrefix") // set prefix for type alias purposes
1047    default <V> ConfigurationNode setList(Class<V> elementType, @Nullable List<V> items) throws SerializationException {
1048        return set(TypeFactory.parameterizedClass(List.class, elementType), items);
1049    }
1050
1051    /**
1052     * Set the node's value to the provided list.
1053     *
1054     * <p>This method provides a helper for constructing the appropriate
1055     * {@link Type} for serializing a {@link List}</p>
1056     *
1057     * @param elementType the type of the list elements. This must not be
1058     *         a raw type.
1059     * @param items the list to serializer
1060     * @param <V> list element type, the {@code T} in {@code List<T>}
1061     * @return this node
1062     * @throws SerializationException if the value fails to be converted to the
1063     *         requested type.
1064     * @see #set(TypeToken, Object) for details on restrictions.
1065     * @since 4.0.0
1066     */
1067    @SuppressWarnings("checkstyle:NoGetSetPrefix") // set prefix for type alias purposes
1068    default <V> ConfigurationNode setList(TypeToken<V> elementType, @Nullable List<V> items) throws SerializationException {
1069        return set(TypeFactory.parameterizedClass(List.class, elementType.getType()), items);
1070    }
1071
1072    /**
1073     * Get the raw value of this node.
1074     *
1075     * <p>The raw value is the plain value that will be passed to the loaders,
1076     * without serialization except for unwrapping of maps and collections.</p>
1077     *
1078     * @return this configuration's current value
1079     * @see #raw(Object)
1080     * @since 4.0.0
1081     */
1082    @Nullable Object raw();
1083
1084    /**
1085     * Set the raw value of this node.
1086     *
1087     * <p>The provided value must be of a type accepted by
1088     * {@link ConfigurationOptions#acceptsType(Class)}. No other serialization
1089     * will be performed.</p>
1090     *
1091     * @param value the value to set on this node
1092     * @return this node
1093     * @since 4.0.0
1094     */
1095    ConfigurationNode raw(@Nullable Object value);
1096
1097    /**
1098     * Get the raw value of this node if the node is a scalar.
1099     *
1100     * <p>The raw value is the plain value that will be passed to the loaders,
1101     * without serialization.</p>
1102     *
1103     * <p>Map and list values will not be unboxed.</p>
1104     *
1105     * @return this configuration's current value if it is a scalar,
1106     *          or else null.
1107     * @see #raw()
1108     * @since 4.0.0
1109     */
1110    @Nullable Object rawScalar();
1111
1112    /**
1113     * Apply all data from {@code other} to this node, overwriting any
1114     * existing data.
1115     *
1116     * @param other source node
1117     * @return this node
1118     * @since 4.0.0
1119     */
1120    ConfigurationNode from(ConfigurationNode other);
1121
1122    /**
1123     * Set all the values from the given node that are not present in this node
1124     * to their values in the provided node.
1125     *
1126     * <p>Map keys will be merged. Lists and scalar values will be replaced.</p>
1127     *
1128     * @param other the node to merge values from
1129     * @return this node
1130     * @since 4.0.0
1131     */
1132    ConfigurationNode mergeFrom(ConfigurationNode other);
1133
1134    /**
1135     * Removes a direct child of this node.
1136     *
1137     * @param key the key of the node to remove
1138     * @return if a node was removed
1139     * @since 4.0.0
1140     */
1141    boolean removeChild(Object key);
1142
1143    /**
1144     * Gets a new child node created as the next entry in the list.
1145     *
1146     * @return a new child created as the next entry in the list when it is
1147     *         attached
1148     * @since 4.0.0
1149     */
1150    ConfigurationNode appendListNode();
1151
1152    /**
1153     * Creates a deep copy of this node.
1154     *
1155     * <p>If this node has child nodes (is a list or map), the child nodes will
1156     * also be copied. This action is performed recursively.</p>
1157     *
1158     * <p>The resultant node will (initially) contain the same value(s) as this
1159     * node, and will therefore be {@link Object#equals(Object) equal}, however,
1160     * changes made to the original will not be reflected in the copy,
1161     * and vice versa.</p>
1162     *
1163     * <p>The actual scalar values that back the configuration will
1164     * <strong>not</strong> be copied - only the node structure that forms the
1165     * configuration. This is not a problem in most cases, as the scalar values
1166     * stored in configurations are usually immutable. (e.g. strings,
1167     * numbers, booleans).</p>
1168     *
1169     * @return a copy of this node
1170     * @since 4.0.0
1171     */
1172    ConfigurationNode copy();
1173
1174    /**
1175     * Visit this node hierarchy as described in {@link ConfigurationVisitor}.
1176     *
1177     * @param visitor the visitor
1178     * @param <S> the state type
1179     * @param <T> the terminal type
1180     * @param <E> exception type that may be thrown
1181     * @return returned terminal from the visitor
1182     * @throws E when throw by visitor implementation
1183     * @since 4.0.0
1184     */
1185    default <S, T, E extends Exception> T visit(ConfigurationVisitor<S, T, E> visitor) throws E {
1186        return visit(visitor, visitor.newState());
1187    }
1188
1189    /**
1190     * Visit this node hierarchy as described in {@link ConfigurationVisitor}.
1191     *
1192     * @param visitor the visitor
1193     * @param state the state to start with
1194     * @param <T> the terminal type
1195     * @param <S> the state type
1196     * @param <E> exception type that may be thrown
1197     * @return returned terminal from the visitor
1198     * @throws E when throw by visitor implementation
1199     * @since 4.0.0
1200     */
1201    <S, T, E extends Exception> T visit(ConfigurationVisitor<S, T, E> visitor, S state) throws E;
1202
1203    /**
1204     * Visit this node hierarchy as described in {@link ConfigurationVisitor}.
1205     *
1206     * <p>This overload will remove the need for exception handling for visitors
1207     * that do not have any checked exceptions.</p>
1208     *
1209     * @param visitor the visitor
1210     * @param <S> the state type
1211     * @param <T> the terminal type
1212     * @return the returned terminal from the visitor
1213     * @since 4.0.0
1214     */
1215    default <S, T> T visit(ConfigurationVisitor.Safe<S, T> visitor) {
1216        return visit(visitor, visitor.newState());
1217    }
1218
1219    /**
1220     * Visit this node hierarchy as described in {@link ConfigurationVisitor}.
1221     *
1222     * <p>This overload will remove the need for exception handling for visitors
1223     * that do not have any checked exceptions.</p>
1224     *
1225     * @param visitor the visitor
1226     * @param state the state to start with
1227     * @param <T> the terminal type
1228     * @param <S> the state type
1229     * @return the returned terminal from the visitor
1230     * @since 4.0.0
1231     */
1232    <S, T> T visit(ConfigurationVisitor.Safe<S, T> visitor, S state);
1233
1234    /**
1235     * Set a representation hint on this node.
1236     *
1237     * <p>Removing a hint from this node means the hint's value will be
1238     * delegated to the node's parent. To explicitly revert to a hint's default,
1239     * apply that default value.</p>
1240     *
1241     * @param hint the hint to set a value for
1242     * @param value value to set, or null to unset for self
1243     * @param <V> hint value type
1244     * @return this node
1245     * @since 4.0.0
1246     */
1247    <V> ConfigurationNode hint(RepresentationHint<V> hint, @Nullable V value);
1248
1249    /**
1250     * Query a representation hint from this node.
1251     *
1252     * <p>If the hint is not set on this node, its parents will be recursively
1253     * checked for a value.</p>
1254     *
1255     * @param hint the hint to get
1256     * @param <V> value type
1257     * @return value of the hint, or {@link RepresentationHint#defaultValue()}
1258     * @since 4.0.0
1259     */
1260    <V> @Nullable V hint(RepresentationHint<V> hint);
1261
1262    /**
1263     * Query a representation hint from this node.
1264     *
1265     * <p>This will only check the current node, and return null rather than
1266     * any default value.</p>
1267     *
1268     * @param hint the hint to get
1269     * @param <V> value type
1270     * @return value of the hint, or {@code null}
1271     * @since 4.0.0
1272     */
1273    <V> @Nullable V ownHint(RepresentationHint<V> hint);
1274
1275    /**
1276     * Get an unmodifiable copy of representation hints stored on this node.
1277     *
1278     * <p>This does not include inherited hints.</p>
1279     *
1280     * @return copy of hints this node has set.
1281     * @since 4.0.0
1282     */
1283    Map<RepresentationHint<?>, ?> ownHints();
1284
1285}