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 ninja.leaping.configurate; 018 019import com.google.common.collect.ImmutableList; 020import com.google.common.collect.Iterables; 021import com.google.common.reflect.TypeToken; 022import ninja.leaping.configurate.loader.ConfigurationLoader; 023import ninja.leaping.configurate.objectmapping.ObjectMappingException; 024import ninja.leaping.configurate.objectmapping.serialize.TypeSerializer; 025import org.checkerframework.checker.nullness.qual.NonNull; 026import org.checkerframework.checker.nullness.qual.Nullable; 027 028import java.util.Collection; 029import java.util.List; 030import java.util.Map; 031import java.util.function.Consumer; 032import java.util.function.Function; 033import java.util.function.Supplier; 034 035import static java.util.Objects.requireNonNull; 036 037/** 038 * A node in the configuration tree. 039 * 040 * <p>All aspects of a configurations structure are represented using instances of 041 * {@link ConfigurationNode}, and the links between them.</p> 042 * 043 * <p>{@link ConfigurationNode}s can hold different types of {@link ValueType values}. They can:</p> 044 * 045 * <ul> 046 * <li>Hold a single "scalar" value ({@link ValueType#SCALAR})</li> 047 * <li>Represent a "list" of child {@link ConfigurationNode}s ({@link ValueType#LIST})</li> 048 * <li>Represent a "map" of child {@link ConfigurationNode}s ({@link ValueType#MAP})</li> 049 * <li>Hold no value at all ({@link ValueType#NULL})</li> 050 * </ul> 051 * 052 * <p>The overall configuration stems from a single "root" node, which is provided by the 053 * {@link ConfigurationLoader}, or by other means programmatically.</p> 054 * 055 * <p>This is effectively the main class of Configurate.</p> 056 */ 057public interface ConfigurationNode { 058 int NUMBER_DEF = 0; 059 060 @NonNull 061 static ConfigurationNode root() { 062 return root(ConfigurationOptions.defaults()); 063 } 064 065 @NonNull 066 static ConfigurationNode root(Consumer<ConfigurationNode> action) { 067 return root(ConfigurationOptions.defaults(), action); 068 } 069 070 @NonNull 071 static ConfigurationNode root(@NonNull ConfigurationOptions options) { 072 return new SimpleConfigurationNode(null, null, options); 073 } 074 075 @NonNull 076 static ConfigurationNode root(@NonNull ConfigurationOptions options, Consumer<ConfigurationNode> action) { 077 return new SimpleConfigurationNode(null, null, options).act(action); 078 } 079 080 /** 081 * Gets the "key" of this node. 082 * 083 * <p>The key determines this {@link ConfigurationNode}s position within the overall 084 * configuration structure.</p> 085 * 086 * <p>If this node is currently {@link #isVirtual() virtual}, this method's result may be 087 * inaccurate.</p> 088 * 089 * <p>Note that this method only returns the nearest "link" in the hierarchy, and does not 090 * return a representation of the full path. See {@link #getPath()} for that.</p> 091 * 092 * <p>The {@link ConfigurationNode}s returned as values from {@link #getChildrenMap()} will 093 * have keys derived from their pairing in the map node.</p> 094 * 095 * <p>The {@link ConfigurationNode}s returned from {@link #getChildrenList()} will have keys 096 * derived from their position (index) in the list node.</p> 097 * 098 * @return The key of this node 099 */ 100 @Nullable 101 Object getKey(); 102 103 /** 104 * Gets the full path of {@link #getKey() keys} from the root node to this node. 105 * 106 * <p>Node implementations may not keep a full path for each node, so this method may be 107 * somewhat complex to calculate. Most uses should not need to calculate the full path unless providing debug information</p> 108 * 109 * @return An array compiled from the keys for each node up the hierarchy 110 * @see #getKey() for this node's key relative to its direct parent 111 */ 112 @NonNull 113 Object[] getPath(); 114 115 /** 116 * Gets the parent of this node. 117 * 118 * <p>If this node is currently {@link #isVirtual() virtual}, this method's result may be 119 * inaccurate.</p> 120 * 121 * @return The nodes parent 122 */ 123 @Nullable 124 ConfigurationNode getParent(); 125 126 /** 127 * Gets the node at the given (relative) path, possibly traversing multiple levels of nodes. 128 * 129 * <p>This is the main method used to navigate through the configuration.</p> 130 * 131 * <p>The path parameter effectively consumes an array of keys, which locate the unique position 132 * of a given node within the structure. Each element will navigate one level down in the configration hierarchy</p> 133 * 134 * <p>A node is <b>always</b> returned by this method. If the given node does not exist in the 135 * structure, a {@link #isVirtual() virtual} node will be returned which represents the 136 * position.</p> 137 * 138 * @param path The path to fetch the node at 139 * @return The node at the given path, possibly virtual 140 */ 141 @NonNull 142 ConfigurationNode getNode(@NonNull Object @NonNull... path); 143 144 /** 145 * Gets the node at the given (relative) path, possibly traversing multiple levels of nodes. 146 * 147 * <p>This is the main method used to navigate through the configuration.</p> 148 * 149 * <p>The path parameter effectively consumes an iterable of keys, which locate the unique position 150 * of a given node within the structure.</p> 151 * 152 * <p>A node is <b>always</b> returned by this method. If the given node does not exist in the 153 * structure, a {@link #isVirtual() virtual} node will be returned which represents the 154 * position.</p> 155 * 156 * @param path The path to fetch the node at 157 * @return The node at the given path, possibly virtual 158 */ 159 @NonNull 160 default ConfigurationNode getNode(@NonNull Iterable<?> path) { 161 return getNode(Iterables.toArray(requireNonNull(path, "path"), Object.class)); 162 } 163 164 /** 165 * Gets if this node is virtual. 166 * 167 * <p>Virtual nodes are nodes which are not attached to a wider configuration structure.</p> 168 * 169 * <p>A node is primarily "virtual" when it has no set value.</p> 170 * 171 * @return true if this node is virtual 172 */ 173 boolean isVirtual(); 174 175 /** 176 * Gets the options that currently apply to this node 177 * 178 * @return The ConfigurationOptions instance that governs the functionality of this node 179 */ 180 @NonNull 181 ConfigurationOptions getOptions(); 182 183 /** 184 * Gets the value type of this node. 185 * 186 * @return The value type 187 * @deprecated Use {@link ConfigurationNode#isList()} and {@link ConfigurationNode#isMap()} for the same information 188 */ 189 @NonNull 190 @Deprecated 191 ValueType getValueType(); 192 193 /** 194 * Gets if this node has "list children". 195 * 196 * @return if this node has children in the form of a list 197 */ 198 default boolean isList() { 199 return getValueType() == ValueType.LIST; 200 } 201 202 /** 203 * Gets if this node has "map children". 204 * 205 * @return if this node has children in the form of a map 206 */ 207 default boolean isMap() { 208 return getValueType() == ValueType.MAP; 209 } 210 211 /** 212 * Gets if this node has "list children". 213 * 214 * @return if this node has children in the form of a list 215 * @deprecated Use {@link #isList()} instead 216 */ 217 @Deprecated 218 default boolean hasListChildren() { 219 return isList(); 220 } 221 222 /** 223 * Gets if this node has "map children" 224 * 225 * @return if this node has children in the form of a map 226 * @deprecated Use {@link #isMap()} instead 227 */ 228 @Deprecated 229 default boolean hasMapChildren() { 230 return isMap(); 231 } 232 233 /** 234 * Return true when this node has a null or empty value. Values that may result in this method returning true include: 235 * 236 * <ul> 237 * <li><code>null</code></li> 238 * <li>the empty string</li> 239 * <li>an empty map</li> 240 * <li>an empty list</li> 241 * <li>Any other type of empty collection</li> 242 * </ul> 243 * 244 * This is a distinct value from {@link #isVirtual()}. Emptiness refers to the value of this node itself, 245 * while virtuality refers to whether or not this node is attached to its parent and the rest of the configuration 246 * structure. 247 * 248 * @return Whether this node is empty 249 */ 250 default boolean isEmpty() { // backwards compat 251 if (isVirtual()) { 252 return true; 253 } 254 255 if (isMap()) { 256 return getChildrenMap().isEmpty(); 257 } else if (isList()) { 258 return getChildrenList().isEmpty(); 259 } else { 260 return getValue() == null; 261 } 262 } 263 264 /** 265 * Gets the "list children" attached to this node, if it has any. 266 * 267 * <p>If this node does not {@link #isList() have list children}, an empty list is 268 * returned. For example, if the value of this node is a map, this will return an empty result.</p> 269 * 270 * @return The list children currently attached to this node 271 */ 272 @NonNull 273 List<? extends ConfigurationNode> getChildrenList(); 274 275 /** 276 * Gets the "map children" attached to this node, if it has any. 277 * 278 * <p>If this node does not {@link #isMap() have map children}, an empty map 279 * returned.</p> 280 * 281 * @return The map children currently attached to this node 282 */ 283 @NonNull 284 Map<Object, ? extends ConfigurationNode> getChildrenMap(); 285 286 /** 287 * Get the current value associated with this node. 288 * 289 * <p>If this node has children, this method will recursively unwrap them to construct a List 290 * or a Map.</p> 291 * 292 * @see #getValue(Object) 293 * @return This configuration's current value, or null if there is none 294 */ 295 @Nullable 296 default Object getValue() { 297 return getValue((Object) null); 298 } 299 300 /** 301 * Get the current value associated with this node. 302 * 303 * <p>If this node has children, this method will recursively unwrap them to construct a List 304 * or a Map.</p> 305 * 306 * @param def The default value to return if this node has no set value 307 * @return This configuration's current value, or {@code def} if there is none 308 */ 309 Object getValue(@Nullable Object def); 310 311 /** 312 * Get the current value associated with this node. 313 * 314 * <p>If this node has children, this method will recursively unwrap them to construct a List 315 * or a Map.</p> 316 * 317 * @param defSupplier The function that will be called to calculate a default value only if 318 * there is no existing value 319 * @return This configuration's current value, or {@code def} if there is none 320 */ 321 Object getValue(@NonNull Supplier<Object> defSupplier); 322 323 /** 324 * Gets the appropriately transformed typed version of this node's value from the provided 325 * transformation function. 326 * 327 * @param transformer The transformation function 328 * @param <T> The expected type 329 * @return A transformed value of the correct type, or null either if no value is present or the 330 * value could not be converted 331 */ 332 @Nullable 333 default <T> T getValue(@NonNull Function<Object, T> transformer) { 334 return getValue(transformer, (T) null); 335 } 336 337 /** 338 * Gets the appropriately transformed typed version of this node's value from the provided 339 * transformation function. 340 * 341 * @param transformer The transformation function 342 * @param def The default value to return if this node has no set value or is not of a 343 * convertible type 344 * @param <T> The expected type 345 * @return A transformed value of the correct type, or {@code def} either if no value is present 346 * or the value could not be converted 347 */ 348 <T> T getValue(@NonNull Function<Object, T> transformer, @Nullable T def); 349 350 /** 351 * Gets the appropriately transformed typed version of this node's value from the provided 352 * transformation function. 353 * 354 * @param transformer The transformation function 355 * @param defSupplier The function that will be called to calculate a default value only if 356 * there is no existing value of the correct type 357 * @param <T> The expected type 358 * @return A transformed value of the correct type, or {@code def} either if no value is present 359 * or the value could not be converted 360 */ 361 <T> T getValue(@NonNull Function<Object, T> transformer, @NonNull Supplier<T> defSupplier); 362 363 /** 364 * If this node has list values, this function unwraps them and converts them to an appropriate 365 * type based on the provided function. 366 * 367 * <p>If this node has a scalar value, this function treats it as a list with one value</p> 368 * 369 * @param transformer The transformation function 370 * @param <T> The expected type 371 * @return An immutable copy of the values contained 372 */ 373 @NonNull 374 <T> List<T> getList(@NonNull Function<Object, T> transformer); 375 376 /** 377 * If this node has list values, this function unwraps them and converts them to an appropriate 378 * type based on the provided function. 379 * 380 * <p>If this node has a scalar value, this function treats it as a list with one value.</p> 381 * 382 * @param transformer The transformation function 383 * @param def The default value if no appropriate value is set 384 * @param <T> The expected type 385 * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no 386 * values could be converted 387 */ 388 <T> List<T> getList(@NonNull Function<Object, T> transformer, @Nullable List<T> def); 389 390 /** 391 * If this node has list values, this function unwraps them and converts them to an appropriate 392 * type based on the provided function. 393 * 394 * <p>If this node has a scalar value, this function treats it as a list with one value.</p> 395 * 396 * @param transformer The transformation function 397 * @param defSupplier The function that will be called to calculate a default value only if there is no existing 398 * value of the correct type 399 * @param <T> The expected type 400 * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no 401 * values could be converted 402 */ 403 <T> List<T> getList(@NonNull Function<Object, T> transformer, @NonNull Supplier<List<T>> defSupplier); 404 405 /** 406 * If this node has list values, this function unwraps them and converts them to an appropriate 407 * type based on the provided function. 408 * 409 * <p>If this node has a scalar value, this function treats it as a list with one value.</p> 410 * 411 * @param type The expected type 412 * @param <T> The expected type 413 * @return An immutable copy of the values contained 414 * @throws ObjectMappingException If any value fails to be converted to the requested type 415 */ 416 @NonNull 417 default <T> List<T> getList(@NonNull TypeToken<T> type) throws ObjectMappingException { 418 return getList(type, ImmutableList.of()); 419 } 420 421 /** 422 * If this node has list values, this function unwraps them and converts them to an appropriate 423 * type based on the provided function. 424 * 425 * <p>If this node has a scalar value, this function treats it as a list with one value.</p> 426 * 427 * @param type The expected type 428 * @param def The default value if no appropriate value is set 429 * @param <T> The expected type 430 * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no 431 * values could be converted 432 * @throws ObjectMappingException If any value fails to be converted to the requested type 433 */ 434 <T> List<T> getList(@NonNull TypeToken<T> type, @Nullable List<T> def) throws ObjectMappingException; 435 436 /** 437 * If this node has list values, this function unwraps them and converts them to an appropriate 438 * type based on the provided function. 439 * 440 * <p>If this node has a scalar value, this function treats it as a list with one value.</p> 441 * 442 * @param type The expected type 443 * @param defSupplier The function that will be called to calculate a default value only if there is no existing 444 * value of the correct type 445 * @param <T> The expected type 446 * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no 447 * values could be converted 448 * @throws ObjectMappingException If any value fails to be converted to the requested type 449 */ 450 <T> List<T> getList(@NonNull TypeToken<T> type, @NonNull Supplier<List<T>> defSupplier) throws ObjectMappingException; 451 452 /** 453 * Gets the value typed using the appropriate type conversion from {@link Types} 454 * 455 * @see #getValue() 456 * @return The appropriate type conversion, null if no appropriate value is available 457 */ 458 @Nullable 459 default String getString() { 460 return getString(null); 461 } 462 463 /** 464 * Gets the value typed using the appropriate type conversion from {@link Types} 465 * 466 * @param def The default value if no appropriate value is set 467 * @see #getValue() 468 * @return The appropriate type conversion, {@code def} if no appropriate value is available 469 */ 470 default String getString(@Nullable String def) { 471 return getValue(Types::asString, def); 472 } 473 474 /** 475 * Gets the value typed using the appropriate type conversion from {@link Types} 476 * 477 * @see #getValue() 478 * @return The appropriate type conversion, 0 if no appropriate value is available 479 */ 480 default float getFloat() { 481 return getFloat(NUMBER_DEF); 482 } 483 484 /** 485 * Gets the value typed using the appropriate type conversion from {@link Types} 486 * 487 * @param def The default value if no appropriate value is set 488 * @see #getValue() 489 * @return The appropriate type conversion, {@code def} if no appropriate value is available 490 */ 491 default float getFloat(float def) { 492 return getValue(Types::asFloat, def); 493 } 494 495 /** 496 * Gets the value typed using the appropriate type conversion from {@link Types} 497 * 498 * @see #getValue() 499 * @return The appropriate type conversion, 0 if no appropriate value is available 500 */ 501 default double getDouble() { 502 return getDouble(NUMBER_DEF); 503 } 504 505 /** 506 * Gets the value typed using the appropriate type conversion from {@link Types} 507 * 508 * @param def The default value if no appropriate value is set 509 * @see #getValue() 510 * @return The appropriate type conversion, {@code def} if no appropriate value is available 511 */ 512 default double getDouble(double def) { 513 return getValue(Types::asDouble, def); 514 } 515 516 /** 517 * Gets the value typed using the appropriate type conversion from {@link Types} 518 * 519 * @see #getValue() 520 * @return The appropriate type conversion, 0 if no appropriate value is available 521 */ 522 default int getInt() { 523 return getInt(NUMBER_DEF); 524 } 525 526 /** 527 * Gets the value typed using the appropriate type conversion from {@link Types} 528 * 529 * @param def The default value if no appropriate value is set 530 * @see #getValue() 531 * @return The appropriate type conversion, {@code def} if no appropriate value is available 532 */ 533 default int getInt(int def) { 534 return getValue(Types::asInt, def); 535 } 536 537 /** 538 * Gets the value typed using the appropriate type conversion from {@link Types} 539 * 540 * @see #getValue() 541 * @return The appropriate type conversion, 0 if no appropriate value is available 542 */ 543 default long getLong() { 544 return getLong(NUMBER_DEF); 545 } 546 547 /** 548 * Gets the value typed using the appropriate type conversion from {@link Types} 549 * 550 * @param def The default value if no appropriate value is set 551 * @see #getValue() 552 * @return The appropriate type conversion, {@code def} if no appropriate value is available 553 */ 554 default long getLong(long def) { 555 return getValue(Types::asLong, def); 556 } 557 558 /** 559 * Gets the value typed using the appropriate type conversion from {@link Types} 560 * 561 * @see #getValue() 562 * @return The appropriate type conversion, false if no appropriate value is available 563 */ 564 default boolean getBoolean() { 565 return getBoolean(false); 566 } 567 568 /** 569 * Gets the value typed using the appropriate type conversion from {@link Types} 570 * 571 * @param def The default value if no appropriate value is set 572 * @see #getValue() 573 * @return The appropriate type conversion, {@code def} if no appropriate value is available 574 */ 575 default boolean getBoolean(boolean def) { 576 return getValue(Types::asBoolean, def); 577 } 578 579 /** 580 * Get the current value associated with this node. 581 * 582 * <p>If this node has children, this method will recursively unwrap them to construct a 583 * List or a Map.</p> 584 * 585 * <p>This method will also perform deserialization using the appropriate TypeSerializer for 586 * the given type, or casting if no type serializer is found.</p> 587 * 588 * @param type The type to deserialize to 589 * @param <T> the type to get 590 * @return the value if present and of the proper type, else null 591 * @throws ObjectMappingException If the value fails to be converted to the requested type 592 */ 593 @Nullable 594 default <T> T getValue(@NonNull TypeToken<T> type) throws ObjectMappingException { 595 return getValue(type, (T) null); 596 } 597 598 /** 599 * Get the current value associated with this node. 600 * 601 * <p>If this node has children, this method will recursively unwrap them to construct a 602 * List or a Map.</p> 603 * 604 * <p>This method will also perform deserialization using the appropriate TypeSerializer for 605 * the given type, or casting if no type serializer is found.</p> 606 * 607 * @param type The type to deserialize to 608 * @param def The value to return if no value or value is not of appropriate type 609 * @param <T> the type to get 610 * @return the value if of the proper type, else {@code def} 611 * @throws ObjectMappingException If the value fails to be converted to the requested type 612 */ 613 <T> T getValue(@NonNull TypeToken<T> type, T def) throws ObjectMappingException; 614 615 /** 616 * Get the current value associated with this node. 617 * 618 * <p>If this node has children, this method will recursively unwrap them to construct a 619 * List or a Map.</p> 620 * 621 * <p>This method will also perform deserialization using the appropriate TypeSerializer for 622 * the given type, or casting if no type serializer is found.</p> 623 * 624 * @param type The type to deserialize to 625 * @param defSupplier The function that will be called to calculate a default value only if there is no existing 626 * value of the correct type 627 * @param <T> the type to get 628 * @return the value if of the proper type, else {@code def} 629 * @throws ObjectMappingException If the value fails to be converted to the requested type 630 */ 631 <T> T getValue(@NonNull TypeToken<T> type, @NonNull Supplier<T> defSupplier) throws ObjectMappingException; 632 633 /** 634 * Set this node's value to the given value. 635 * 636 * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into 637 * the appropriate configuration node structure.</p> 638 * 639 * This method only accepts <em>native types</em> as values. If the type of a value is unknown at runtime, 640 * {@link ConfigurationOptions#acceptsType(Class)} will return whether or not it is a native type. 641 * 642 * @param value The value to set 643 * @return this 644 * @see #setValue(TypeToken, Object) to set a value with any type conversion necessary 645 */ 646 @NonNull 647 ConfigurationNode setValue(@Nullable Object value); 648 649 /** 650 * Set this node's value to the given value. 651 * 652 * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into 653 * the appropriate configuration node structure.</p> 654 * 655 * <p>This method will also perform serialization using the appropriate TypeSerializer for the 656 * given type, or casting if no type serializer is found.</p> 657 * 658 * @param type The type to use for serialization type information 659 * @param value The value to set 660 * @param <T> The type to serialize to 661 * @return this 662 * @throws ObjectMappingException If the value fails to be converted to the requested type. No change will be made to the node. 663 */ 664 @NonNull 665 default <T> ConfigurationNode setValue(@NonNull TypeToken<T> type, @Nullable T value) throws ObjectMappingException { 666 if (value == null) { 667 setValue(null); 668 return this; 669 } 670 671 TypeSerializer<T> serial = getOptions().getSerializers().get(type); 672 if (serial != null) { 673 serial.serialize(type, value, this); 674 } else if (getOptions().acceptsType(value.getClass())) { 675 setValue(value); // Just write if no applicable serializer exists? 676 } else { 677 throw new ObjectMappingException("No serializer available for type " + type); 678 } 679 return this; 680 } 681 682 /** 683 * Set all the values from the given node that are not present in this node 684 * to their values in the provided node. 685 * 686 * <p>Map keys will be merged. Lists and scalar values will be replaced.</p> 687 * 688 * @param other The node to merge values from 689 * @return this 690 */ 691 @NonNull 692 ConfigurationNode mergeValuesFrom(@NonNull ConfigurationNode other); 693 694 /** 695 * Removes a direct child of this node 696 * 697 * @param key The key of the node to remove 698 * @return If a node was removed 699 */ 700 boolean removeChild(@NonNull Object key); 701 702 /** 703 * Gets a new child node created as the next entry in the list. 704 * 705 * @return A new child created as the next entry in the list when it is attached 706 * @deprecated Use {@link #appendListNode()} instead 707 */ 708 @Deprecated 709 @NonNull 710 ConfigurationNode getAppendedNode(); 711 712 /** 713 * Gets a new child node created as the next entry in the list. 714 * 715 * @return A new child created as the next entry in the list when it is attached 716 */ 717 @NonNull 718 default ConfigurationNode appendListNode() { 719 return getAppendedNode(); 720 } 721 722 /** 723 * Creates a deep copy of this node. 724 * 725 * <p>If this node has child nodes (is a list or map), the child nodes will 726 * also be copied. This action is performed recursively.</p> 727 * 728 * <p>The resultant node will (initially) contain the same value(s) as this node, 729 * and will therefore be {@link Object#equals(Object) equal}, however, changes made to 730 * the original will not be reflected in the copy, and vice versa.</p> 731 * 732 * <p>The actual scalar values that back the configuration will 733 * <strong>not</strong> be copied - only the node structure that forms the 734 * configuration. This is not a problem in most cases, as the scalar values 735 * stored in configurations are usually immutable. (e.g. strings, numbers, booleans).</p> 736 * 737 * @return A copy of this node 738 */ 739 @NonNull 740 ConfigurationNode copy(); 741 742 /** 743 * Execute an action on this node. This allows performing multiple operations 744 * on a single node without having to clutter up the surrounding scope. 745 * 746 * @param action The action to perform on this node 747 * @return this 748 */ 749 default ConfigurationNode act(Consumer<? super ConfigurationNode> action) { 750 action.accept(this); 751 return this; 752 } 753 754 /** 755 * Visit this node hierarchy as described in {@link ConfigurationVisitor} 756 * 757 * @param visitor The visitor 758 * @param <S> The state type 759 * @param <T> The terminal type 760 * @param <E> exception type that may be thrown 761 * @throws E when throw by visitor implementation 762 * @return The returned terminal from the visitor 763 */ 764 default <S, T, E extends Exception> T visit(ConfigurationVisitor<S, T, E> visitor) throws E { 765 return visit(visitor, visitor.newState()); 766 } 767 768 /** 769 * Visit this node hierarchy as described in {@link ConfigurationVisitor} 770 * 771 * @param visitor The visitor 772 * @param state The state to start with 773 * @param <T> The terminal type 774 * @param <S> The state type 775 * @param <E> exception type that may be thrown 776 * @throws E when throw by visitor implementation 777 * @return The returned terminal from the visitor 778 */ 779 default <S, T, E extends Exception> T visit(ConfigurationVisitor<S, T, E> visitor, S state) throws E { 780 throw new UnsupportedOperationException("Nodes of type " + getClass() + " do not support visitations!"); 781 } 782 783 /** 784 * Visit this node hierarchy as described in {@link ConfigurationVisitor} 785 * This overload will remove the need for exception handling for visitors that do not have any checked exceptions. 786 * 787 * @param visitor The visitor 788 * @param <S> The state type 789 * @param <T> The terminal type 790 * @return The returned terminal from the visitor 791 */ 792 default <S, T> T visit(ConfigurationVisitor.Safe<S, T> visitor) { 793 return visit(visitor, visitor.newState()); 794 } 795 796 /** 797 * Visit this node hierarchy as described in {@link ConfigurationVisitor} 798 * This overload will remove the need for exception handling for visitors that do not have any checked exceptions. 799 * 800 * @param visitor The visitor 801 * @param state The state to start with 802 * @param <T> The terminal type 803 * @param <S> The state type 804 * @return The returned terminal from the visitor 805 */ 806 default <S, T> T visit(ConfigurationVisitor.Safe<S, T> visitor, S state) { 807 throw new UnsupportedOperationException("Nodes of type " + getClass() + " do not support visitations!"); 808 } 809 810}