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