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