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