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}