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