001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2019–2020 microBean™. 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 014 * implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.microbean.settings; 018 019import java.beans.BeanInfo; 020import java.beans.FeatureDescriptor; 021import java.beans.IntrospectionException; 022import java.beans.Introspector; 023import java.beans.PropertyDescriptor; 024import java.beans.PropertyEditor; 025 026import java.lang.annotation.Annotation; 027 028import java.lang.reflect.Method; 029import java.lang.reflect.Type; 030 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.Collection; 034import java.util.Collections; 035import java.util.Comparator; 036import java.util.HashSet; 037import java.util.Iterator; 038import java.util.LinkedHashSet; 039import java.util.NoSuchElementException; 040import java.util.Objects; 041import java.util.PriorityQueue; 042import java.util.Queue; 043import java.util.Set; 044 045import java.util.ConcurrentModificationException; // for javadoc only 046 047import java.util.function.BiFunction; 048import java.util.function.Supplier; 049 050import javax.el.ELContext; 051import javax.el.ELException; // for javadoc only 052import javax.el.ELResolver; 053import javax.el.ExpressionFactory; 054import javax.el.PropertyNotFoundException; 055import javax.el.StandardELContext; 056import javax.el.ValueExpression; 057 058import javax.enterprise.inject.Typed; 059 060import javax.enterprise.util.TypeLiteral; 061 062import org.microbean.development.annotation.Experimental; 063 064import org.microbean.settings.converter.PropertyEditorConverter; 065 066/** 067 * A provider of <a 068 * href="{@docRoot}/overview-summary.html#setting_name">named</a> <a 069 * href="{@docRoot}/overview-summary.html#setting_value">setting 070 * values</a> sourced from any number of {@linkplain Source sources}. 071 * 072 * <p>Please see the <a 073 * href="{@docRoot}/overview-summary.html#overview.description">overview</a> 074 * for necessary context.</p> 075 * 076 * <h1>Class Organization</h1> 077 * 078 * <p>The bulk of the methods that belong to the {@link Settings} 079 * class can be placed into two categories:</p> 080 * 081 * <ol> 082 * 083 * <li><strong>Value acquisition methods.</strong> These methods, such 084 * as the canonical {@link #get(String, Set, Converter, BiFunction)} 085 * method and its convenience forms, such as, simply, {@link 086 * #get(String)}, acquire values from {@link Source}s, {@linkplain 087 * #arbitrate(Set, String, Set, Collection) resolve ambiguities}, 088 * {@linkplain Converter#convert(Value) perform type conversion} and 089 * so on.</li> 090 * 091 * <li><strong>Configuration methods.</strong> These methods, such as 092 * the canonical {@link #configure(Object, Iterable, String, Set)} 093 * method and its convenience forms, such as, simply, {@link 094 * #configure(Object)}, fully configure Java Beans by using the value 095 * acquisition methods above in conjunction with {@link 096 * PropertyDescriptor} features from the Java Beans 097 * specification.</li> 098 * 099 * </ol> 100 * 101 * @author <a href="https://about.me/lairdnelson" 102 * target="_parent">Laird Nelson</a> 103 * 104 * @threadsafety Instances of this class are safe for concurrent use 105 * by multiple threads. 106 */ 107@Typed({ Settings.class }) 108public class Settings extends Source { 109 110 111 /* 112 * Static fields. 113 */ 114 115 116 private static final Comparator<Value> valueComparator = Comparator.<Value>comparingInt(v -> v.getQualifiers().size()).reversed(); 117 118 /** 119 * A convenient {@link BiFunction} suitable for use as a default 120 * value function normally provided to the {@link #get(String, Set, 121 * Type, BiFunction)} method and its ilk that returns {@code null} 122 * when invoked. 123 */ 124 public static final BiFunction<? super String, 125 ? super Set<? extends Annotation>, 126 ? extends String> NULL = (name, qualifiers) -> null; 127 128 /** 129 * A convenient {@link BiFunction} suitable for use as a default 130 * value function normally provided to the {@link #get(String, Set, 131 * Type, BiFunction)} method and its ilk that returns an empty 132 * {@link String} when invoked. 133 */ 134 public static final BiFunction<? super String, 135 ? super Set<? extends Annotation>, 136 ? extends String> EMPTY = (name, qualifiers) -> ""; 137 138 139 /* 140 * Instance fields. 141 */ 142 143 144 private final Set<Annotation> qualifiers; 145 146 private final ConverterProvider converterProvider; 147 148 private final BiFunction<? super String, 149 ? super Set<Annotation>, 150 ? extends Set<? extends Source>> sourcesFunction; 151 152 private final Iterable<? extends Arbiter> arbiters; 153 154 155 /* 156 * Constructors. 157 */ 158 159 160 /** 161 * Creates a new {@link Settings}. 162 * 163 * <p>The created instance will use an empty {@link Set} of 164 * qualifiers by default.</p> 165 * 166 * <p>The created instance will source its values from System 167 * properties and environment variables, in that order.</p> 168 * 169 * <p>The created instance will use a new {@link Converters} 170 * instance as its underlying source of {@link Converter} 171 * instances.</p> 172 * 173 * <p>The created instance will use a single {@link 174 * SourceOrderArbiter} as its mechanism for value arbitration.</p> 175 * 176 * @see #Settings(Set, BiFunction, ConverterProvider, Iterable) 177 */ 178 public Settings() { 179 super(); 180 181 this.qualifiers = Collections.emptySet(); 182 183 final Set<Source> sources = new LinkedHashSet<>(); 184 sources.add(new SystemPropertiesSource()); 185 sources.add(new EnvironmentVariablesSource()); 186 this.sourcesFunction = (name, qualifiers) -> Collections.unmodifiableSet(sources); 187 188 this.converterProvider = new Converters(); 189 190 this.arbiters = Collections.singleton(new SourceOrderArbiter()); 191 } 192 193 /** 194 * Creates a new {@link Settings}. 195 * 196 * @param sourcesFunction a {@link BiFunction} that accepts a <a 197 * href="{@docRoot}/overview-summary.html#setting_name">setting 198 * name</a> and a {@link Set} of {@linkplain Annotation qualifier 199 * annotations} and returns a {@link Set} of {@link Source}s 200 * appropriate for the request represented by its inputs; may be 201 * {@code null}; may return {@code null}; if non-{@code null} and 202 * this new {@link Settings} will be used concurrently by multiple 203 * threads, then this parameter value must be safe for concurrent 204 * use by multiple threads; any {@link Set} returned by this {@link 205 * BiFunction} will be {@linkplain Iterable#iterator() iterated 206 * over} by this {@link Settings} instance without any 207 * synchronization 208 * 209 * @param converterProvider a {@link ConverterProvider}; must not be 210 * {@code null}; if this new {@link Settings} will be used 211 * concurrently by multiple threads, then this parameter value must 212 * be safe for concurrent use by multiple threads 213 * 214 * @param arbiters an {@link Iterable} of {@link Arbiter}s; may be 215 * {@code null}; if this new {@link Settings} will be used 216 * concurrently by multiple threads, then this parameter value must 217 * be safe for concurrent use by multiple threads and {@link 218 * Iterator}s produced by its {@link Iterable#iterator() iterator()} 219 * method must also be safe for concurrent iteration by multiple 220 * threads 221 * 222 * @exception NullPointerException if {@code converterProvider} is 223 * {@code null} 224 * 225 * @see #Settings(Set, BiFunction, ConverterProvider, Iterable) 226 */ 227 public Settings(final BiFunction<? super String, 228 ? super Set<Annotation>, 229 ? extends Set<? extends Source>> sourcesFunction, 230 final ConverterProvider converterProvider, 231 final Iterable<? extends Arbiter> arbiters) { 232 this(null, sourcesFunction, converterProvider, arbiters); 233 } 234 235 /** 236 * Creates a new {@link Settings}. 237 * 238 * @param qualifiers a {@link Set} of {@linkplain Annotation 239 * annotations} that can be used to further qualify the selection of 240 * appropriate values; may be {@code null}; will be iterated over 241 * with no synchronization or locking and shallowly copied by this 242 * constructor 243 * 244 * @param sourcesFunction a {@link BiFunction} that accepts a <a 245 * href="{@docRoot}/overview-summary.html#setting_name">setting 246 * name</a> and a {@link Set} of {@linkplain Annotation qualifier 247 * annotations} and returns a {@link Set} of {@link Source}s 248 * appropriate for the request represented by its inputs; may be 249 * {@code null}; may return {@code null}; if non-{@code null} and 250 * this new {@link Settings} will be used concurrently by multiple 251 * threads, then this parameter value must be safe for concurrent 252 * use by multiple threads; any {@link Set} returned by this {@link 253 * BiFunction} will be {@linkplain Iterable#iterator() iterated 254 * over} by this {@link Settings} instance without any 255 * synchronization 256 * 257 * @param converterProvider a {@link ConverterProvider}; must not be 258 * {@code null}; if this new {@link Settings} will be used 259 * concurrently by multiple threads, then this parameter value must 260 * be safe for concurrent use by multiple threads 261 * 262 * @param arbiters an {@link Iterable} of {@link Arbiter}s; may be 263 * {@code null}; if this new {@link Settings} will be used 264 * concurrently by multiple threads, then this parameter value must 265 * be safe for concurrent use by multiple threads and {@link 266 * Iterator}s produced by its {@link Iterable#iterator() iterator()} 267 * method must also be safe for concurrent iteration by multiple 268 * threads 269 * 270 * @exception NullPointerException if {@code converterProvider} is 271 * {@code null} 272 */ 273 public Settings(final Set<Annotation> qualifiers, 274 final BiFunction<? super String, 275 ? super Set<Annotation>, 276 ? extends Set<? extends Source>> sourcesFunction, 277 final ConverterProvider converterProvider, 278 final Iterable<? extends Arbiter> arbiters) { 279 super(); 280 if (qualifiers == null || qualifiers.isEmpty()) { 281 this.qualifiers = Collections.emptySet(); 282 } else { 283 this.qualifiers = Collections.unmodifiableSet(new LinkedHashSet<>(qualifiers)); 284 } 285 if (sourcesFunction == null) { 286 this.sourcesFunction = (name, qs) -> Collections.emptySet(); 287 } else { 288 this.sourcesFunction = sourcesFunction; 289 } 290 this.converterProvider = Objects.requireNonNull(converterProvider); 291 if (arbiters == null) { 292 this.arbiters = Collections.emptySet(); 293 } else { 294 this.arbiters = arbiters; 295 } 296 } 297 298 299 /* 300 * Instance methods. 301 */ 302 303 304 /** 305 * Returns a suitable {@link String} value for a <a 306 * href="{@docRoot}/overview-summary.html#setting_name">setting 307 * name</a>d by the supplied {@code name}. 308 * 309 * @param name the name of the setting for which a value is to be 310 * returned; must not be {@code null} 311 * 312 * @return a suitable value (possibly {@code null}) 313 * 314 * @exception NullPointerException if {@code name} is {@code null} 315 * 316 * @exception NoSuchElementException if no value could be sourced 317 * 318 * @exception ValueAcquisitionException if there was a procedural 319 * problem acquiring a value 320 * 321 * @exception ArbitrationException if there was a problem performing 322 * value arbitration 323 * 324 * @exception AmbiguousValuesException if arbitration completed but 325 * could not resolve an ambiguity between potential return values 326 * 327 * @exception MalformedValuesException if the {@link 328 * #handleMalformedValues(String, Set, Collection)} method was 329 * overridden and the override throws a {@link 330 * MalformedValuesException} 331 * 332 * @exception ELException if there was an error related to 333 * expression language parsing or evaluation 334 * 335 * 336 * @exception ConcurrentModificationException if the {@link 337 * BiFunction} or {@link Iterable} supplied at {@linkplain 338 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 339 * construction time} throws one 340 * 341 * @threadsafety This method is and its overrides must be safe for 342 * concurrent use by multiple threads. 343 * 344 * @idempotency No guarantees of any kind are made with respect to 345 * the idempotency of this method or its overrides. 346 * 347 * @nullability This method may return {@code null}. 348 * 349 * @see #get(String, Set, Converter, BiFunction) 350 */ 351 public final String get(final String name) { 352 return this.get(name, 353 this.qualifiers, 354 this.converterProvider.getConverter(String.class), 355 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 356 } 357 358 /** 359 * Returns a suitable {@link String} value for a <a 360 * href="{@docRoot}/overview-summary.html#setting_name">setting 361 * name</a>d by the supplied {@code name} and with default value 362 * semantics implemented by the optional supplied {@code 363 * defaultValueFunction}. 364 * 365 * @param name the name of the setting for which a value is to be 366 * returned; must not be {@code null} 367 * 368 * @param defaultValue a {@link String} representation of the 369 * default value to be used in case <a 370 * href="{@docRoot}/overview-summary.html#setting_value_acquisition">setting 371 * value acquisition</a> does not yield a value; may be {@code null} 372 * 373 * @return a suitable value (possibly {@code null}) 374 * 375 * @exception NullPointerException if {@code name} is {@code null} 376 * 377 * @exception NoSuchElementException if {@code defaultValueFunction} 378 * was {@code null} and no value could be sourced 379 * 380 * @exception ValueAcquisitionException if there was a procedural 381 * problem acquiring a value 382 * 383 * @exception ArbitrationException if there was a problem performing 384 * value arbitration 385 * 386 * @exception AmbiguousValuesException if arbitration completed but 387 * could not resolve an ambiguity between potential return values 388 * 389 * @exception MalformedValuesException if the {@link 390 * #handleMalformedValues(String, Set, Collection)} method was 391 * overridden and the override throws a {@link 392 * MalformedValuesException} 393 * 394 * @exception ELException if there was an error related to 395 * expression language parsing or evaluation 396 * 397 * @exception ConcurrentModificationException if the {@link 398 * BiFunction} or {@link Iterable} supplied at {@linkplain 399 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 400 * construction time} throws one 401 * 402 * @threadsafety This method is and its overrides must be safe for 403 * concurrent use by multiple threads. 404 * 405 * @idempotency No guarantees of any kind are made with respect to 406 * the idempotency of this method or its overrides. 407 * 408 * @nullability This method may return {@code null}. 409 * 410 * @see #get(String, Set, Converter, BiFunction) 411 */ 412 public final String get(final String name, 413 final String defaultValue) { 414 return this.get(name, 415 this.qualifiers, 416 this.converterProvider.getConverter(String.class), 417 (n, qs) -> defaultValue); 418 } 419 420 /** 421 * Returns a suitable {@link String} value for a <a 422 * href="{@docRoot}/overview-summary.html#setting_name">setting 423 * name</a>d by the supplied {@code name} and with default value 424 * semantics implemented by the optional supplied {@code 425 * defaultValueFunction}. 426 * 427 * @param name the name of the setting for which a value is to be 428 * returned; must not be {@code null} 429 * 430 * @param defaultValueFunction a {@link BiFunction} accepting a <a 431 * href="{@docRoot}/overview-summary.html#setting_name">setting 432 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 433 * returns a default {@link String}-typed value when a value could 434 * not sourced; may be {@code null} in which case if no value can be 435 * sourced a {@link NoSuchElementException} will be thrown; may 436 * return {@code null}; must be safe for concurrent use by mulitple 437 * threads; must not call any of this {@link Settings} instance's 438 * methods or undefined behavior will result 439 * 440 * @return a suitable value (possibly {@code null}) 441 * 442 * @exception NullPointerException if {@code name} is {@code null} 443 * 444 * @exception NoSuchElementException if {@code defaultValueFunction} 445 * was {@code null} and no value could be sourced 446 * 447 * @exception ValueAcquisitionException if there was a procedural 448 * problem acquiring a value 449 * 450 * @exception ArbitrationException if there was a problem performing 451 * value arbitration 452 * 453 * @exception AmbiguousValuesException if arbitration completed but 454 * could not resolve an ambiguity between potential return values 455 * 456 * @exception MalformedValuesException if the {@link 457 * #handleMalformedValues(String, Set, Collection)} method was 458 * overridden and the override throws a {@link 459 * MalformedValuesException} 460 * 461 * @exception ELException if there was an error related to 462 * expression language parsing or evaluation 463 * 464 * @exception ConcurrentModificationException if the {@link 465 * BiFunction} or {@link Iterable} supplied at {@linkplain 466 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 467 * construction time} throws one 468 * 469 * @threadsafety This method is and its overrides must be safe for 470 * concurrent use by multiple threads. 471 * 472 * @idempotency No guarantees of any kind are made with respect to 473 * the idempotency of this method or its overrides. 474 * 475 * @nullability This method may return {@code null}. 476 * 477 * @see #get(String, Set, Converter, BiFunction) 478 */ 479 public final String get(final String name, 480 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 481 return this.get(name, 482 this.qualifiers, 483 this.converterProvider.getConverter(String.class), 484 defaultValueFunction); 485 } 486 487 /** 488 * Returns a suitable {@link String} value for a <a 489 * href="{@docRoot}/overview-summary.html#setting_name">setting 490 * name</a>d by the supplied {@code name} and <a 491 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 492 * with</a> the supplied {@code qualifiers}. 493 * 494 * @param name the name of the setting for which a value is to be 495 * returned; must not be {@code null} 496 * 497 * @param qualifiers a {@link Set} of {@link Annotation}s to further 498 * qualify the selection of the value to be returned; may be {@code 499 * null}; if non-{@code null} then this parameter value must be safe 500 * for concurrent iteration by multiple threads 501 * 502 * @return a suitable value (possibly {@code null}) 503 * 504 * @exception NullPointerException if {@code name} is {@code null} 505 * 506 * @exception NoSuchElementException if no value could be sourced 507 * 508 * @exception ValueAcquisitionException if there was a procedural 509 * problem acquiring a value 510 * 511 * @exception ArbitrationException if there was a problem performing 512 * value arbitration 513 * 514 * @exception AmbiguousValuesException if arbitration completed but 515 * could not resolve an ambiguity between potential return values 516 * 517 * @exception MalformedValuesException if the {@link 518 * #handleMalformedValues(String, Set, Collection)} method was 519 * overridden and the override throws a {@link 520 * MalformedValuesException} 521 * 522 * @exception ELException if there was an error related to 523 * expression language parsing or evaluation 524 * 525 * @exception ConcurrentModificationException if the {@link 526 * BiFunction} or {@link Iterable} supplied at {@linkplain 527 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 528 * construction time} throws one 529 * 530 * @threadsafety This method is and its overrides must be safe for 531 * concurrent use by multiple threads. 532 * 533 * @idempotency No guarantees of any kind are made with respect to 534 * the idempotency of this method or its overrides. 535 * 536 * @nullability This method may return {@code null}. 537 * 538 * @see #get(String, Set, Converter, BiFunction) 539 */ 540 public final String get(final String name, 541 final Set<Annotation> qualifiers) { 542 return this.get(name, 543 qualifiers, 544 this.converterProvider.getConverter(String.class), 545 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 546 } 547 548 /** 549 * Returns a suitable {@link String} value for a <a 550 * href="{@docRoot}/overview-summary.html#setting_name">setting 551 * name</a>d by the supplied {@code name} and <a 552 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 553 * with</a> the supplied {@code qualifiers} and with default value 554 * semantics implemented by the optional supplied {@code 555 * defaultValueFunction}. 556 * 557 * @param name the name of the setting for which a value is to be 558 * returned; must not be {@code null} 559 * 560 * @param qualifiers a {@link Set} of {@link Annotation}s to further 561 * qualify the selection of the value to be returned; may be {@code 562 * null}; if non-{@code null} then this parameter value must be safe 563 * for concurrent iteration by multiple threads 564 * 565 * @param defaultValue a {@link String} representation of the 566 * default value to be used in case <a 567 * href="{@docRoot}/overview-summary.html#setting_value_acquisition">setting 568 * value acquisition</a> does not yield a value; may be {@code null} 569 * 570 * @return a suitable value (possibly {@code null}) 571 * 572 * @exception NullPointerException if {@code name} is {@code null} 573 * 574 * @exception NoSuchElementException if {@code defaultValueFunction} 575 * was {@code null} and no value could be sourced 576 * 577 * @exception ValueAcquisitionException if there was a procedural 578 * problem acquiring a value 579 * 580 * @exception ArbitrationException if there was a problem performing 581 * value arbitration 582 * 583 * @exception AmbiguousValuesException if arbitration completed but 584 * could not resolve an ambiguity between potential return values 585 * 586 * @exception MalformedValuesException if the {@link 587 * #handleMalformedValues(String, Set, Collection)} method was 588 * overridden and the override throws a {@link 589 * MalformedValuesException} 590 * 591 * @exception ELException if there was an error related to 592 * expression language parsing or evaluation 593 * 594 * @exception ConcurrentModificationException if the {@link 595 * BiFunction} or {@link Iterable} supplied at {@linkplain 596 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 597 * construction time} throws one 598 * 599 * @threadsafety This method is and its overrides must be safe for 600 * concurrent use by multiple threads. 601 * 602 * @idempotency No guarantees of any kind are made with respect to 603 * the idempotency of this method or its overrides. 604 * 605 * @nullability This method may return {@code null}. 606 * 607 * @see #get(String, Set, Converter, BiFunction) 608 */ 609 public final String get(final String name, 610 final Set<Annotation> qualifiers, 611 final String defaultValue) { 612 return this.get(name, 613 qualifiers, 614 this.converterProvider.getConverter(String.class), 615 (n, qs) -> defaultValue); 616 } 617 618 /** 619 * Returns a suitable {@link String} value for a <a 620 * href="{@docRoot}/overview-summary.html#setting_name">setting 621 * name</a>d by the supplied {@code name} and <a 622 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 623 * with</a> the supplied {@code qualifiers} and with default value 624 * semantics implemented by the optional supplied {@code 625 * defaultValueFunction}. 626 * 627 * @param name the name of the setting for which a value is to be 628 * returned; must not be {@code null} 629 * 630 * @param qualifiers a {@link Set} of {@link Annotation}s to further 631 * qualify the selection of the value to be returned; may be {@code 632 * null}; if non-{@code null} then this parameter value must be safe 633 * for concurrent iteration by multiple threads 634 * 635 * @param defaultValueFunction a {@link BiFunction} accepting a <a 636 * href="{@docRoot}/overview-summary.html#setting_name">setting 637 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 638 * returns a default {@link String}-typed value when a value could 639 * not sourced; may be {@code null} in which case if no value can be 640 * sourced a {@link NoSuchElementException} will be thrown; may 641 * return {@code null}; must be safe for concurrent use by mulitple 642 * threads; must not call any of this {@link Settings} instance's 643 * methods or undefined behavior will result 644 * 645 * @return a suitable value (possibly {@code null}) 646 * 647 * @exception NullPointerException if {@code name} is {@code null} 648 * 649 * @exception NoSuchElementException if {@code defaultValueFunction} 650 * was {@code null} and no value could be sourced 651 * 652 * @exception ValueAcquisitionException if there was a procedural 653 * problem acquiring a value 654 * 655 * @exception ArbitrationException if there was a problem performing 656 * value arbitration 657 * 658 * @exception AmbiguousValuesException if arbitration completed but 659 * could not resolve an ambiguity between potential return values 660 * 661 * @exception MalformedValuesException if the {@link 662 * #handleMalformedValues(String, Set, Collection)} method was 663 * overridden and the override throws a {@link 664 * MalformedValuesException} 665 * 666 * @exception ELException if there was an error related to 667 * expression language parsing or evaluation 668 * 669 * @exception ConcurrentModificationException if the {@link 670 * BiFunction} or {@link Iterable} supplied at {@linkplain 671 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 672 * construction time} throws one 673 * 674 * @threadsafety This method is and its overrides must be safe for 675 * concurrent use by multiple threads. 676 * 677 * @idempotency No guarantees of any kind are made with respect to 678 * the idempotency of this method or its overrides. 679 * 680 * @nullability This method may return {@code null}. 681 * 682 * @see #get(String, Set, Converter, BiFunction) 683 */ 684 public final String get(final String name, 685 final Set<Annotation> qualifiers, 686 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 687 return this.get(name, 688 qualifiers, 689 this.converterProvider.getConverter(String.class), 690 defaultValueFunction); 691 } 692 693 //---------------------------------------------------------------------------- 694 695 /** 696 * Returns a suitable value for a <a 697 * href="{@docRoot}/overview-summary.html#setting_name">setting 698 * name</a>d by the supplied {@code name} as {@linkplain 699 * Converter#convert(Value) converted} by the {@link Converter} 700 * {@linkplain ConverterProvider#getConverter(Class) located} using 701 * the supplied {@link Class}. 702 * 703 * @param <T> the type to which any value should be {@linkplain 704 * Converter#convert(Value) converted} 705 * 706 * @param name the name of the setting for which a value is to be 707 * returned; must not be {@code null} 708 * 709 * @param type a {@link Class} used to {@linkplain 710 * ConverterProvider#getConverter(Class) locate} an appropriate 711 * {@link Converter}; must not be {@code null} 712 * 713 * @return a suitable value (possibly {@code null}) 714 * 715 * @exception NullPointerException if either {@code name} or {@code 716 * class} is {@code null} 717 * 718 * @exception IllegalArgumentException if {@linkplain 719 * Converter#convert(Value) conversion} could not occur for any 720 * reason; see {@link Converter#convert(Value)} 721 * 722 * @exception ConversionException if {@linkplain 723 * Converter#convert(Value) conversion} could not occur for any 724 * reason other than bad inputs 725 * 726 * @exception NoSuchElementException if no value could be sourced 727 * 728 * @exception ValueAcquisitionException if there was a procedural 729 * problem acquiring a value 730 * 731 * @exception ArbitrationException if there was a problem performing 732 * value arbitration 733 * 734 * @exception AmbiguousValuesException if arbitration completed but 735 * could not resolve an ambiguity between potential return values 736 * 737 * @exception MalformedValuesException if the {@link 738 * #handleMalformedValues(String, Set, Collection)} method was 739 * overridden and the override throws a {@link 740 * MalformedValuesException} 741 * 742 * @exception ELException if there was an error related to 743 * expression language parsing or evaluation 744 * 745 * @exception ConcurrentModificationException if the {@link 746 * BiFunction} or {@link Iterable} supplied at {@linkplain 747 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 748 * construction time} throws one 749 * 750 * @threadsafety This method is and its overrides must be safe for 751 * concurrent use by multiple threads. 752 * 753 * @idempotency No guarantees of any kind are made with respect to 754 * the idempotency of this method or its overrides. 755 * 756 * @nullability This method may return {@code null}. 757 * 758 * @see #get(String, Set, Converter, BiFunction) 759 */ 760 public final <T> T get(final String name, 761 final Class<T> type) { 762 return this.get(name, 763 this.qualifiers, 764 this.converterProvider.getConverter(type), 765 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 766 } 767 768/** 769 * Returns a suitable value for a <a 770 * href="{@docRoot}/overview-summary.html#setting_name">setting 771 * name</a>d by the supplied {@code name} as {@linkplain 772 * Converter#convert(Value) converted} by the {@link Converter} 773 * {@linkplain ConverterProvider#getConverter(Class) located} using 774 * the supplied {@link Class}, and with default value semantics 775 * implemented by the optional supplied {@code 776 * defaultValueFunction}. 777 * 778 * @param <T> the type to which any value should be {@linkplain 779 * Converter#convert(Value) converted} 780 * 781 * @param name the name of the setting for which a value is to be 782 * returned; must not be {@code null} 783 * 784 * @param type a {@link Class} used to {@linkplain 785 * ConverterProvider#getConverter(Class) locate} an appropriate 786 * {@link Converter}; must not be {@code null} 787 * 788 * @param defaultValue a {@link String} representation of the 789 * default value to be used in case <a 790 * href="{@docRoot}/overview-summary.html#setting_value_acquisition">setting 791 * value acquisition</a> does not yield a value; may be {@code null} 792 * 793 * @return a suitable value (possibly {@code null}) 794 * 795 * @exception NullPointerException if either {@code name} or {@code 796 * class} is {@code null} 797 * 798 * @exception IllegalArgumentException if {@linkplain 799 * Converter#convert(Value) conversion} could not occur for any 800 * reason; see {@link Converter#convert(Value)} 801 * 802 * @exception ConversionException if {@linkplain 803 * Converter#convert(Value) conversion} could not occur for any 804 * reason other than bad inputs 805 * 806 * @exception NoSuchElementException if {@code defaultValueFunction} 807 * was {@code null} and no value could be sourced 808 * 809 * @exception ValueAcquisitionException if there was a procedural 810 * problem acquiring a value 811 * 812 * @exception ArbitrationException if there was a problem performing 813 * value arbitration 814 * 815 * @exception AmbiguousValuesException if arbitration completed but 816 * could not resolve an ambiguity between potential return values 817 * 818 * @exception MalformedValuesException if the {@link 819 * #handleMalformedValues(String, Set, Collection)} method was 820 * overridden and the override throws a {@link 821 * MalformedValuesException} 822 * 823 * @exception ELException if there was an error related to 824 * expression language parsing or evaluation 825 * 826 * @exception ConcurrentModificationException if the {@link 827 * BiFunction} or {@link Iterable} supplied at {@linkplain 828 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 829 * construction time} throws one 830 * 831 * @threadsafety This method is and its overrides must be safe for 832 * concurrent use by multiple threads. 833 * 834 * @idempotency No guarantees of any kind are made with respect to 835 * the idempotency of this method or its overrides. 836 * 837 * @nullability This method may return {@code null}. 838 * 839 * @see #get(String, Set, Converter, BiFunction) 840 */ 841 public final <T> T get(final String name, 842 final Class<T> type, 843 final String defaultValue) { 844 return this.get(name, 845 this.qualifiers, 846 this.converterProvider.getConverter(type), 847 (n, qs) -> defaultValue); 848 } 849 850 /** 851 * Returns a suitable value for a <a 852 * href="{@docRoot}/overview-summary.html#setting_name">setting 853 * name</a>d by the supplied {@code name} as {@linkplain 854 * Converter#convert(Value) converted} by the {@link Converter} 855 * {@linkplain ConverterProvider#getConverter(Class) located} using 856 * the supplied {@link Class}, and with default value semantics 857 * implemented by the optional supplied {@code 858 * defaultValueFunction}. 859 * 860 * @param <T> the type to which any value should be {@linkplain 861 * Converter#convert(Value) converted} 862 * 863 * @param name the name of the setting for which a value is to be 864 * returned; must not be {@code null} 865 * 866 * @param type a {@link Class} used to {@linkplain 867 * ConverterProvider#getConverter(Class) locate} an appropriate 868 * {@link Converter}; must not be {@code null} 869 * 870 * @param defaultValueFunction a {@link BiFunction} accepting a <a 871 * href="{@docRoot}/overview-summary.html#setting_name">setting 872 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 873 * returns a default {@link String}-typed value when a value could 874 * not sourced; may be {@code null} in which case if no value can be 875 * sourced a {@link NoSuchElementException} will be thrown; may 876 * return {@code null}; must be safe for concurrent use by mulitple 877 * threads; must not call any of this {@link Settings} instance's 878 * methods or undefined behavior will result 879 * 880 * @return a suitable value (possibly {@code null}) 881 * 882 * @exception NullPointerException if either {@code name} or {@code 883 * class} is {@code null} 884 * 885 * @exception IllegalArgumentException if {@linkplain 886 * Converter#convert(Value) conversion} could not occur for any 887 * reason; see {@link Converter#convert(Value)} 888 * 889 * @exception ConversionException if {@linkplain 890 * Converter#convert(Value) conversion} could not occur for any 891 * reason other than bad inputs 892 * 893 * @exception NoSuchElementException if {@code defaultValueFunction} 894 * was {@code null} and no value could be sourced 895 * 896 * @exception ValueAcquisitionException if there was a procedural 897 * problem acquiring a value 898 * 899 * @exception ArbitrationException if there was a problem performing 900 * value arbitration 901 * 902 * @exception AmbiguousValuesException if arbitration completed but 903 * could not resolve an ambiguity between potential return values 904 * 905 * @exception MalformedValuesException if the {@link 906 * #handleMalformedValues(String, Set, Collection)} method was 907 * overridden and the override throws a {@link 908 * MalformedValuesException} 909 * 910 * @exception ELException if there was an error related to 911 * expression language parsing or evaluation 912 * 913 * @exception ConcurrentModificationException if the {@link 914 * BiFunction} or {@link Iterable} supplied at {@linkplain 915 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 916 * construction time} throws one 917 * 918 * @threadsafety This method is and its overrides must be safe for 919 * concurrent use by multiple threads. 920 * 921 * @idempotency No guarantees of any kind are made with respect to 922 * the idempotency of this method or its overrides. 923 * 924 * @nullability This method may return {@code null}. 925 * 926 * @see #get(String, Set, Converter, BiFunction) 927 */ 928 public final <T> T get(final String name, 929 final Class<T> type, 930 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 931 return this.get(name, 932 this.qualifiers, 933 this.converterProvider.getConverter(type), 934 defaultValueFunction); 935 } 936 937 /** 938 * Returns a suitable value for a <a 939 * href="{@docRoot}/overview-summary.html#setting_name">setting 940 * name</a>d by the supplied {@code name} and <a 941 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 942 * with</a> the supplied {@code qualifiers}, as {@linkplain 943 * Converter#convert(Value) converted} by the {@link Converter} 944 * {@linkplain ConverterProvider#getConverter(Class) located} using 945 * the supplied {@link Class}, and with default value semantics 946 * implemented by the optional supplied {@code 947 * defaultValueFunction}. 948 * 949 * @param <T> the type to which any value should be {@linkplain 950 * Converter#convert(Value) converted} 951 * 952 * @param name the name of the setting for which a value is to be 953 * returned; must not be {@code null} 954 * 955 * @param qualifiers a {@link Set} of {@link Annotation}s to further 956 * qualify the selection of the value to be returned; may be {@code 957 * null}; if non-{@code null} then this parameter value must be safe 958 * for concurrent iteration by multiple threads 959 * 960 * @param type a {@link Class} used to {@linkplain 961 * ConverterProvider#getConverter(Class) locate} an appropriate 962 * {@link Converter}; must not be {@code null} 963 * 964 * @param defaultValue a {@link String} representation of the 965 * default value to be used in case <a 966 * href="{@docRoot}/overview-summary.html#setting_value_acquisition">setting 967 * value acquisition</a> does not yield a value; may be {@code null} 968 * 969 * @return a suitable value (possibly {@code null}) 970 * 971 * @exception NullPointerException if either {@code name} or {@code 972 * type} is {@code null} 973 * 974 * @exception IllegalArgumentException if {@linkplain 975 * Converter#convert(Value) conversion} could not occur for any 976 * reason; see {@link Converter#convert(Value)} 977 * 978 * @exception ConversionException if {@linkplain 979 * Converter#convert(Value) conversion} could not occur for any 980 * reason other than bad inputs 981 * 982 * @exception NoSuchElementException if {@code defaultValueFunction} 983 * was {@code null} and no value could be sourced 984 * 985 * @exception ValueAcquisitionException if there was a procedural 986 * problem acquiring a value 987 * 988 * @exception ArbitrationException if there was a problem performing 989 * value arbitration 990 * 991 * @exception AmbiguousValuesException if arbitration completed but 992 * could not resolve an ambiguity between potential return values 993 * 994 * @exception MalformedValuesException if the {@link 995 * #handleMalformedValues(String, Set, Collection)} method was 996 * overridden and the override throws a {@link 997 * MalformedValuesException} 998 * 999 * @exception ELException if there was an error related to 1000 * expression language parsing or evaluation 1001 * 1002 * @exception ConcurrentModificationException if the {@link 1003 * BiFunction} or {@link Iterable} supplied at {@linkplain 1004 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1005 * construction time} throws one 1006 * 1007 * @threadsafety This method is and its overrides must be safe for 1008 * concurrent use by multiple threads. 1009 * 1010 * @idempotency No guarantees of any kind are made with respect to 1011 * the idempotency of this method or its overrides. 1012 * 1013 * @nullability This method may return {@code null}. 1014 * 1015 * @see #get(String, Set, Converter, BiFunction) 1016 */ 1017 public final <T> T get(final String name, 1018 final Set<Annotation> qualifiers, 1019 final Class<T> type, 1020 final String defaultValue) { 1021 return this.get(name, 1022 qualifiers, 1023 this.converterProvider.getConverter(type), 1024 (n, qs) -> defaultValue); 1025 } 1026 1027 /** 1028 * Returns a suitable value for a <a 1029 * href="{@docRoot}/overview-summary.html#setting_name">setting 1030 * name</a>d by the supplied {@code name} and <a 1031 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 1032 * with</a> the supplied {@code qualifiers}, as {@linkplain 1033 * Converter#convert(Value) converted} by the {@link Converter} 1034 * {@linkplain ConverterProvider#getConverter(Class) located} using 1035 * the supplied {@link Class}, and with default value semantics 1036 * implemented by the optional supplied {@code 1037 * defaultValueFunction}. 1038 * 1039 * @param <T> the type to which any value should be {@linkplain 1040 * Converter#convert(Value) converted} 1041 * 1042 * @param name the name of the setting for which a value is to be 1043 * returned; must not be {@code null} 1044 * 1045 * @param qualifiers a {@link Set} of {@link Annotation}s to further 1046 * qualify the selection of the value to be returned; may be {@code 1047 * null}; if non-{@code null} then this parameter value must be safe 1048 * for concurrent iteration by multiple threads 1049 * 1050 * @param type a {@link Class} used to {@linkplain 1051 * ConverterProvider#getConverter(Class) locate} an appropriate 1052 * {@link Converter}; must not be {@code null} 1053 * 1054 * @param defaultValueFunction a {@link BiFunction} accepting a <a 1055 * href="{@docRoot}/overview-summary.html#setting_name">setting 1056 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 1057 * returns a default {@link String}-typed value when a value could 1058 * not sourced; may be {@code null} in which case if no value can be 1059 * sourced a {@link NoSuchElementException} will be thrown; may 1060 * return {@code null}; must be safe for concurrent use by mulitple 1061 * threads; must not call any of this {@link Settings} instance's 1062 * methods or undefined behavior will result 1063 * 1064 * @return a suitable value (possibly {@code null}) 1065 * 1066 * @exception NullPointerException if either {@code name} or {@code 1067 * type} is {@code null} 1068 * 1069 * @exception IllegalArgumentException if {@linkplain 1070 * Converter#convert(Value) conversion} could not occur for any 1071 * reason; see {@link Converter#convert(Value)} 1072 * 1073 * @exception ConversionException if {@linkplain 1074 * Converter#convert(Value) conversion} could not occur for any 1075 * reason other than bad inputs 1076 * 1077 * @exception NoSuchElementException if {@code defaultValueFunction} 1078 * was {@code null} and no value could be sourced 1079 * 1080 * @exception ValueAcquisitionException if there was a procedural 1081 * problem acquiring a value 1082 * 1083 * @exception ArbitrationException if there was a problem performing 1084 * value arbitration 1085 * 1086 * @exception AmbiguousValuesException if arbitration completed but 1087 * could not resolve an ambiguity between potential return values 1088 * 1089 * @exception MalformedValuesException if the {@link 1090 * #handleMalformedValues(String, Set, Collection)} method was 1091 * overridden and the override throws a {@link 1092 * MalformedValuesException} 1093 * 1094 * @exception ELException if there was an error related to 1095 * expression language parsing or evaluation 1096 * 1097 * @exception ConcurrentModificationException if the {@link 1098 * BiFunction} or {@link Iterable} supplied at {@linkplain 1099 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1100 * construction time} throws one 1101 * 1102 * @threadsafety This method is and its overrides must be safe for 1103 * concurrent use by multiple threads. 1104 * 1105 * @idempotency No guarantees of any kind are made with respect to 1106 * the idempotency of this method or its overrides. 1107 * 1108 * @nullability This method may return {@code null}. 1109 * 1110 * @see #get(String, Set, Converter, BiFunction) 1111 */ 1112 public final <T> T get(final String name, 1113 final Set<Annotation> qualifiers, 1114 final Class<T> type, 1115 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 1116 return this.get(name, 1117 qualifiers, 1118 this.converterProvider.getConverter(type), 1119 defaultValueFunction); 1120 } 1121 1122 //---------------------------------------------------------------------------- 1123 1124 /** 1125 * Returns a suitable value for a <a 1126 * href="{@docRoot}/overview-summary.html#setting_name">setting 1127 * name</a>d by the supplied {@code name} as {@linkplain 1128 * Converter#convert(Value) converted} by the {@link Converter} 1129 * {@linkplain ConverterProvider#getConverter(TypeLiteral) located} 1130 * using the supplied {@link TypeLiteral}. 1131 * 1132 * @param <T> the type to which any value should be {@linkplain 1133 * Converter#convert(Value) converted} 1134 * 1135 * @param name the name of the setting for which a value is to be 1136 * returned; must not be {@code null} 1137 * 1138 * @param typeLiteral a {@link TypeLiteral} used to {@linkplain 1139 * ConverterProvider#getConverter(TypeLiteral) locate} an 1140 * appropriate {@link Converter}; must not be {@code null} 1141 * 1142 * @return a suitable value (possibly {@code null}) 1143 * 1144 * @exception NullPointerException if either {@code name} or {@code 1145 * typeLiteral} is {@code null} 1146 * 1147 * @exception IllegalArgumentException if {@linkplain 1148 * Converter#convert(Value) conversion} could not occur for any 1149 * reason; see {@link Converter#convert(Value)} 1150 * 1151 * @exception ConversionException if {@linkplain 1152 * Converter#convert(Value) conversion} could not occur for any 1153 * reason other than bad inputs 1154 * 1155 * @exception NoSuchElementException if no value could be sourced 1156 * 1157 * @exception ValueAcquisitionException if there was a procedural 1158 * problem acquiring a value 1159 * 1160 * @exception ArbitrationException if there was a problem performing 1161 * value arbitration 1162 * 1163 * @exception AmbiguousValuesException if arbitration completed but 1164 * could not resolve an ambiguity between potential return values 1165 * 1166 * @exception MalformedValuesException if the {@link 1167 * #handleMalformedValues(String, Set, Collection)} method was 1168 * overridden and the override throws a {@link 1169 * MalformedValuesException} 1170 * 1171 * @exception ELException if there was an error related to 1172 * expression language parsing or evaluation 1173 * 1174 * @exception ConcurrentModificationException if the {@link 1175 * BiFunction} or {@link Iterable} supplied at {@linkplain 1176 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1177 * construction time} throws one 1178 * 1179 * @threadsafety This method is and its overrides must be safe for 1180 * concurrent use by multiple threads. 1181 * 1182 * @idempotency No guarantees of any kind are made with respect to 1183 * the idempotency of this method or its overrides. 1184 * 1185 * @nullability This method may return {@code null}. 1186 * 1187 * @see #get(String, Set, Converter, BiFunction) 1188 */ 1189 public final <T> T get(final String name, 1190 final TypeLiteral<T> typeLiteral) { 1191 return this.get(name, 1192 this.qualifiers, 1193 this.converterProvider.getConverter(typeLiteral), 1194 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 1195 } 1196 1197 /** 1198 * Returns a suitable value for a <a 1199 * href="{@docRoot}/overview-summary.html#setting_name">setting 1200 * name</a>d by the supplied {@code name} as {@linkplain 1201 * Converter#convert(Value) converted} by the {@link Converter} 1202 * {@linkplain ConverterProvider#getConverter(TypeLiteral) located} 1203 * using the supplied {@link TypeLiteral}, and with default value 1204 * semantics implemented by the optional supplied {@code 1205 * defaultValueFunction}. 1206 * 1207 * @param <T> the type to which any value should be {@linkplain 1208 * Converter#convert(Value) converted} 1209 * 1210 * @param name the name of the setting for which a value is to be 1211 * returned; must not be {@code null} 1212 * 1213 * @param typeLiteral a {@link TypeLiteral} used to {@linkplain 1214 * ConverterProvider#getConverter(TypeLiteral) locate} an 1215 * appropriate {@link Converter}; must not be {@code null} 1216 * 1217 * @param defaultValue a {@link String} representation of the 1218 * default value to be used in case <a 1219 * href="{@docRoot}/overview-summary.html#setting_value_acquisition">setting 1220 * value acquisition</a> does not yield a value; may be {@code null} 1221 * 1222 * @return a suitable value (possibly {@code null}) 1223 * 1224 * @exception NullPointerException if either {@code name} or {@code 1225 * typeLiteral} is {@code null} 1226 * 1227 * @exception IllegalArgumentException if {@linkplain 1228 * Converter#convert(Value) conversion} could not occur for any 1229 * reason; see {@link Converter#convert(Value)} 1230 * 1231 * @exception ConversionException if {@linkplain 1232 * Converter#convert(Value) conversion} could not occur for any 1233 * reason other than bad inputs 1234 * 1235 * @exception NoSuchElementException if {@code defaultValueFunction} 1236 * was {@code null} and no value could be sourced 1237 * 1238 * @exception ValueAcquisitionException if there was a procedural 1239 * problem acquiring a value 1240 * 1241 * @exception ArbitrationException if there was a problem performing 1242 * value arbitration 1243 * 1244 * @exception AmbiguousValuesException if arbitration completed but 1245 * could not resolve an ambiguity between potential return values 1246 * 1247 * @exception MalformedValuesException if the {@link 1248 * #handleMalformedValues(String, Set, Collection)} method was 1249 * overridden and the override throws a {@link 1250 * MalformedValuesException} 1251 * 1252 * @exception ELException if there was an error related to 1253 * expression language parsing or evaluation 1254 * 1255 * @exception ConcurrentModificationException if the {@link 1256 * BiFunction} or {@link Iterable} supplied at {@linkplain 1257 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1258 * construction time} throws one 1259 * 1260 * @threadsafety This method is and its overrides must be safe for 1261 * concurrent use by multiple threads. 1262 * 1263 * @idempotency No guarantees of any kind are made with respect to 1264 * the idempotency of this method or its overrides. 1265 * 1266 * @nullability This method may return {@code null}. 1267 * 1268 * @see #get(String, Set, Converter, BiFunction) 1269 */ 1270 public final <T> T get(final String name, 1271 final TypeLiteral<T> typeLiteral, 1272 final String defaultValue) { 1273 return this.get(name, 1274 this.qualifiers, 1275 this.converterProvider.getConverter(typeLiteral), 1276 (n, qs) -> defaultValue); 1277 } 1278 1279 /** 1280 * Returns a suitable value for a <a 1281 * href="{@docRoot}/overview-summary.html#setting_name">setting 1282 * name</a>d by the supplied {@code name} as {@linkplain 1283 * Converter#convert(Value) converted} by the {@link Converter} 1284 * {@linkplain ConverterProvider#getConverter(TypeLiteral) located} 1285 * using the supplied {@link TypeLiteral}, and with default value 1286 * semantics implemented by the optional supplied {@code 1287 * defaultValueFunction}. 1288 * 1289 * @param <T> the type to which any value should be {@linkplain 1290 * Converter#convert(Value) converted} 1291 * 1292 * @param name the name of the setting for which a value is to be 1293 * returned; must not be {@code null} 1294 * 1295 * @param typeLiteral a {@link TypeLiteral} used to {@linkplain 1296 * ConverterProvider#getConverter(TypeLiteral) locate} an 1297 * appropriate {@link Converter}; must not be {@code null} 1298 * 1299 * @param defaultValueFunction a {@link BiFunction} accepting a <a 1300 * href="{@docRoot}/overview-summary.html#setting_name">setting 1301 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 1302 * returns a default {@link String}-typed value when a value could 1303 * not sourced; may be {@code null} in which case if no value can be 1304 * sourced a {@link NoSuchElementException} will be thrown; may 1305 * return {@code null}; must be safe for concurrent use by mulitple 1306 * threads; must not call any of this {@link Settings} instance's 1307 * methods or undefined behavior will result 1308 * 1309 * @return a suitable value (possibly {@code null}) 1310 * 1311 * @exception NullPointerException if either {@code name} or {@code 1312 * typeLiteral} is {@code null} 1313 * 1314 * @exception IllegalArgumentException if {@linkplain 1315 * Converter#convert(Value) conversion} could not occur for any 1316 * reason; see {@link Converter#convert(Value)} 1317 * 1318 * @exception ConversionException if {@linkplain 1319 * Converter#convert(Value) conversion} could not occur for any 1320 * reason other than bad inputs 1321 * 1322 * @exception NoSuchElementException if {@code defaultValueFunction} 1323 * was {@code null} and no value could be sourced 1324 * 1325 * @exception ValueAcquisitionException if there was a procedural 1326 * problem acquiring a value 1327 * 1328 * @exception ArbitrationException if there was a problem performing 1329 * value arbitration 1330 * 1331 * @exception AmbiguousValuesException if arbitration completed but 1332 * could not resolve an ambiguity between potential return values 1333 * 1334 * @exception MalformedValuesException if the {@link 1335 * #handleMalformedValues(String, Set, Collection)} method was 1336 * overridden and the override throws a {@link 1337 * MalformedValuesException} 1338 * 1339 * @exception ELException if there was an error related to 1340 * expression language parsing or evaluation 1341 * 1342 * @exception ConcurrentModificationException if the {@link 1343 * BiFunction} or {@link Iterable} supplied at {@linkplain 1344 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1345 * construction time} throws one 1346 * 1347 * @threadsafety This method is and its overrides must be safe for 1348 * concurrent use by multiple threads. 1349 * 1350 * @idempotency No guarantees of any kind are made with respect to 1351 * the idempotency of this method or its overrides. 1352 * 1353 * @nullability This method may return {@code null}. 1354 * 1355 * @see #get(String, Set, Converter, BiFunction) 1356 */ 1357 public final <T> T get(final String name, 1358 final TypeLiteral<T> typeLiteral, 1359 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 1360 return this.get(name, 1361 this.qualifiers, 1362 this.converterProvider.getConverter(typeLiteral), 1363 defaultValueFunction); 1364 } 1365 1366 /** 1367 * Returns a suitable value for a <a 1368 * href="{@docRoot}/overview-summary.html#setting_name">setting 1369 * name</a>d by the supplied {@code name} and <a 1370 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 1371 * with</a> the supplied {@code qualifiers}, as {@linkplain 1372 * Converter#convert(Value) converted} by the {@link Converter} 1373 * {@linkplain ConverterProvider#getConverter(TypeLiteral) located} 1374 * using the supplied {@link TypeLiteral}, and with default value 1375 * semantics implemented by the optional supplied {@code 1376 * defaultValueFunction}. 1377 * 1378 * @param <T> the type to which any value should be {@linkplain 1379 * Converter#convert(Value) converted} 1380 * 1381 * @param name the name of the setting for which a value is to be 1382 * returned; must not be {@code null} 1383 * 1384 * @param qualifiers a {@link Set} of {@link Annotation}s to further 1385 * qualify the selection of the value to be returned; may be {@code 1386 * null}; if non-{@code null} then this parameter value must be safe 1387 * for concurrent iteration by multiple threads 1388 * 1389 * @param typeLiteral a {@link TypeLiteral} used to {@linkplain 1390 * ConverterProvider#getConverter(TypeLiteral) locate} an 1391 * appropriate {@link Converter}; must not be {@code null} 1392 * 1393 * @param defaultValueFunction a {@link BiFunction} accepting a <a 1394 * href="{@docRoot}/overview-summary.html#setting_name">setting 1395 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 1396 * returns a default {@link String}-typed value when a value could 1397 * not sourced; may be {@code null} in which case if no value can be 1398 * sourced a {@link NoSuchElementException} will be thrown; may 1399 * return {@code null}; must be safe for concurrent use by mulitple 1400 * threads; must not call any of this {@link Settings} instance's 1401 * methods or undefined behavior will result 1402 * 1403 * @return a suitable value (possibly {@code null}) 1404 * 1405 * @exception NullPointerException if either {@code name} or {@code 1406 * typeLiteral} is {@code null} 1407 * 1408 * @exception IllegalArgumentException if {@linkplain 1409 * Converter#convert(Value) conversion} could not occur for any 1410 * reason; see {@link Converter#convert(Value)} 1411 * 1412 * @exception ConversionException if {@linkplain 1413 * Converter#convert(Value) conversion} could not occur for any 1414 * reason other than bad inputs 1415 * 1416 * @exception NoSuchElementException if {@code defaultValueFunction} 1417 * was {@code null} and no value could be sourced 1418 * 1419 * @exception ValueAcquisitionException if there was a procedural 1420 * problem acquiring a value 1421 * 1422 * @exception ArbitrationException if there was a problem performing 1423 * value arbitration 1424 * 1425 * @exception AmbiguousValuesException if arbitration completed but 1426 * could not resolve an ambiguity between potential return values 1427 * 1428 * @exception MalformedValuesException if the {@link 1429 * #handleMalformedValues(String, Set, Collection)} method was 1430 * overridden and the override throws a {@link 1431 * MalformedValuesException} 1432 * 1433 * @exception ELException if there was an error related to 1434 * expression language parsing or evaluation 1435 * 1436 * @exception ConcurrentModificationException if the {@link 1437 * BiFunction} or {@link Iterable} supplied at {@linkplain 1438 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1439 * construction time} throws one 1440 * 1441 * @threadsafety This method is and its overrides must be safe for 1442 * concurrent use by multiple threads. 1443 * 1444 * @idempotency No guarantees of any kind are made with respect to 1445 * the idempotency of this method or its overrides. 1446 * 1447 * @nullability This method may return {@code null}. 1448 * 1449 * @see #get(String, Set, Converter, BiFunction) 1450 */ 1451 public final <T> T get(final String name, 1452 final Set<Annotation> qualifiers, 1453 final TypeLiteral<T> typeLiteral, 1454 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 1455 return this.get(name, 1456 qualifiers, 1457 this.converterProvider.getConverter(typeLiteral), 1458 defaultValueFunction); 1459 } 1460 1461 //---------------------------------------------------------------------------- 1462 1463 /** 1464 * Returns a suitable value for a <a 1465 * href="{@docRoot}/overview-summary.html#setting_name">setting 1466 * name</a>d by the supplied {@code name} as {@linkplain 1467 * Converter#convert(Value) converted} by the {@link Converter} 1468 * {@linkplain ConverterProvider#getConverter(Type) located} using 1469 * the supplied {@link Type}. 1470 * 1471 * @param name the name of the setting for which a value is to be 1472 * returned; must not be {@code null} 1473 * 1474 * @param type a {@link Type} used to {@linkplain 1475 * ConverterProvider#getConverter(Type) locate} an appropriate 1476 * {@link Converter}; must not be {@code null} 1477 * 1478 * @return a suitable value (possibly {@code null}) 1479 * 1480 * @exception NullPointerException if either {@code name} or {@code 1481 * type} is {@code null} 1482 * 1483 * @exception IllegalArgumentException if {@linkplain 1484 * Converter#convert(Value) conversion} could not occur for any 1485 * reason; see {@link Converter#convert(Value)} 1486 * 1487 * @exception ConversionException if {@linkplain 1488 * Converter#convert(Value) conversion} could not occur for any 1489 * reason other than bad inputs 1490 * 1491 * @exception NoSuchElementException if no value could be sourced 1492 * 1493 * @exception ValueAcquisitionException if there was a procedural 1494 * problem acquiring a value 1495 * 1496 * @exception ArbitrationException if there was a problem performing 1497 * value arbitration 1498 * 1499 * @exception AmbiguousValuesException if arbitration completed but 1500 * could not resolve an ambiguity between potential return values 1501 * 1502 * @exception MalformedValuesException if the {@link 1503 * #handleMalformedValues(String, Set, Collection)} method was 1504 * overridden and the override throws a {@link 1505 * MalformedValuesException} 1506 * 1507 * @exception ELException if there was an error related to 1508 * expression language parsing or evaluation 1509 * 1510 * @exception ConcurrentModificationException if the {@link 1511 * BiFunction} or {@link Iterable} supplied at {@linkplain 1512 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1513 * construction time} throws one 1514 * 1515 * @threadsafety This method is and its overrides must be safe for 1516 * concurrent use by multiple threads. 1517 * 1518 * @idempotency No guarantees of any kind are made with respect to 1519 * the idempotency of this method or its overrides. 1520 * 1521 * @nullability This method may return {@code null}. 1522 * 1523 * @see #get(String, Set, Converter, BiFunction) 1524 */ 1525 public final Object get(final String name, 1526 final Type type) { 1527 return this.get(name, 1528 this.qualifiers, 1529 this.converterProvider.getConverter(type), 1530 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 1531 } 1532 1533 /** 1534 * Returns a suitable value for a <a 1535 * href="{@docRoot}/overview-summary.html#setting_name">setting 1536 * name</a>d by the supplied {@code name} and <a 1537 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 1538 * with</a> the supplied {@code qualifiers}, as {@linkplain 1539 * Converter#convert(Value) converted} by the {@link Converter} 1540 * {@linkplain ConverterProvider#getConverter(Type) located} using 1541 * the supplied {@link Type}. 1542 * 1543 * @param name the name of the setting for which a value is to be 1544 * returned; must not be {@code null} 1545 * 1546 * @param qualifiers a {@link Set} of {@link Annotation}s to further 1547 * qualify the selection of the value to be returned; may be {@code 1548 * null}; if non-{@code null} then this parameter value must be safe 1549 * for concurrent iteration by multiple threads 1550 * 1551 * @param type a {@link Type} used to {@linkplain 1552 * ConverterProvider#getConverter(Type) locate} an appropriate 1553 * {@link Converter}; must not be {@code null} 1554 * 1555 * @return a suitable value (possibly {@code null}) 1556 * 1557 * @exception NullPointerException if either {@code name} or {@code 1558 * type} is {@code null} 1559 * 1560 * @exception IllegalArgumentException if {@linkplain 1561 * Converter#convert(Value) conversion} could not occur for any 1562 * reason; see {@link Converter#convert(Value)} 1563 * 1564 * @exception ConversionException if {@linkplain 1565 * Converter#convert(Value) conversion} could not occur for any reason 1566 * other than bad inputs 1567 * 1568 * @exception NoSuchElementException if no value could be sourced 1569 * 1570 * @exception ValueAcquisitionException if there was a procedural 1571 * problem acquiring a value 1572 * 1573 * @exception ArbitrationException if there was a problem performing 1574 * value arbitration 1575 * 1576 * @exception AmbiguousValuesException if arbitration completed but 1577 * could not resolve an ambiguity between potential return values 1578 * 1579 * @exception MalformedValuesException if the {@link 1580 * #handleMalformedValues(String, Set, Collection)} method was 1581 * overridden and the override throws a {@link 1582 * MalformedValuesException} 1583 * 1584 * @exception ELException if there was an error related to 1585 * expression language parsing or evaluation 1586 * 1587 * @exception ConcurrentModificationException if the {@link 1588 * BiFunction} or {@link Iterable} supplied at {@linkplain 1589 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1590 * construction time} throws one 1591 * 1592 * @threadsafety This method is and its overrides must be safe for 1593 * concurrent use by multiple threads. 1594 * 1595 * @idempotency No guarantees of any kind are made with respect to 1596 * the idempotency of this method or its overrides. 1597 * 1598 * @nullability This method may return {@code null}. 1599 * 1600 * @see #get(String, Set, Converter, BiFunction) 1601 */ 1602 public final Object get(final String name, 1603 final Set<Annotation> qualifiers, 1604 final Type type) { 1605 return this.get(name, 1606 qualifiers, 1607 this.converterProvider.getConverter(type), 1608 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 1609 } 1610 1611 /** 1612 * Returns a suitable value for a <a 1613 * href="{@docRoot}/overview-summary.html#setting_name">setting 1614 * name</a>d by the supplied {@code name} as {@linkplain 1615 * Converter#convert(Value) converted} by the {@link Converter} 1616 * {@linkplain ConverterProvider#getConverter(Type) located} using 1617 * the supplied {@link Type}, and with default value semantics 1618 * implemented by the optional supplied {@code 1619 * defaultValueFunction}. 1620 * 1621 * @param name the name of the setting for which a value is to be 1622 * returned; must not be {@code null} 1623 * 1624 * @param type a {@link Type} used to {@linkplain 1625 * ConverterProvider#getConverter(Type) locate} an appropriate 1626 * {@link Converter}; must not be {@code null} 1627 * 1628 * @param defaultValueFunction a {@link BiFunction} accepting a <a 1629 * href="{@docRoot}/overview-summary.html#setting_name">setting 1630 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 1631 * returns a default {@link String}-typed value when a value could 1632 * not sourced; may be {@code null} in which case if no value can be 1633 * sourced a {@link NoSuchElementException} will be thrown; may 1634 * return {@code null}; must be safe for concurrent use by mulitple 1635 * threads; must not call any of this {@link Settings} instance's 1636 * methods or undefined behavior will result 1637 * 1638 * @return a suitable value (possibly {@code null}) 1639 * 1640 * @exception NullPointerException if either {@code name} or {@code 1641 * type} is {@code null} 1642 * 1643 * @exception IllegalArgumentException if {@linkplain 1644 * Converter#convert(Value) conversion} could not occur for any 1645 * reason; see {@link Converter#convert(Value)} 1646 * 1647 * @exception ConversionException if {@linkplain 1648 * Converter#convert(Value) conversion} could not occur for any reason 1649 * other than bad inputs 1650 * 1651 * @exception NoSuchElementException if {@code defaultValueFunction} 1652 * was {@code null} and no value could be sourced 1653 * 1654 * @exception ValueAcquisitionException if there was a procedural 1655 * problem acquiring a value 1656 * 1657 * @exception ArbitrationException if there was a problem performing 1658 * value arbitration 1659 * 1660 * @exception AmbiguousValuesException if arbitration completed but 1661 * could not resolve an ambiguity between potential return values 1662 * 1663 * @exception MalformedValuesException if the {@link 1664 * #handleMalformedValues(String, Set, Collection)} method was 1665 * overridden and the override throws a {@link 1666 * MalformedValuesException} 1667 * 1668 * @exception ELException if there was an error related to 1669 * expression language parsing or evaluation 1670 * 1671 * @exception ConcurrentModificationException if the {@link 1672 * BiFunction} or {@link Iterable} supplied at {@linkplain 1673 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1674 * construction time} throws one 1675 * 1676 * @threadsafety This method is and its overrides must be safe for 1677 * concurrent use by multiple threads. 1678 * 1679 * @idempotency No guarantees of any kind are made with respect to 1680 * the idempotency of this method or its overrides. 1681 * 1682 * @nullability This method may return {@code null}. 1683 * 1684 * @see #get(String, Set, Converter, BiFunction) 1685 */ 1686 public final Object get(final String name, 1687 final Type type, 1688 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 1689 return this.get(name, 1690 this.qualifiers, 1691 this.converterProvider.getConverter(type), 1692 defaultValueFunction); 1693 } 1694 1695 /** 1696 * Returns a suitable value for a <a 1697 * href="{@docRoot}/overview-summary.html#setting_name">setting 1698 * name</a>d by the supplied {@code name} and <a 1699 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 1700 * with</a> the supplied {@code qualifiers}, as {@linkplain 1701 * Converter#convert(Value) converted} by the {@link Converter} 1702 * {@linkplain ConverterProvider#getConverter(Type) located} using 1703 * the supplied {@link Type}, and with default value semantics 1704 * implemented by the optional supplied {@code 1705 * defaultValueFunction}. 1706 * 1707 * @param name the name of the setting for which a value is to be 1708 * returned; must not be {@code null} 1709 * 1710 * @param qualifiers a {@link Set} of {@link Annotation}s to further 1711 * qualify the selection of the value to be returned; may be {@code 1712 * null}; if non-{@code null} then this parameter value must be safe 1713 * for concurrent iteration by multiple threads 1714 * 1715 * @param type a {@link Type} used to {@linkplain 1716 * ConverterProvider#getConverter(Type) locate} an appropriate 1717 * {@link Converter}; must not be {@code null} 1718 * 1719 * @param defaultValueFunction a {@link BiFunction} accepting a <a 1720 * href="{@docRoot}/overview-summary.html#setting_name">setting 1721 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 1722 * returns a default {@link String}-typed value when a value could 1723 * not sourced; may be {@code null} in which case if no value can be 1724 * sourced a {@link NoSuchElementException} will be thrown; may 1725 * return {@code null}; must be safe for concurrent use by mulitple 1726 * threads; must not call any of this {@link Settings} instance's 1727 * methods or undefined behavior will result 1728 * 1729 * @return a suitable value (possibly {@code null}) 1730 * 1731 * @exception NullPointerException if either {@code name} or {@code 1732 * type} is {@code null} 1733 * 1734 * @exception IllegalArgumentException if {@linkplain 1735 * Converter#convert(Value) conversion} could not occur for any 1736 * reason; see {@link Converter#convert(Value)} 1737 * 1738 * @exception ConversionException if {@linkplain 1739 * Converter#convert(Value) conversion} could not occur for any reason 1740 * other than bad inputs 1741 * 1742 * @exception NoSuchElementException if {@code defaultValueFunction} 1743 * was {@code null} and no value could be sourced 1744 * 1745 * @exception ValueAcquisitionException if there was a procedural 1746 * problem acquiring a value 1747 * 1748 * @exception ArbitrationException if there was a problem performing 1749 * value arbitration 1750 * 1751 * @exception AmbiguousValuesException if arbitration completed but 1752 * could not resolve an ambiguity between potential return values 1753 * 1754 * @exception MalformedValuesException if the {@link 1755 * #handleMalformedValues(String, Set, Collection)} method was 1756 * overridden and the override throws a {@link 1757 * MalformedValuesException} 1758 * 1759 * @exception ELException if there was an error related to 1760 * expression language parsing or evaluation 1761 * 1762 * @exception ConcurrentModificationException if the {@link 1763 * BiFunction} or {@link Iterable} supplied at {@linkplain 1764 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1765 * construction time} throws one 1766 * 1767 * @threadsafety This method is and its overrides must be safe for 1768 * concurrent use by multiple threads. 1769 * 1770 * @idempotency No guarantees of any kind are made with respect to 1771 * the idempotency of this method or its overrides. 1772 * 1773 * @nullability This method may return {@code null}. 1774 * 1775 * @see #get(String, Set, Converter, BiFunction) 1776 */ 1777 public final Object get(final String name, 1778 final Set<Annotation> qualifiers, 1779 final Type type, 1780 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 1781 return this.get(name, 1782 qualifiers, 1783 this.converterProvider.getConverter(type), 1784 defaultValueFunction); 1785 } 1786 1787 //---------------------------------------------------------------------------- 1788 1789 /** 1790 * Returns a suitable value for a <a 1791 * href="{@docRoot}/overview-summary.html#setting_name">setting 1792 * name</a>d by the supplied {@code name} as {@linkplain 1793 * Converter#convert(Value) converted} by the supplied {@link 1794 * Converter}. 1795 * 1796 * @param <T> the type to which any value should be {@linkplain 1797 * Converter#convert(Value) converted} 1798 * 1799 * @param name the name of the setting for which a value is to be 1800 * returned; must not be {@code null} 1801 * 1802 * @param converter a {@link Converter} used to {@linkplain 1803 * Converter#convert(Value) convert} a {@link String} value into a 1804 * <a href="{@docRoot}/overview-summary.html#setting_value">setting 1805 * value</a> of the appropriate type; must not be {@code null}; must 1806 * either be safe for concurrent use by multiple threads or created 1807 * specially for this method invocation or supplied in a context 1808 * where it is known that only one thread is executing at a time 1809 * 1810 * @return a suitable value (possibly {@code null}) 1811 * 1812 * @exception NullPointerException if either {@code name} or {@code 1813 * converter} is {@code null} 1814 * 1815 * @exception IllegalArgumentException if {@linkplain 1816 * Converter#convert(Value) conversion} could not occur for any 1817 * reason; see {@link Converter#convert(Value)} 1818 * 1819 * @exception ConversionException if {@linkplain 1820 * Converter#convert(Value) conversion} could not occur for any reason 1821 * other than bad inputs 1822 * 1823 * @exception NoSuchElementException if no value could be sourced 1824 * 1825 * @exception ValueAcquisitionException if there was a procedural 1826 * problem acquiring a value 1827 * 1828 * @exception ArbitrationException if there was a problem performing 1829 * value arbitration 1830 * 1831 * @exception AmbiguousValuesException if arbitration completed but 1832 * could not resolve an ambiguity between potential return values 1833 * 1834 * @exception MalformedValuesException if the {@link 1835 * #handleMalformedValues(String, Set, Collection)} method was 1836 * overridden and the override throws a {@link 1837 * MalformedValuesException} 1838 * 1839 * @exception ELException if there was an error related to 1840 * expression language parsing or evaluation 1841 * 1842 * @exception ConcurrentModificationException if the {@link 1843 * BiFunction} or {@link Iterable} supplied at {@linkplain 1844 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1845 * construction time} throws one 1846 * 1847 * @threadsafety This method is safe for concurrent use by multiple 1848 * threads. 1849 * 1850 * @idempotency No guarantees of any kind are made with respect to 1851 * the idempotency of this method. 1852 * 1853 * @nullability This method may return {@code null}. 1854 * 1855 * @see #get(String, Set, Converter, BiFunction) 1856 */ 1857 public final <T> T get(final String name, 1858 final Converter<? extends T> converter) { 1859 return this.get(name, 1860 this.qualifiers, 1861 converter, 1862 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 1863 } 1864 1865 /** 1866 * Returns a suitable value for a <a 1867 * href="{@docRoot}/overview-summary.html#setting_name">setting 1868 * name</a>d by the supplied {@code name} and <a 1869 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 1870 * with</a> the supplied {@code qualifiers}, as {@linkplain 1871 * Converter#convert(Value) converted} by the supplied {@link 1872 * Converter}. 1873 * 1874 * @param <T> the type to which any value should be {@linkplain 1875 * Converter#convert(Value) converted} 1876 * 1877 * @param name the name of the setting for which a value is to be 1878 * returned; must not be {@code null} 1879 * 1880 * @param qualifiers a {@link Set} of {@link Annotation}s to further 1881 * qualify the selection of the value to be returned; may be {@code 1882 * null}; if non-{@code null} then this parameter value must be safe 1883 * for concurrent iteration by multiple threads 1884 * 1885 * @param converter a {@link Converter} used to {@linkplain 1886 * Converter#convert(Value) convert} a {@link String} value into a 1887 * <a href="{@docRoot}/overview-summary.html#setting_value">setting 1888 * value</a> of the appropriate type; must not be {@code null}; must 1889 * either be safe for concurrent use by multiple threads or created 1890 * specially for this method invocation or supplied in a context 1891 * where it is known that only one thread is executing at a time 1892 * 1893 * @return a suitable value (possibly {@code null}) 1894 * 1895 * @exception NullPointerException if either {@code name} or {@code 1896 * converter} is {@code null} 1897 * 1898 * @exception IllegalArgumentException if {@linkplain 1899 * Converter#convert(Value) conversion} could not occur for any 1900 * reason; see {@link Converter#convert(Value)} 1901 * 1902 * @exception ConversionException if {@linkplain 1903 * Converter#convert(Value) conversion} could not occur for any reason 1904 * other than bad inputs 1905 * 1906 * @exception NoSuchElementException if no value could be sourced 1907 * 1908 * @exception ValueAcquisitionException if there was a procedural 1909 * problem acquiring a value 1910 * 1911 * @exception ArbitrationException if there was a problem performing 1912 * value arbitration 1913 * 1914 * @exception AmbiguousValuesException if arbitration completed but 1915 * could not resolve an ambiguity between potential return values 1916 * 1917 * @exception MalformedValuesException if the {@link 1918 * #handleMalformedValues(String, Set, Collection)} method was 1919 * overridden and the override throws a {@link 1920 * MalformedValuesException} 1921 * 1922 * @exception ELException if there was an error related to 1923 * expression language parsing or evaluation 1924 * 1925 * @exception ConcurrentModificationException if the {@link 1926 * BiFunction} or {@link Iterable} supplied at {@linkplain 1927 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 1928 * construction time} throws one 1929 * 1930 * @threadsafety This method is safe for concurrent use by multiple 1931 * threads. 1932 * 1933 * @idempotency No guarantees of any kind are made with respect to 1934 * the idempotency of this method. 1935 * 1936 * @nullability This method may return {@code null}. 1937 * 1938 * @see #get(String, Set, Converter, BiFunction) 1939 */ 1940 public final <T> T get(final String name, 1941 final Set<Annotation> qualifiers, 1942 final Converter<? extends T> converter) { 1943 return this.get(name, 1944 qualifiers, 1945 converter, 1946 (BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String>)null); 1947 } 1948 1949 /** 1950 * Returns a suitable value for a <a 1951 * href="{@docRoot}/overview-summary.html#setting_name">setting 1952 * name</a>d by the supplied {@code name} as {@linkplain 1953 * Converter#convert(Value) converted} by the supplied {@link 1954 * Converter} and with default value semantics implemented by the 1955 * optional supplied {@code defaultValueFunction}. 1956 * 1957 * @param <T> the type to which any value should be {@linkplain 1958 * Converter#convert(Value) converted} 1959 * 1960 * @param name the name of the setting for which a value is to be 1961 * returned; must not be {@code null} 1962 * 1963 * @param converter a {@link Converter} used to {@linkplain 1964 * Converter#convert(Value) convert} a {@link String} value into a 1965 * <a href="{@docRoot}/overview-summary.html#setting_value">setting 1966 * value</a> of the appropriate type; must not be {@code null}; must 1967 * either be safe for concurrent use by multiple threads or created 1968 * specially for this method invocation or supplied in a context 1969 * where it is known that only one thread is executing at a time 1970 * 1971 * @param defaultValueFunction a {@link BiFunction} accepting a <a 1972 * href="{@docRoot}/overview-summary.html#setting_name">setting 1973 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 1974 * returns a default {@link String}-typed value when a value could 1975 * not sourced; may be {@code null} in which case if no value can be 1976 * sourced a {@link NoSuchElementException} will be thrown; may 1977 * return {@code null}; must be safe for concurrent use by mulitple 1978 * threads; must not call any of this {@link Settings} instance's 1979 * methods or undefined behavior will result 1980 * 1981 * @return a suitable value (possibly {@code null}) 1982 * 1983 * @exception NullPointerException if either {@code name} or {@code 1984 * converter} is {@code null} 1985 * 1986 * @exception IllegalArgumentException if {@linkplain 1987 * Converter#convert(Value) conversion} could not occur for any 1988 * reason; see {@link Converter#convert(Value)} 1989 * 1990 * @exception ConversionException if {@linkplain 1991 * Converter#convert(Value) conversion} could not occur for any reason 1992 * other than bad inputs 1993 * 1994 * @exception NoSuchElementException if {@code defaultValueFunction} 1995 * was {@code null} and no value could be sourced 1996 * 1997 * @exception ValueAcquisitionException if there was a procedural 1998 * problem acquiring a value 1999 * 2000 * @exception ArbitrationException if there was a problem performing 2001 * value arbitration 2002 * 2003 * @exception AmbiguousValuesException if arbitration completed but 2004 * could not resolve an ambiguity between potential return values 2005 * 2006 * @exception MalformedValuesException if the {@link 2007 * #handleMalformedValues(String, Set, Collection)} method was 2008 * overridden and the override throws a {@link 2009 * MalformedValuesException} 2010 * 2011 * @exception ELException if there was an error related to 2012 * expression language parsing or evaluation 2013 * 2014 * @exception ConcurrentModificationException if the {@link 2015 * BiFunction} or {@link Iterable} supplied at {@linkplain 2016 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 2017 * construction time} throws one 2018 * 2019 * @threadsafety This method is safe for concurrent use by multiple 2020 * threads. 2021 * 2022 * @idempotency No guarantees of any kind are made with respect to 2023 * the idempotency of this method. 2024 * 2025 * @nullability This method may return {@code null}. 2026 * 2027 * @see #get(String, Set, Converter, BiFunction) 2028 */ 2029 public final <T> T get(final String name, 2030 final Converter<? extends T> converter, 2031 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 2032 return this.get(name, 2033 this.qualifiers, 2034 converter, 2035 defaultValueFunction); 2036 } 2037 2038 /** 2039 * Returns a suitable value for a <a 2040 * href="{@docRoot}/overview-summary.html#setting_name">setting 2041 * name</a>d by the supplied {@code name} and <a 2042 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 2043 * with</a> the supplied {@code qualifiers}, as {@linkplain 2044 * Converter#convert(Value) converted} by the supplied {@link 2045 * Converter} and with default value semantics implemented by the 2046 * optional supplied {@code defaultValueFunction}. 2047 * 2048 * @param <T> the type to which any value should be {@linkplain 2049 * Converter#convert(Value) converted} 2050 * 2051 * @param name the name of the setting for which a value is to be 2052 * returned; must not be {@code null} 2053 * 2054 * @param qualifiers a {@link Set} of {@link Annotation}s to further 2055 * qualify the selection of the value to be returned; may be {@code 2056 * null}; if non-{@code null} then this parameter value must be safe 2057 * for concurrent iteration by multiple threads 2058 * 2059 * @param converter a {@link Converter} used to {@linkplain 2060 * Converter#convert(Value) convert} a {@link String} value into a 2061 * <a href="{@docRoot}/overview-summary.html#setting_value">setting 2062 * value</a> of the appropriate type; must not be {@code null}; must 2063 * either be safe for concurrent use by multiple threads or created 2064 * specially for this method invocation or supplied in a context 2065 * where it is known that only one thread is executing at a time 2066 * 2067 * @param defaultValue a {@link String} representation of the 2068 * default value to be used in case <a 2069 * href="{@docRoot}/overview-summary.html#setting_value_acquisition">setting 2070 * value acquisition</a> does not yield a value; may be {@code null} 2071 * 2072 * @return a suitable value (possibly {@code null}) 2073 * 2074 * @exception NullPointerException if either {@code name} or {@code 2075 * converter} is {@code null} 2076 * 2077 * @exception IllegalArgumentException if {@linkplain 2078 * Converter#convert(Value) conversion} could not occur for any 2079 * reason; see {@link Converter#convert(Value)} 2080 * 2081 * @exception ConversionException if {@linkplain 2082 * Converter#convert(Value) conversion} could not occur for any reason 2083 * other than bad inputs 2084 * 2085 * @exception NoSuchElementException if {@code defaultValueFunction} 2086 * was {@code null} and no value could be sourced 2087 * 2088 * @exception ValueAcquisitionException if there was a procedural 2089 * problem acquiring a value 2090 * 2091 * @exception ArbitrationException if there was a problem performing 2092 * value arbitration 2093 * 2094 * @exception AmbiguousValuesException if arbitration completed but 2095 * could not resolve an ambiguity between potential return values 2096 * 2097 * @exception MalformedValuesException if the {@link 2098 * #handleMalformedValues(String, Set, Collection)} method was 2099 * overridden and the override throws a {@link 2100 * MalformedValuesException} 2101 * 2102 * @exception ELException if there was an error related to 2103 * expression language parsing or evaluation 2104 * 2105 * @exception ConcurrentModificationException if the {@link 2106 * BiFunction} or {@link Iterable} supplied at {@linkplain 2107 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 2108 * construction time} throws one 2109 * 2110 * @threadsafety This method is safe for concurrent use by multiple 2111 * threads. 2112 * 2113 * @idempotency No guarantees of any kind are made with respect to 2114 * the idempotency of this method. 2115 * 2116 * @nullability This method may return {@code null}. 2117 */ 2118 public final <T> T get(final String name, 2119 final Set<Annotation> qualifiers, 2120 final Converter<? extends T> converter, 2121 final String defaultValue) { 2122 return this.get(name, qualifiers, converter, (n, qs) -> defaultValue); 2123 } 2124 2125 /** 2126 * Returns a suitable value for a <a 2127 * href="{@docRoot}/overview-summary.html#setting_name">setting 2128 * name</a>d by the supplied {@code name} and <a 2129 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 2130 * with</a> the supplied {@code qualifiers}, as {@linkplain 2131 * Converter#convert(Value) converted} by the supplied {@link 2132 * Converter} and with default value semantics implemented by the 2133 * optional supplied {@code defaultValueFunction}. 2134 * 2135 * @param <T> the type to which any value should be {@linkplain 2136 * Converter#convert(Value) converted} 2137 * 2138 * @param name the name of the setting for which a value is to be 2139 * returned; must not be {@code null} 2140 * 2141 * @param qualifiers a {@link Set} of {@link Annotation}s to further 2142 * qualify the selection of the value to be returned; may be {@code 2143 * null}; if non-{@code null} then this parameter value must be safe 2144 * for concurrent iteration by multiple threads 2145 * 2146 * @param converter a {@link Converter} used to {@linkplain 2147 * Converter#convert(Value) convert} a {@link String} value into a 2148 * <a href="{@docRoot}/overview-summary.html#setting_value">setting 2149 * value</a> of the appropriate type; must not be {@code null}; must 2150 * either be safe for concurrent use by multiple threads or created 2151 * specially for this method invocation or supplied in a context 2152 * where it is known that only one thread is executing at a time 2153 * 2154 * @param defaultValueFunction a {@link BiFunction} accepting a <a 2155 * href="{@docRoot}/overview-summary.html#setting_name">setting 2156 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 2157 * returns a default {@link String}-typed value when a value could 2158 * not sourced; may be {@code null} in which case if no value can be 2159 * sourced a {@link NoSuchElementException} will be thrown; may 2160 * return {@code null}; must be safe for concurrent use by mulitple 2161 * threads; must not call any of this {@link Settings} instance's 2162 * methods or undefined behavior will result 2163 * 2164 * @return a suitable value (possibly {@code null}) 2165 * 2166 * @exception NullPointerException if either {@code name} or {@code 2167 * converter} is {@code null} 2168 * 2169 * @exception IllegalArgumentException if {@linkplain 2170 * Converter#convert(Value) conversion} could not occur for any 2171 * reason; see {@link Converter#convert(Value)} 2172 * 2173 * @exception ConversionException if {@linkplain 2174 * Converter#convert(Value) conversion} could not occur for any reason 2175 * other than bad inputs 2176 * 2177 * @exception NoSuchElementException if {@code defaultValueFunction} 2178 * was {@code null} and no value could be sourced 2179 * 2180 * @exception ValueAcquisitionException if there was a procedural 2181 * problem acquiring a value 2182 * 2183 * @exception ArbitrationException if there was a problem performing 2184 * value arbitration 2185 * 2186 * @exception AmbiguousValuesException if arbitration completed but 2187 * could not resolve an ambiguity between potential return values 2188 * 2189 * @exception MalformedValuesException if the {@link 2190 * #handleMalformedValues(String, Set, Collection)} method was 2191 * overridden and the override throws a {@link 2192 * MalformedValuesException} 2193 * 2194 * @exception ELException if there was an error related to 2195 * expression language parsing or evaluation 2196 * 2197 * @exception ConcurrentModificationException if the {@link 2198 * BiFunction} or {@link Iterable} supplied at {@linkplain 2199 * #Settings(Set, BiFunction, ConverterProvider, Iterable) 2200 * construction time} throws one 2201 * 2202 * @threadsafety This method is safe for concurrent use by multiple 2203 * threads. 2204 * 2205 * @idempotency No guarantees of any kind are made with respect to 2206 * the idempotency of this method. 2207 * 2208 * @nullability This method may return {@code null}. 2209 */ 2210 public final <T> T get(final String name, 2211 final Set<Annotation> qualifiers, 2212 final Converter<? extends T> converter, 2213 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 2214 Objects.requireNonNull(name); 2215 Objects.requireNonNull(converter); 2216 final ExpressionFactory expressionFactory = ExpressionFactory.newInstance(); 2217 final StandardELContext elContext = new StandardELContext(expressionFactory); 2218 elContext.addELResolver(new SourceELResolver(this, expressionFactory, qualifiers)); 2219 return this.get(name, 2220 qualifiers, 2221 elContext, 2222 expressionFactory, 2223 converter, 2224 defaultValueFunction); 2225 } 2226 2227 //---------------------------------------------------------------------------- 2228 2229 /** 2230 * Returns a suitable value for a <a 2231 * href="{@docRoot}/overview-summary.html#setting_name">setting 2232 * name</a>d by the supplied {@code name} and <a 2233 * href="{@docRoot}/overview-summary.html#qualifiers">qualified 2234 * with</a> the supplied {@code qualifiers}, as {@linkplain 2235 * Converter#convert(Value) converted} by the supplied {@link 2236 * Converter} and with default value semantics implemented by the 2237 * optional supplied {@code defaultValueFunction}. 2238 * 2239 * @param name the name of the setting for which a value is to be 2240 * returned; must not be {@code null} 2241 * 2242 * @param qualifiers a {@link Set} of {@link Annotation}s to further 2243 * qualify the selection of the value to be returned; may be {@code 2244 * null}; if non-{@code null} then this parameter value must be safe 2245 * for concurrent iteration by multiple threads 2246 * 2247 * @param elContext an {@link ELContext}; must not be {@code null}; 2248 * must either be safe for concurrent use by multiple threads 2249 * (highly unlikely) or created specially for this method invocation 2250 * or supplied in a context where it is known that only one thread 2251 * is executing at a time 2252 * 2253 * @param expressionFactory an {@link ExpressionFactory} used to 2254 * {@linkplain ExpressionFactory#createValueExpression(ELContext, 2255 * String, Class) create <code>ValueExpression</code>}s; must not be 2256 * {@code null}; must either be safe for concurrent use by multiple 2257 * threads (highly unlikely) or created specially for this method 2258 * invocation or supplied in a context where it is known that only 2259 * one thread is executing at a time 2260 * 2261 * @param converter a {@link Converter} used to {@linkplain 2262 * Converter#convert(Value) convert} a {@link String} value into a 2263 * <a href="{@docRoot}/overview-summary.html#setting_value">setting 2264 * value</a> of the appropriate type; must not be {@code null}; must 2265 * either be safe for concurrent use by multiple threads or created 2266 * specially for this method invocation or supplied in a context 2267 * where it is known that only one thread is executing at a time 2268 * 2269 * @param defaultValueFunction a {@link BiFunction} accepting a <a 2270 * href="{@docRoot}/overview-summary.html#setting_name">setting 2271 * name</a> and a {@link Set} of qualifier {@link Annotation}s that 2272 * returns a default {@link String}-typed value when a value could 2273 * not sourced; may be {@code null} in which case if no value can be 2274 * sourced a {@link NoSuchElementException} will be thrown; may 2275 * return {@code null}; must be safe for concurrent use by mulitple 2276 * threads; must not call any of this {@link Settings} instance's 2277 * methods or undefined behavior will result 2278 * 2279 * @exception NullPointerException if either {@code name}, {@code 2280 * elContext}, {@code expressionFactory} or {@code converter} is 2281 * {@code null} 2282 * 2283 * @exception IllegalArgumentException if {@linkplain 2284 * Converter#convert(Value) conversion} could not occur for any 2285 * reason; see {@link Converter#convert(Value)} 2286 * 2287 * @exception ConversionException if {@linkplain 2288 * Converter#convert(Value) conversion} could not occur for any 2289 * reason other than bad inputs 2290 * 2291 * @exception NoSuchElementException if {@code defaultValueFunction} 2292 * was {@code null} and no value could be sourced 2293 * 2294 * @exception ValueAcquisitionException if there was a procedural 2295 * problem acquiring a value 2296 * 2297 * @exception ArbitrationException if there was a problem performing 2298 * value arbitration 2299 * 2300 * @exception AmbiguousValuesException if arbitration completed but 2301 * could not resolve an ambiguity between potential return values 2302 * 2303 * @exception MalformedValuesException if the {@link 2304 * #handleMalformedValues(String, Set, Collection)} method was 2305 * overridden and the override throws a {@link 2306 * MalformedValuesException} 2307 * 2308 * @exception ELException if there was an error related to 2309 * expression language parsing or evaluation 2310 * 2311 * @threadsafety This method is and its overrides must be safe for 2312 * concurrent use by multiple threads. 2313 * 2314 * @idempotency No guarantees of any kind are made with respect to 2315 * the idempotency of this method or its overrides. 2316 * 2317 * @nullability This method may return {@code null}. 2318 */ 2319 final <T> T get(final String name, 2320 final Set<Annotation> qualifiers, 2321 final ELContext elContext, 2322 final ExpressionFactory expressionFactory, 2323 final Converter<? extends T> converter, 2324 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction) { 2325 Objects.requireNonNull(name); 2326 Objects.requireNonNull(converter); 2327 Value value = 2328 this.getValue(name, 2329 qualifiers, 2330 elContext, 2331 expressionFactory, 2332 defaultValueFunction); 2333 2334 final String stringToInterpolate; 2335 if (value == null) { 2336 if (defaultValueFunction == null) { 2337 // There was no value that came up. There's also no way to 2338 // get a default one. So the value is missing. 2339 throw new NoSuchElementException(name + " (" + qualifiers + ")"); 2340 } else { 2341 stringToInterpolate = defaultValueFunction.apply(name, qualifiers); 2342 } 2343 } else { 2344 stringToInterpolate = value.get(); 2345 } 2346 final String interpolatedString = this.interpolate(stringToInterpolate, elContext, expressionFactory, qualifiers); 2347 if (value == null) { 2348 value = new Value(null /* no Source; we synthesized this Value */, name, qualifiers, interpolatedString); 2349 } else { 2350 value = new Value(value, interpolatedString); 2351 } 2352 return converter.convert(value); 2353 } 2354 2355 //---------------------------------------------------------------------------- 2356 2357 /** 2358 * Implements the {@link Source#getValue(String, Set)} method so 2359 * that this {@link Settings} can be conveniently used as a {@link 2360 * Source} from a higher-order {@link Settings}. 2361 * 2362 * <p>End users should never need to call this method directly.</p> 2363 * 2364 * @param name the name of the setting for which a value is to be 2365 * returned; must not be {@code null} 2366 * 2367 * @param qualifiers a {@link Set} of {@link Annotation}s to further 2368 * qualify the selection of the value to be returned; may be {@code 2369 * null}; if non-{@code null} then this parameter value must be safe 2370 * for concurrent iteration by multiple threads 2371 * 2372 * @return a suitable {@link Value}, or {@code null} if no {@link 2373 * Value} could be created or acquired 2374 * 2375 * @exception NullPointerException if {@code name} is {@code null} 2376 * 2377 * @exception ValueAcquisitionException if there was a procedural 2378 * problem acquiring a {@link Value} 2379 * 2380 * @nullability This method may return {@code null}. 2381 * 2382 * @idempotency This method may not be idempotent. That is, two 2383 * invocations supplied with the same {@code name} and {@code 2384 * qualifiers} parameter values may or may not return {@link Value}s 2385 * that are identical, {@linkplain Object#equals(Object) equal} or 2386 * neither. 2387 * 2388 * @threadsafety This method is safe for concurrent use by multiple 2389 * threads. 2390 * 2391 * @see Source#getValue(String, Set) 2392 */ 2393 @Experimental 2394 @Override 2395 public final Value getValue(final String name, final Set<Annotation> qualifiers) { 2396 final ExpressionFactory expressionFactory = ExpressionFactory.newInstance(); 2397 final StandardELContext elContext = new StandardELContext(expressionFactory); 2398 elContext.addELResolver(new SourceELResolver(this, expressionFactory, qualifiers)); 2399 try { 2400 return this.getValue(name, qualifiers, elContext, expressionFactory, NULL); 2401 } catch (final AmbiguousValuesException ambiguousValuesException) { 2402 throw new ValueAcquisitionException(ambiguousValuesException.getMessage(), ambiguousValuesException); 2403 } 2404 } 2405 2406 private final Value getValue(final String name, 2407 Set<Annotation> qualifiers, 2408 final ELContext elContext, 2409 final ExpressionFactory expressionFactory, 2410 final BiFunction<? super String, 2411 ? super Set<? extends Annotation>, 2412 ? extends String> defaultValueFunction) { 2413 Objects.requireNonNull(name); 2414 Objects.requireNonNull(elContext); 2415 Objects.requireNonNull(expressionFactory); 2416 2417 final int qualifiersSize; 2418 if (qualifiers == null || qualifiers.isEmpty()) { 2419 qualifiers = Collections.emptySet(); 2420 qualifiersSize = 0; 2421 } else { 2422 qualifiers = Collections.unmodifiableSet(qualifiers); 2423 qualifiersSize = qualifiers.size(); 2424 } 2425 2426 // The candidate for returning. 2427 Value selectedValue = null; 2428 2429 // Values that need to be arbitrated; i.e. conflicts. 2430 Queue<Value> conflictingValues = null; 2431 2432 // Bad values. 2433 Collection<Value> badValues = null; 2434 2435 final Set<? extends Source> sources = this.sourcesFunction.apply(name, qualifiers); 2436 if (sources != null) { 2437 for (final Source source : sources) { 2438 if (source != null && source != this) { 2439 2440 final Value value = source.getValue(name, qualifiers); 2441 2442 if (value != null) { 2443 2444 if (name.equals(value.getName())) { 2445 2446 Set<Annotation> valueQualifiers = value.getQualifiers(); 2447 final int valueQualifiersSize; 2448 if (valueQualifiers == null) { 2449 valueQualifiersSize = 0; 2450 valueQualifiers = Collections.emptySet(); 2451 } else { 2452 valueQualifiersSize = valueQualifiers.size(); 2453 } 2454 2455 if (qualifiersSize < valueQualifiersSize) { 2456 // The value said it was for, say, {a=b, c=d}. We 2457 // supplied just {a=b}, or maybe even {q=r}. So 2458 // somehow the value's qualifiers were overly 2459 // specific. It doesn't matter whether some of the 2460 // value's qualifiers were contained by us or not; 2461 // it's a bad value either way. 2462 if (badValues == null) { 2463 badValues = new ArrayList<>(); 2464 } 2465 badValues.add(value); 2466 2467 } else if (qualifiers.equals(valueQualifiers)) { 2468 // We asked for, say, {a=b, c=d}; the value said it 2469 // was for exactly {a=b, c=d}. That's very good: we 2470 // now have an exact match. We hope it's going to 2471 // be the only one, i.e. that no other source ALSO 2472 // produces an exact match. If we have two exact 2473 // matches, then they're obviously a conflict. 2474 if (selectedValue == null) { 2475 if (conflictingValues == null || conflictingValues.isEmpty()) { 2476 // There aren't any conflicts yet; this is good. 2477 // This value will be our candidate. 2478 selectedValue = value; 2479 } else { 2480 // The conflicting values queue already contains 2481 // something, and the only way it could is when 2482 // a prior exact match happened. That is, we 2483 // got an exact match, true, but we already 2484 // *had* an exact match, so now we have TWO 2485 // exact matches, and therefore we don't in fact 2486 // have a candidate--instead, add it to the 2487 // conflicting values queue. 2488 conflictingValues.add(value); 2489 } 2490 } else { 2491 // We have an exact match, but we already 2492 // identified a candidate, so oops, we have to 2493 // treat our prior match and this one as 2494 // non-candidates. 2495 if (conflictingValues == null) { 2496 conflictingValues = new PriorityQueue<>(valueComparator); 2497 } 2498 conflictingValues.add(selectedValue); 2499 conflictingValues.add(value); 2500 // "Erase" our prior best candidate, now that we 2501 // have more than one. 2502 selectedValue = null; 2503 } 2504 2505 } else if (qualifiersSize == valueQualifiersSize) { 2506 // We asked for, e.g., {a=b} and we got back {c=d}. 2507 // Bad value! The configuration subsystem handed 2508 // back a value containing coordinates not drawn 2509 // from the configurationCoordinatesSet. We know 2510 // this because we already tested for Set equality, 2511 // which failed, so this test means disparate 2512 // entries. 2513 if (badValues == null) { 2514 badValues = new ArrayList<>(); 2515 } 2516 badValues.add(value); 2517 2518 } else if (selectedValue != null) { 2519 assert qualifiersSize > valueQualifiersSize; 2520 // We asked for {a=b, c=d}; we got back either {a=b} 2521 // or {c=d} or {q=x}. We already have selectedValue 2522 // set so we already had a better match at some 2523 // point. 2524 2525 if (!qualifiers.containsAll(valueQualifiers)) { 2526 // We asked for {a=b, c=d}; we got back {q=x}. 2527 // That's a bad value. 2528 if (badValues == null) { 2529 badValues = new ArrayList<>(); 2530 } 2531 badValues.add(value); 2532 } 2533 2534 } else if (qualifiers.containsAll(valueQualifiers)) { 2535 assert qualifiersSize > valueQualifiersSize; 2536 // We specified, e.g., {a=b, c=d, e=f} and they 2537 // have, say, {c=d, e=f} or {a=b, c=d} etc. but not, 2538 // say, {q=r}. So we got a 2539 // less-than-perfect-but-possibly-suitable match. 2540 if (conflictingValues == null) { 2541 conflictingValues = new PriorityQueue<>(valueComparator); 2542 } 2543 conflictingValues.add(value); 2544 2545 } else { 2546 // Bad value! 2547 if (badValues == null) { 2548 badValues = new ArrayList<>(); 2549 } 2550 badValues.add(value); 2551 2552 } 2553 2554 } else { 2555 // We asked for "frobnicationInterval"; they responded 2556 // with "hostname". Bad value. 2557 if (badValues == null) { 2558 badValues = new ArrayList<>(); 2559 } 2560 badValues.add(value); 2561 2562 } 2563 } 2564 } 2565 } 2566 } 2567 2568 if (badValues != null && !badValues.isEmpty()) { 2569 this.handleMalformedValues(name, qualifiers, badValues); 2570 } 2571 2572 Collection<Value> valuesToArbitrate = null; 2573 2574 if (selectedValue == null) { 2575 2576 if (conflictingValues != null) { 2577 2578 // Perform arbitration. The first "round" of arbitration is 2579 // hard-coded, effectively: we check to see if all conflicting 2580 // values are of different specificities. If they are, then 2581 // the most specific value is selected and the others are 2582 // discarded. Otherwise, if any two conflicting values share 2583 // specificities, then they are added to a collection over 2584 // which our supplied Arbiters will operate. 2585 2586 int highestSpecificitySoFarEncountered = -1; 2587 2588 while (!conflictingValues.isEmpty()) { 2589 2590 final Value value = conflictingValues.poll(); 2591 assert value != null; 2592 2593 final int valueSpecificity = Math.max(0, value.getQualifiers().size()); 2594 assert highestSpecificitySoFarEncountered < 0 || valueSpecificity <= highestSpecificitySoFarEncountered; 2595 2596 if (highestSpecificitySoFarEncountered < 0 || valueSpecificity < highestSpecificitySoFarEncountered) { 2597 if (selectedValue == null) { 2598 assert valuesToArbitrate == null || valuesToArbitrate.isEmpty(); 2599 selectedValue = value; 2600 highestSpecificitySoFarEncountered = valueSpecificity; 2601 } else if (valuesToArbitrate == null || valuesToArbitrate.isEmpty()) { 2602 // We have a selected value that is non-null, and no 2603 // further values to arbitrate, so we're done. We know 2604 // we picked the most specific value so we effectively 2605 // discard the others. 2606 break; 2607 } else { 2608 valuesToArbitrate.add(value); 2609 } 2610 } else if (valueSpecificity == highestSpecificitySoFarEncountered) { 2611 assert selectedValue != null; 2612 if (value.isAuthoritative()) { 2613 if (selectedValue.isAuthoritative()) { 2614 // Both say they're authoritative; arbitration required 2615 if (valuesToArbitrate == null) { 2616 valuesToArbitrate = new ArrayList<>(); 2617 } 2618 valuesToArbitrate.add(selectedValue); 2619 selectedValue = null; 2620 valuesToArbitrate.add(value); 2621 } else { 2622 // value is authoritative; selectedValue is not; so swap 2623 // them 2624 selectedValue = value; 2625 } 2626 } else if (selectedValue.isAuthoritative()) { 2627 // value is not authoritative; selected value is; so just 2628 // drop value on the floor; it's not authoritative. 2629 } else { 2630 // Neither is authoritative; arbitration required. 2631 if (valuesToArbitrate == null) { 2632 valuesToArbitrate = new ArrayList<>(); 2633 } 2634 valuesToArbitrate.add(selectedValue); 2635 selectedValue = null; 2636 valuesToArbitrate.add(value); 2637 } 2638 } else { 2639 assert false : "valueSpecificity > highestSpecificitySoFarEncountered: " + 2640 valueSpecificity + " > " + highestSpecificitySoFarEncountered; 2641 } 2642 } 2643 } 2644 } 2645 2646 if (selectedValue == null) { 2647 if (valuesToArbitrate == null || valuesToArbitrate.isEmpty()) { 2648 selectedValue = this.arbitrate(sources, name, qualifiers, Collections.emptySet()); 2649 } else { 2650 selectedValue = this.arbitrate(sources, name, qualifiers, Collections.unmodifiableCollection(valuesToArbitrate)); 2651 if (selectedValue == null) { 2652 throw new AmbiguousValuesException(valuesToArbitrate); 2653 } 2654 } 2655 } 2656 2657 return selectedValue; 2658 } 2659 2660 //---------------------------------------------------------------------------- 2661 2662 /** 2663 * Configures the supplied Java Bean by {@linkplain #get(String, 2664 * Set, Converter, BiFunction) acquiring setting values} named after 2665 * the supplied {@link PropertyDescriptor}s and using their 2666 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 2667 * methods} to set the corresponding values. 2668 * 2669 * <p>This implementation calls the {@link #configure(Object, 2670 * Iterable, String, Set)} method with sensible defaults.</p> 2671 * 2672 * @param object the {@link Object} to configure; must not be {@code null} 2673 * 2674 * @exception NullPointerException if either {@code object} or {@code 2675 * beanInfo} is {@code null} 2676 * 2677 * @exception IntrospectionException if introspection of the 2678 * supplied {@code object} fails 2679 * 2680 * @exception ReflectiveOperationException if there was a problem 2681 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 2682 * method}; the supplied {@link Object} may, in this case, be left 2683 * in an inconsistent state 2684 * 2685 * @exception IllegalArgumentException if {@linkplain 2686 * Converter#convert(Value) conversion} could not occur for any 2687 * reason; see {@link Converter#convert(Value)}; the supplied {@link 2688 * Object} may, in this case, be left in an inconsistent state 2689 * 2690 * @exception ConversionException if {@linkplain 2691 * Converter#convert(Value) conversion} could not occur for any 2692 * reason other than bad inputs; the supplied {@link Object} may, in 2693 * this case, be left in an inconsistent state 2694 * 2695 * @exception ValueAcquisitionException if there was a procedural 2696 * problem acquiring a value; the supplied {@link Object} may, in 2697 * this case, be left in an inconsistent state 2698 * 2699 * @exception ArbitrationException if there was a problem performing 2700 * value arbitration; the supplied {@link Object} may, in this case, 2701 * be left in an inconsistent state 2702 * 2703 * @exception AmbiguousValuesException if arbitration completed but 2704 * could not resolve an ambiguity between potential return values; 2705 * the supplied {@link Object} may, in this case, be left in an 2706 * inconsistent state 2707 * 2708 * @exception MalformedValuesException if the {@link 2709 * #handleMalformedValues(String, Set, Collection)} method was 2710 * overridden and the override throws a {@link 2711 * MalformedValuesException}; the supplied {@link Object} may, in 2712 * this case, be left in an inconsistent state 2713 * 2714 * @exception ELException if there was an error related to 2715 * expression language parsing or evaluation; the supplied {@link 2716 * Object} may, in this case, be left in an inconsistent state 2717 * 2718 * @threadsafety This method is safe for concurrent use by multiple 2719 * threads. 2720 * 2721 * @idempotency No guarantees are made with respect to the 2722 * idempotency of this method. 2723 * 2724 * @see #configure(Object, Iterable, String, Set) 2725 */ 2726 public final void configure(final Object object) 2727 throws IntrospectionException, ReflectiveOperationException { 2728 this.configure(object, 2729 Arrays.asList(Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors()), 2730 null, 2731 this.qualifiers); 2732 } 2733 2734 /** 2735 * Configures the supplied Java Bean by {@linkplain #get(String, 2736 * Set, Converter, BiFunction) acquiring setting values} named after 2737 * the supplied {@link PropertyDescriptor}s and using their 2738 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 2739 * methods} to set the corresponding values. 2740 * 2741 * <p>This implementation calls the {@link #configure(Object, 2742 * Iterable, String, Set)} method with sensible defaults.</p> 2743 * 2744 * @param object the {@link Object} to configure; must not be {@code null} 2745 * 2746 * @param prefix a {@link String} that will be prepended to each 2747 * {@linkplain PropertyDescriptor#getName() 2748 * <code>PropertyDescriptor</code> name} before using the result as 2749 * the name of a setting for which a value {@linkplain #get(String, 2750 * Set, Converter, BiFunction) will be acquired}; may be {@code 2751 * null} 2752 * 2753 * @exception NullPointerException if either {@code object} or {@code 2754 * beanInfo} is {@code null} 2755 * 2756 * @exception IntrospectionException if introspection of the 2757 * supplied {@code object} fails 2758 * 2759 * @exception ReflectiveOperationException if there was a problem 2760 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 2761 * method}; the supplied {@link Object} may, in this case, be left 2762 * in an inconsistent state 2763 * 2764 * @exception IllegalArgumentException if {@linkplain 2765 * Converter#convert(Value) conversion} could not occur for any 2766 * reason; see {@link Converter#convert(Value)}; the supplied {@link 2767 * Object} may, in this case, be left in an inconsistent state 2768 * 2769 * @exception ConversionException if {@linkplain 2770 * Converter#convert(Value) conversion} could not occur for any 2771 * reason other than bad inputs; the supplied {@link Object} may, in 2772 * this case, be left in an inconsistent state 2773 * 2774 * @exception ValueAcquisitionException if there was a procedural 2775 * problem acquiring a value; the supplied {@link Object} may, in 2776 * this case, be left in an inconsistent state 2777 * 2778 * @exception ArbitrationException if there was a problem performing 2779 * value arbitration; the supplied {@link Object} may, in this case, 2780 * be left in an inconsistent state 2781 * 2782 * @exception AmbiguousValuesException if arbitration completed but 2783 * could not resolve an ambiguity between potential return values; 2784 * the supplied {@link Object} may, in this case, be left in an 2785 * inconsistent state 2786 * 2787 * @exception MalformedValuesException if the {@link 2788 * #handleMalformedValues(String, Set, Collection)} method was 2789 * overridden and the override throws a {@link 2790 * MalformedValuesException}; the supplied {@link Object} may, in 2791 * this case, be left in an inconsistent state 2792 * 2793 * @exception ELException if there was an error related to 2794 * expression language parsing or evaluation; the supplied {@link 2795 * Object} may, in this case, be left in an inconsistent state 2796 * 2797 * @threadsafety This method is safe for concurrent use by multiple 2798 * threads. 2799 * 2800 * @idempotency No guarantees are made with respect to the 2801 * idempotency of this method. 2802 * 2803 * @see #configure(Object, Iterable, String, Set) 2804 */ 2805 public final void configure(final Object object, 2806 final String prefix) 2807 throws IntrospectionException, ReflectiveOperationException { 2808 this.configure(object, 2809 Arrays.asList(Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors()), 2810 prefix, 2811 this.qualifiers); 2812 } 2813 2814 /** 2815 * Configures the supplied Java Bean by {@linkplain #get(String, 2816 * Set, Converter, BiFunction) acquiring setting values} named after 2817 * the supplied {@link PropertyDescriptor}s and using their 2818 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 2819 * methods} to set the corresponding values. 2820 * 2821 * <p>This implementation calls the {@link #configure(Object, 2822 * Iterable, String, Set)} method with sensible defaults.</p> 2823 * 2824 * @param object the {@link Object} to configure; must not be {@code null} 2825 * 2826 * @param qualifiers a {@link Set} of {@link Annotation}s to further 2827 * qualify the selection of values; may be {@code null}; if 2828 * non-{@code null} then this parameter value must be safe for 2829 * concurrent iteration by multiple threads 2830 * 2831 * @exception NullPointerException if either {@code object} or {@code 2832 * beanInfo} is {@code null} 2833 * 2834 * @exception IntrospectionException if introspection of the 2835 * supplied {@code object} fails 2836 * 2837 * @exception ReflectiveOperationException if there was a problem 2838 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 2839 * method}; the supplied {@link Object} may, in this case, be left 2840 * in an inconsistent state 2841 * 2842 * @exception IllegalArgumentException if {@linkplain 2843 * Converter#convert(Value) conversion} could not occur for any 2844 * reason; see {@link Converter#convert(Value)}; the supplied {@link 2845 * Object} may, in this case, be left in an inconsistent state 2846 * 2847 * @exception ConversionException if {@linkplain 2848 * Converter#convert(Value) conversion} could not occur for any 2849 * reason other than bad inputs; the supplied {@link Object} may, in 2850 * this case, be left in an inconsistent state 2851 * 2852 * @exception ValueAcquisitionException if there was a procedural 2853 * problem acquiring a value; the supplied {@link Object} may, in 2854 * this case, be left in an inconsistent state 2855 * 2856 * @exception ArbitrationException if there was a problem performing 2857 * value arbitration; the supplied {@link Object} may, in this case, 2858 * be left in an inconsistent state 2859 * 2860 * @exception AmbiguousValuesException if arbitration completed but 2861 * could not resolve an ambiguity between potential return values; 2862 * the supplied {@link Object} may, in this case, be left in an 2863 * inconsistent state 2864 * 2865 * @exception MalformedValuesException if the {@link 2866 * #handleMalformedValues(String, Set, Collection)} method was 2867 * overridden and the override throws a {@link 2868 * MalformedValuesException}; the supplied {@link Object} may, in 2869 * this case, be left in an inconsistent state 2870 * 2871 * @exception ELException if there was an error related to 2872 * expression language parsing or evaluation; the supplied {@link 2873 * Object} may, in this case, be left in an inconsistent state 2874 * 2875 * @threadsafety This method is safe for concurrent use by multiple 2876 * threads. 2877 * 2878 * @idempotency No guarantees are made with respect to the 2879 * idempotency of this method. 2880 * 2881 * @see #configure(Object, Iterable, String, Set) 2882 */ 2883 public final void configure(final Object object, 2884 final Set<Annotation> qualifiers) 2885 throws IntrospectionException, ReflectiveOperationException { 2886 this.configure(object, 2887 Arrays.asList(Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors()), 2888 null, 2889 qualifiers); 2890 } 2891 2892 /** 2893 * Configures the supplied Java Bean by {@linkplain #get(String, 2894 * Set, Converter, BiFunction) acquiring setting values} named after 2895 * the supplied {@link PropertyDescriptor}s and using their 2896 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 2897 * methods} to set the corresponding values. 2898 * 2899 * <p>This implementation calls the {@link #configure(Object, 2900 * Iterable, String, Set)} method with sensible defaults.</p> 2901 * 2902 * @param object the {@link Object} to configure; must not be {@code null} 2903 * 2904 * @param prefix a {@link String} that will be prepended to each 2905 * {@linkplain PropertyDescriptor#getName() 2906 * <code>PropertyDescriptor</code> name} before using the result as 2907 * the name of a setting for which a value {@linkplain #get(String, 2908 * Set, Converter, BiFunction) will be acquired}; may be {@code 2909 * null} 2910 * 2911 * @param qualifiers a {@link Set} of {@link Annotation}s to further 2912 * qualify the selection of values; may be {@code null}; if 2913 * non-{@code null} then this parameter value must be safe for 2914 * concurrent iteration by multiple threads 2915 * 2916 * @exception NullPointerException if either {@code object} or {@code 2917 * beanInfo} is {@code null} 2918 * 2919 * @exception IntrospectionException if introspection of the 2920 * supplied {@code object} fails 2921 * 2922 * @exception ReflectiveOperationException if there was a problem 2923 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 2924 * method}; the supplied {@link Object} may, in this case, be left 2925 * in an inconsistent state 2926 * 2927 * @exception IllegalArgumentException if {@linkplain 2928 * Converter#convert(Value) conversion} could not occur for any 2929 * reason; see {@link Converter#convert(Value)}; the supplied {@link 2930 * Object} may, in this case, be left in an inconsistent state 2931 * 2932 * @exception ConversionException if {@linkplain 2933 * Converter#convert(Value) conversion} could not occur for any 2934 * reason other than bad inputs; the supplied {@link Object} may, in 2935 * this case, be left in an inconsistent state 2936 * 2937 * @exception ValueAcquisitionException if there was a procedural 2938 * problem acquiring a value; the supplied {@link Object} may, in 2939 * this case, be left in an inconsistent state 2940 * 2941 * @exception ArbitrationException if there was a problem performing 2942 * value arbitration; the supplied {@link Object} may, in this case, 2943 * be left in an inconsistent state 2944 * 2945 * @exception AmbiguousValuesException if arbitration completed but 2946 * could not resolve an ambiguity between potential return values; 2947 * the supplied {@link Object} may, in this case, be left in an 2948 * inconsistent state 2949 * 2950 * @exception MalformedValuesException if the {@link 2951 * #handleMalformedValues(String, Set, Collection)} method was 2952 * overridden and the override throws a {@link 2953 * MalformedValuesException}; the supplied {@link Object} may, in 2954 * this case, be left in an inconsistent state 2955 * 2956 * @exception ELException if there was an error related to 2957 * expression language parsing or evaluation; the supplied {@link 2958 * Object} may, in this case, be left in an inconsistent state 2959 * 2960 * @threadsafety This method is safe for concurrent use by multiple 2961 * threads. 2962 * 2963 * @idempotency No guarantees are made with respect to the 2964 * idempotency of this method. 2965 * 2966 * @see #configure(Object, Iterable, String, Set) 2967 */ 2968 public final void configure(final Object object, 2969 final String prefix, 2970 final Set<Annotation> qualifiers) 2971 throws IntrospectionException, ReflectiveOperationException { 2972 this.configure(object, 2973 Arrays.asList(Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors()), 2974 prefix, 2975 qualifiers); 2976 } 2977 2978 /** 2979 * Configures the supplied Java Bean by {@linkplain #get(String, 2980 * Set, Converter, BiFunction) acquiring setting values} named after 2981 * the supplied {@link PropertyDescriptor}s and using their 2982 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 2983 * methods} to set the corresponding values. 2984 * 2985 * <p>This implementation calls the {@link #configure(Object, 2986 * Iterable, String, Set)} method with sensible defaults.</p> 2987 * 2988 * @param object the {@link Object} to configure; must not be {@code null} 2989 * 2990 * @param beanInfo a {@link BeanInfo} {@linkplain 2991 * BeanInfo#getPropertyDescriptors() providing access to 2992 * <code>PropertyDescriptor</code>s}; must not be {@code null} 2993 * 2994 * @exception NullPointerException if either {@code object} or {@code 2995 * beanInfo} is {@code null} 2996 * 2997 * @exception ReflectiveOperationException if there was a problem 2998 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 2999 * method}; the supplied {@link Object} may, in this case, be left 3000 * in an inconsistent state 3001 * 3002 * @exception IllegalArgumentException if {@linkplain 3003 * Converter#convert(Value) conversion} could not occur for any 3004 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3005 * Object} may, in this case, be left in an inconsistent state 3006 * 3007 * @exception ConversionException if {@linkplain 3008 * Converter#convert(Value) conversion} could not occur for any 3009 * reason other than bad inputs; the supplied {@link Object} may, in 3010 * this case, be left in an inconsistent state 3011 * 3012 * @exception ValueAcquisitionException if there was a procedural 3013 * problem acquiring a value; the supplied {@link Object} may, in 3014 * this case, be left in an inconsistent state 3015 * 3016 * @exception ArbitrationException if there was a problem performing 3017 * value arbitration; the supplied {@link Object} may, in this case, 3018 * be left in an inconsistent state 3019 * 3020 * @exception AmbiguousValuesException if arbitration completed but 3021 * could not resolve an ambiguity between potential return values; 3022 * the supplied {@link Object} may, in this case, be left in an 3023 * inconsistent state 3024 * 3025 * @exception MalformedValuesException if the {@link 3026 * #handleMalformedValues(String, Set, Collection)} method was 3027 * overridden and the override throws a {@link 3028 * MalformedValuesException}; the supplied {@link Object} may, in 3029 * this case, be left in an inconsistent state 3030 * 3031 * @exception ELException if there was an error related to 3032 * expression language parsing or evaluation; the supplied {@link 3033 * Object} may, in this case, be left in an inconsistent state 3034 * 3035 * @threadsafety This method is safe for concurrent use by multiple 3036 * threads. 3037 * 3038 * @idempotency No guarantees are made with respect to the 3039 * idempotency of this method. 3040 * 3041 * @see #configure(Object, Iterable, String, Set) 3042 */ 3043 public final void configure(final Object object, 3044 final BeanInfo beanInfo) 3045 throws ReflectiveOperationException { 3046 this.configure(object, 3047 Arrays.asList(beanInfo.getPropertyDescriptors()), 3048 null, 3049 this.qualifiers); 3050 } 3051 3052 /** 3053 * Configures the supplied Java Bean by {@linkplain #get(String, 3054 * Set, Converter, BiFunction) acquiring setting values} named after 3055 * the supplied {@link PropertyDescriptor}s and using their 3056 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 3057 * methods} to set the corresponding values. 3058 * 3059 * <p>This implementation calls the {@link #configure(Object, 3060 * Iterable, String, Set)} method with sensible defaults.</p> 3061 * 3062 * @param object the {@link Object} to configure; must not be {@code null} 3063 * 3064 * @param beanInfo a {@link BeanInfo} {@linkplain 3065 * BeanInfo#getPropertyDescriptors() providing access to 3066 * <code>PropertyDescriptor</code>s}; must not be {@code null} 3067 * 3068 * @param prefix a {@link String} that will be prepended to each 3069 * {@linkplain PropertyDescriptor#getName() 3070 * <code>PropertyDescriptor</code> name} before using the result as 3071 * the name of a setting for which a value {@linkplain #get(String, 3072 * Set, Converter, BiFunction) will be acquired}; may be {@code 3073 * null} 3074 * 3075 * @exception NullPointerException if either {@code object} or {@code 3076 * beanInfo} is {@code null} 3077 * 3078 * @exception ReflectiveOperationException if there was a problem 3079 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 3080 * method}; the supplied {@link Object} may, in this case, be left 3081 * in an inconsistent state 3082 * 3083 * @exception IllegalArgumentException if {@linkplain 3084 * Converter#convert(Value) conversion} could not occur for any 3085 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3086 * Object} may, in this case, be left in an inconsistent state 3087 * 3088 * @exception ConversionException if {@linkplain 3089 * Converter#convert(Value) conversion} could not occur for any 3090 * reason other than bad inputs; the supplied {@link Object} may, in 3091 * this case, be left in an inconsistent state 3092 * 3093 * @exception ValueAcquisitionException if there was a procedural 3094 * problem acquiring a value; the supplied {@link Object} may, in 3095 * this case, be left in an inconsistent state 3096 * 3097 * @exception ArbitrationException if there was a problem performing 3098 * value arbitration; the supplied {@link Object} may, in this case, 3099 * be left in an inconsistent state 3100 * 3101 * @exception AmbiguousValuesException if arbitration completed but 3102 * could not resolve an ambiguity between potential return values; 3103 * the supplied {@link Object} may, in this case, be left in an 3104 * inconsistent state 3105 * 3106 * @exception MalformedValuesException if the {@link 3107 * #handleMalformedValues(String, Set, Collection)} method was 3108 * overridden and the override throws a {@link 3109 * MalformedValuesException}; the supplied {@link Object} may, in 3110 * this case, be left in an inconsistent state 3111 * 3112 * @exception ELException if there was an error related to 3113 * expression language parsing or evaluation; the supplied {@link 3114 * Object} may, in this case, be left in an inconsistent state 3115 * 3116 * @threadsafety This method is safe for concurrent use by multiple 3117 * threads. 3118 * 3119 * @idempotency No guarantees are made with respect to the 3120 * idempotency of this method. 3121 * 3122 * @see #configure(Object, Iterable, String, Set) 3123 */ 3124 public final void configure(final Object object, 3125 final BeanInfo beanInfo, 3126 final String prefix) 3127 throws ReflectiveOperationException { 3128 this.configure(object, 3129 Arrays.asList(beanInfo.getPropertyDescriptors()), 3130 prefix, 3131 this.qualifiers); 3132 } 3133 3134 /** 3135 * Configures the supplied Java Bean by {@linkplain #get(String, 3136 * Set, Converter, BiFunction) acquiring setting values} named after 3137 * the supplied {@link PropertyDescriptor}s and using their 3138 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 3139 * methods} to set the corresponding values. 3140 * 3141 * <p>This implementation calls the {@link #configure(Object, 3142 * Iterable, String, Set)} method with sensible defaults.</p> 3143 * 3144 * @param object the {@link Object} to configure; must not be {@code null} 3145 * 3146 * @param beanInfo a {@link BeanInfo} {@linkplain 3147 * BeanInfo#getPropertyDescriptors() providing access to 3148 * <code>PropertyDescriptor</code>s}; must not be {@code null} 3149 * 3150 * @param qualifiers a {@link Set} of {@link Annotation}s to further 3151 * qualify the selection of values; may be {@code null}; if 3152 * non-{@code null} then this parameter value must be safe for 3153 * concurrent iteration by multiple threads 3154 * 3155 * @exception NullPointerException if either {@code object} or {@code 3156 * beanInfo} is {@code null} 3157 * 3158 * @exception ReflectiveOperationException if there was a problem 3159 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 3160 * method}; the supplied {@link Object} may, in this case, be left 3161 * in an inconsistent state 3162 * 3163 * @exception IllegalArgumentException if {@linkplain 3164 * Converter#convert(Value) conversion} could not occur for any 3165 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3166 * Object} may, in this case, be left in an inconsistent state 3167 * 3168 * @exception ConversionException if {@linkplain 3169 * Converter#convert(Value) conversion} could not occur for any 3170 * reason other than bad inputs; the supplied {@link Object} may, in 3171 * this case, be left in an inconsistent state 3172 * 3173 * @exception ValueAcquisitionException if there was a procedural 3174 * problem acquiring a value; the supplied {@link Object} may, in 3175 * this case, be left in an inconsistent state 3176 * 3177 * @exception ArbitrationException if there was a problem performing 3178 * value arbitration; the supplied {@link Object} may, in this case, 3179 * be left in an inconsistent state 3180 * 3181 * @exception AmbiguousValuesException if arbitration completed but 3182 * could not resolve an ambiguity between potential return values; 3183 * the supplied {@link Object} may, in this case, be left in an 3184 * inconsistent state 3185 * 3186 * @exception MalformedValuesException if the {@link 3187 * #handleMalformedValues(String, Set, Collection)} method was 3188 * overridden and the override throws a {@link 3189 * MalformedValuesException}; the supplied {@link Object} may, in 3190 * this case, be left in an inconsistent state 3191 * 3192 * @exception ELException if there was an error related to 3193 * expression language parsing or evaluation; the supplied {@link 3194 * Object} may, in this case, be left in an inconsistent state 3195 * 3196 * @threadsafety This method is safe for concurrent use by multiple 3197 * threads. 3198 * 3199 * @idempotency No guarantees are made with respect to the 3200 * idempotency of this method. 3201 * 3202 * @see #configure(Object, Iterable, String, Set) 3203 */ 3204 public final void configure(final Object object, 3205 final BeanInfo beanInfo, 3206 final Set<Annotation> qualifiers) 3207 throws ReflectiveOperationException { 3208 this.configure(object, 3209 Arrays.asList(beanInfo.getPropertyDescriptors()), 3210 null, 3211 qualifiers); 3212 } 3213 3214 /** 3215 * Configures the supplied Java Bean by {@linkplain #get(String, 3216 * Set, Converter, BiFunction) acquiring setting values} named after 3217 * the supplied {@link PropertyDescriptor}s and using their 3218 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 3219 * methods} to set the corresponding values. 3220 * 3221 * <p>This implementation calls the {@link #configure(Object, 3222 * Iterable, String, Set)} method with sensible defaults.</p> 3223 * 3224 * @param object the {@link Object} to configure; must not be {@code null} 3225 * 3226 * @param beanInfo a {@link BeanInfo} {@linkplain 3227 * BeanInfo#getPropertyDescriptors() providing access to 3228 * <code>PropertyDescriptor</code>s}; must not be {@code null} 3229 * 3230 * @param prefix a {@link String} that will be prepended to each 3231 * {@linkplain PropertyDescriptor#getName() 3232 * <code>PropertyDescriptor</code> name} before using the result as 3233 * the name of a setting for which a value {@linkplain #get(String, 3234 * Set, Converter, BiFunction) will be acquired}; may be {@code 3235 * null} 3236 * 3237 * @param qualifiers a {@link Set} of {@link Annotation}s to further 3238 * qualify the selection of values; may be {@code null}; if 3239 * non-{@code null} then this parameter value must be safe for 3240 * concurrent iteration by multiple threads 3241 * 3242 * @exception NullPointerException if either {@code object} or {@code 3243 * beanInfo} is {@code null} 3244 * 3245 * @exception ReflectiveOperationException if there was a problem 3246 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 3247 * method}; the supplied {@link Object} may, in this case, be left 3248 * in an inconsistent state 3249 * 3250 * @exception IllegalArgumentException if {@linkplain 3251 * Converter#convert(Value) conversion} could not occur for any 3252 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3253 * Object} may, in this case, be left in an inconsistent state 3254 * 3255 * @exception ConversionException if {@linkplain 3256 * Converter#convert(Value) conversion} could not occur for any 3257 * reason other than bad inputs; the supplied {@link Object} may, in 3258 * this case, be left in an inconsistent state 3259 * 3260 * @exception ValueAcquisitionException if there was a procedural 3261 * problem acquiring a value; the supplied {@link Object} may, in 3262 * this case, be left in an inconsistent state 3263 * 3264 * @exception ArbitrationException if there was a problem performing 3265 * value arbitration; the supplied {@link Object} may, in this case, 3266 * be left in an inconsistent state 3267 * 3268 * @exception AmbiguousValuesException if arbitration completed but 3269 * could not resolve an ambiguity between potential return values; 3270 * the supplied {@link Object} may, in this case, be left in an 3271 * inconsistent state 3272 * 3273 * @exception MalformedValuesException if the {@link 3274 * #handleMalformedValues(String, Set, Collection)} method was 3275 * overridden and the override throws a {@link 3276 * MalformedValuesException}; the supplied {@link Object} may, in 3277 * this case, be left in an inconsistent state 3278 * 3279 * @exception ELException if there was an error related to 3280 * expression language parsing or evaluation; the supplied {@link 3281 * Object} may, in this case, be left in an inconsistent state 3282 * 3283 * @threadsafety This method is safe for concurrent use by multiple 3284 * threads. 3285 * 3286 * @idempotency No guarantees are made with respect to the 3287 * idempotency of this method. 3288 * 3289 * @see #configure(Object, Iterable, String, Set) 3290 */ 3291 public final void configure(final Object object, 3292 final BeanInfo beanInfo, 3293 final String prefix, 3294 final Set<Annotation> qualifiers) 3295 throws ReflectiveOperationException { 3296 this.configure(object, 3297 Arrays.asList(beanInfo.getPropertyDescriptors()), 3298 prefix, 3299 qualifiers); 3300 } 3301 3302 /** 3303 * Configures the supplied Java Bean by {@linkplain #get(String, 3304 * Set, Converter, BiFunction) acquiring setting values} named after 3305 * the supplied {@link PropertyDescriptor}s and using their 3306 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 3307 * methods} to set the corresponding values. 3308 * 3309 * <p>This implementation calls the {@link #configure(Object, 3310 * Iterable, String, Set)} method with sensible defaults.</p> 3311 * 3312 * @param object the {@link Object} to configure; must not be {@code null} 3313 * 3314 * @param propertyDescriptors an {@link Iterable} of {@link 3315 * PropertyDescriptor}s; must not be {@code null} 3316 * 3317 * @exception NullPointerException if either {@code object} or {@code 3318 * propertyDescriptors} is {@code null} 3319 * 3320 * @exception ReflectiveOperationException if there was a problem 3321 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 3322 * method}; the supplied {@link Object} may, in this case, be left 3323 * in an inconsistent state 3324 * 3325 * @exception IllegalArgumentException if {@linkplain 3326 * Converter#convert(Value) conversion} could not occur for any 3327 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3328 * Object} may, in this case, be left in an inconsistent state 3329 * 3330 * @exception ConversionException if {@linkplain 3331 * Converter#convert(Value) conversion} could not occur for any 3332 * reason other than bad inputs; the supplied {@link Object} may, in 3333 * this case, be left in an inconsistent state 3334 * 3335 * @exception ValueAcquisitionException if there was a procedural 3336 * problem acquiring a value; the supplied {@link Object} may, in 3337 * this case, be left in an inconsistent state 3338 * 3339 * @exception ArbitrationException if there was a problem performing 3340 * value arbitration; the supplied {@link Object} may, in this case, 3341 * be left in an inconsistent state 3342 * 3343 * @exception AmbiguousValuesException if arbitration completed but 3344 * could not resolve an ambiguity between potential return values; 3345 * the supplied {@link Object} may, in this case, be left in an 3346 * inconsistent state 3347 * 3348 * @exception MalformedValuesException if the {@link 3349 * #handleMalformedValues(String, Set, Collection)} method was 3350 * overridden and the override throws a {@link 3351 * MalformedValuesException}; the supplied {@link Object} may, in 3352 * this case, be left in an inconsistent state 3353 * 3354 * @exception ELException if there was an error related to 3355 * expression language parsing or evaluation; the supplied {@link 3356 * Object} may, in this case, be left in an inconsistent state 3357 * 3358 * @threadsafety This method is safe for concurrent use by multiple 3359 * threads. 3360 * 3361 * @idempotency No guarantees are made with respect to the 3362 * idempotency of this method. 3363 * 3364 * @see #configure(Object, Iterable, String, Set) 3365 */ 3366 public final void configure(final Object object, 3367 final Iterable<? extends PropertyDescriptor> propertyDescriptors) 3368 throws ReflectiveOperationException { 3369 this.configure(object, 3370 propertyDescriptors, 3371 null, 3372 this.qualifiers); 3373 } 3374 3375 /** 3376 * Configures the supplied Java Bean by {@linkplain #get(String, 3377 * Set, Converter, BiFunction) acquiring setting values} named after 3378 * the supplied {@link PropertyDescriptor}s and using their 3379 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 3380 * methods} to set the corresponding values. 3381 * 3382 * <p>This implementation calls the {@link #configure(Object, 3383 * Iterable, String, Set)} method with sensible defaults.</p> 3384 * 3385 * @param object the {@link Object} to configure; must not be {@code null} 3386 * 3387 * @param propertyDescriptors an {@link Iterable} of {@link 3388 * PropertyDescriptor}s; must not be {@code null} 3389 * 3390 * @param prefix a {@link String} that will be prepended to each 3391 * {@linkplain PropertyDescriptor#getName() 3392 * <code>PropertyDescriptor</code> name} before using the result as 3393 * the name of a setting for which a value {@linkplain #get(String, 3394 * Set, Converter, BiFunction) will be acquired}; may be {@code 3395 * null} 3396 * 3397 * @exception NullPointerException if either {@code object} or {@code 3398 * propertyDescriptors} is {@code null} 3399 * 3400 * @exception ReflectiveOperationException if there was a problem 3401 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 3402 * method}; the supplied {@link Object} may, in this case, be left 3403 * in an inconsistent state 3404 * 3405 * @exception IllegalArgumentException if {@linkplain 3406 * Converter#convert(Value) conversion} could not occur for any 3407 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3408 * Object} may, in this case, be left in an inconsistent state 3409 * 3410 * @exception ConversionException if {@linkplain 3411 * Converter#convert(Value) conversion} could not occur for any 3412 * reason other than bad inputs; the supplied {@link Object} may, in 3413 * this case, be left in an inconsistent state 3414 * 3415 * @exception ValueAcquisitionException if there was a procedural 3416 * problem acquiring a value; the supplied {@link Object} may, in 3417 * this case, be left in an inconsistent state 3418 * 3419 * @exception ArbitrationException if there was a problem performing 3420 * value arbitration; the supplied {@link Object} may, in this case, 3421 * be left in an inconsistent state 3422 * 3423 * @exception AmbiguousValuesException if arbitration completed but 3424 * could not resolve an ambiguity between potential return values; 3425 * the supplied {@link Object} may, in this case, be left in an 3426 * inconsistent state 3427 * 3428 * @exception MalformedValuesException if the {@link 3429 * #handleMalformedValues(String, Set, Collection)} method was 3430 * overridden and the override throws a {@link 3431 * MalformedValuesException}; the supplied {@link Object} may, in 3432 * this case, be left in an inconsistent state 3433 * 3434 * @exception ELException if there was an error related to 3435 * expression language parsing or evaluation; the supplied {@link 3436 * Object} may, in this case, be left in an inconsistent state 3437 * 3438 * @threadsafety This method is safe for concurrent use by multiple 3439 * threads. 3440 * 3441 * @idempotency No guarantees are made with respect to the 3442 * idempotency of this method. 3443 * 3444 * @see #configure(Object, Iterable, String, Set) 3445 */ 3446 public final void configure(final Object object, 3447 final Iterable<? extends PropertyDescriptor> propertyDescriptors, 3448 final String prefix) 3449 throws ReflectiveOperationException { 3450 this.configure(object, 3451 propertyDescriptors, 3452 prefix, 3453 this.qualifiers); 3454 } 3455 3456 /** 3457 * Configures the supplied Java Bean by {@linkplain #get(String, 3458 * Set, Converter, BiFunction) acquiring setting values} named after 3459 * the supplied {@link PropertyDescriptor}s and using their 3460 * {@linkplain PropertyDescriptor#getWriteMethod() affiliated write 3461 * methods} to set the corresponding values. 3462 * 3463 * <p>For each {@link PropertyDescriptor} reachable from the 3464 * supplied {@link Iterable}:</p> 3465 * 3466 * <ul> 3467 * 3468 * <li>A <a 3469 * href="{@docRoot}/overview-summary.html#setting_name">setting 3470 * name</a> is synthesized by concatenating the value of the 3471 * supplied {@code prefix} (or the empty string if the supplied 3472 * {@code prefix} is {@code null}) and the return value of the 3473 * {@link PropertyDescriptor#getName()} method.</li> 3474 * 3475 * <li>The {@link PropertyDescriptor} is {@linkplain 3476 * PropertyDescriptor#getWriteMethod() interrogated for a write 3477 * method}. If there is no write method, processing stops.</li> 3478 * 3479 * <li>A {@link Type} is acquired for the (writable) property in 3480 * question by first seeing if it has a {@code propertyType} 3481 * {@linkplain PropertyDescriptor#getValue(String) attribute} set to 3482 * a {@link Type} or a {@link TypeLiteral} (very uncommon) and then 3483 * by using the return value of its {@link 3484 * PropertyDescriptor#getPropertyType()} method.</li> 3485 * 3486 * <li>A {@link Converter} is acquired by first synthesizing one 3487 * wrapped around the return value of the {@link 3488 * PropertyDescriptor#createPropertyEditor(Object)} method, if that 3489 * method returns a non-{@code null} value, and then by {@linkplain 3490 * ConverterProvider#getConverter(Type) retrieving one normally} 3491 * otherwise.</li> 3492 * 3493 * <li>A default value is sought as the {@link String}-typed value 3494 * of the {@link PropertyDescriptor}'s {@code defaultValue} 3495 * {@linkplain PropertyDescriptor#getValue(String) attribute}. If 3496 * the value of that attribute is {@code null} or not a {@link 3497 * String} (very common) then no default value will be used.</li> 3498 * 3499 * <li>The {@link #get(String, Set, Converter, BiFunction)} method 3500 * is called. If the method throws a {@link 3501 * NoSuchElementException}, then processing stops.</li> 3502 * 3503 * <li>The return value from the previous step is passed to an 3504 * invocation of the {@link PropertyDescriptor}'s {@linkplain 3505 * PropertyDescriptor#getWriteMethod() write method} on the supplied 3506 * {@code object}.</li> 3507 * 3508 * </ul> 3509 * 3510 * <p>The net effect is that only writable Java Bean properties for 3511 * which there is a <a 3512 * href="{@docRoot}/overview-summary.html#setting_value">setting 3513 * value</a> will be set to that value.</p> 3514 * 3515 * @param object the {@link Object} to configure; must not be {@code null} 3516 * 3517 * @param propertyDescriptors an {@link Iterable} of {@link 3518 * PropertyDescriptor}s; must not be {@code null} 3519 * 3520 * @param prefix a {@link String} that will be prepended to each 3521 * {@linkplain PropertyDescriptor#getName() 3522 * <code>PropertyDescriptor</code> name} before using the result as 3523 * the name of a setting for which a value {@linkplain #get(String, 3524 * Set, Converter, BiFunction) will be acquired}; may be {@code 3525 * null} 3526 * 3527 * @param qualifiers a {@link Set} of {@link Annotation}s to further 3528 * qualify the selection of values; may be {@code null}; if 3529 * non-{@code null} then this parameter value must be safe for 3530 * concurrent iteration by multiple threads 3531 * 3532 * @exception NullPointerException if either {@code object} or {@code 3533 * propertyDescriptors} is {@code null} 3534 * 3535 * @exception ReflectiveOperationException if there was a problem 3536 * invoking a {@linkplain PropertyDescriptor#getWriteMethod() write 3537 * method}; the supplied {@link Object} may, in this case, be left 3538 * in an inconsistent state 3539 * 3540 * @exception IllegalArgumentException if {@linkplain 3541 * Converter#convert(Value) conversion} could not occur for any 3542 * reason; see {@link Converter#convert(Value)}; the supplied {@link 3543 * Object} may, in this case, be left in an inconsistent state 3544 * 3545 * @exception ConversionException if {@linkplain 3546 * Converter#convert(Value) conversion} could not occur for any 3547 * reason other than bad inputs; the supplied {@link Object} may, in 3548 * this case, be left in an inconsistent state 3549 * 3550 * @exception ValueAcquisitionException if there was a procedural 3551 * problem acquiring a value; the supplied {@link Object} may, in 3552 * this case, be left in an inconsistent state 3553 * 3554 * @exception ArbitrationException if there was a problem performing 3555 * value arbitration; the supplied {@link Object} may, in this case, 3556 * be left in an inconsistent state 3557 * 3558 * @exception AmbiguousValuesException if arbitration completed but 3559 * could not resolve an ambiguity between potential return values; 3560 * the supplied {@link Object} may, in this case, be left in an 3561 * inconsistent state 3562 * 3563 * @exception MalformedValuesException if the {@link 3564 * #handleMalformedValues(String, Set, Collection)} method was 3565 * overridden and the override throws a {@link 3566 * MalformedValuesException}; the supplied {@link Object} may, in 3567 * this case, be left in an inconsistent state 3568 * 3569 * @exception ELException if there was an error related to 3570 * expression language parsing or evaluation; the supplied {@link 3571 * Object} may, in this case, be left in an inconsistent state 3572 * 3573 * @threadsafety This method is safe for concurrent use by multiple 3574 * threads. 3575 * 3576 * @idempotency No guarantees are made with respect to the 3577 * idempotency of this method. 3578 */ 3579 public final void configure(final Object object, 3580 final Iterable<? extends PropertyDescriptor> propertyDescriptors, 3581 final String prefix, 3582 final Set<Annotation> qualifiers) 3583 throws ReflectiveOperationException { 3584 Objects.requireNonNull(object); 3585 Objects.requireNonNull(propertyDescriptors); 3586 for (final PropertyDescriptor pd : propertyDescriptors) { 3587 if (pd != null) { 3588 final String name = pd.getName(); 3589 if (name != null) { 3590 final Method writeMethod = pd.getWriteMethod(); 3591 if (writeMethod != null) { 3592 3593 final String settingName; 3594 if (prefix == null) { 3595 settingName = name; 3596 } else { 3597 settingName = new StringBuilder(prefix).append(name).toString(); 3598 } 3599 3600 final Type type; 3601 final Object typeObject = pd.getValue("propertyType"); 3602 if (typeObject instanceof Type) { 3603 type = (Type)typeObject; 3604 } else if (typeObject instanceof TypeLiteral) { 3605 type = ((TypeLiteral<?>)typeObject).getType(); 3606 } else { 3607 type = pd.getPropertyType(); 3608 } 3609 assert type != null; 3610 3611 final Converter<?> converter; 3612 final PropertyEditor propertyEditor = pd.createPropertyEditor(object); 3613 if (propertyEditor != null && type instanceof Class) { 3614 converter = new PropertyEditorConverter<Object>((Class<?>)type, propertyEditor); 3615 } else { 3616 converter = this.converterProvider.getConverter(type); 3617 } 3618 3619 final BiFunction<? super String, ? super Set<? extends Annotation>, ? extends String> defaultValueFunction; 3620 final Object defaultValue = pd.getValue("defaultValue"); 3621 if (defaultValue instanceof String) { 3622 defaultValueFunction = (n, qs) -> (String)defaultValue; 3623 } else { 3624 defaultValueFunction = null; 3625 } 3626 3627 try { 3628 writeMethod.invoke(object, this.get(settingName, qualifiers, converter, defaultValueFunction)); 3629 } catch (final NoSuchElementException noSuchElementException) { 3630 // That's fine 3631 } 3632 3633 } 3634 } 3635 } 3636 } 3637 } 3638 3639 //---------------------------------------------------------------------------- 3640 3641 /** 3642 * Performs <em>value arbitration</em> on a {@link Collection} of 3643 * {@link Value}s that this {@link Settings} instance determined 3644 * were indistinguishable during value acquisition, and returns the 3645 * {@link Value} to be used instead (normally drawn from the {@link 3646 * Collection} according to some heuristic). 3647 * 3648 * <p>This implementation {@linkplain Iterable#iterator() iterates} 3649 * over the {@link Arbiter} instances {@linkplain #Settings(Set, 3650 * BiFunction, ConverterProvider, Iterable) supplied at construction 3651 * time} and asks each in turn to {@linkplain Arbiter#arbitrate(Set, 3652 * String, Set, Collection) perform value arbitration}. The first 3653 * non-{@code null} value from an {@link Arbiter} is used as the 3654 * return value from this method; otherwise {@code null} is 3655 * returned.</p> 3656 * 3657 * @param sources the {@link Set} of {@link Source}s in effect 3658 * during the current value acquisition operation; must not be 3659 * {@code null}; must be {@linkplain 3660 * Collections#unmodifiableSet(Set) unmodifiable}; must be safe for 3661 * concurrent read-only access by multiple threads 3662 * 3663 * @param name the name of the <a 3664 * href="{@docRoot}/overview-summary.html#setting_value">setting 3665 * value</a> being sought; must not be {@code null} 3666 * 3667 * @param qualifiers the {@link Set} of qualifier {@link 3668 * Annotation}s in effect during the current value acquisition 3669 * operation; must not be {@code null}; must be {@linkplain 3670 * Collections#unmodifiableSet(Set) unmodifiable}; must be safe for 3671 * concurrent read-only access by multiple threads 3672 * 3673 * @param values the {@link Collection} of {@link Value}s acquired 3674 * during the current value acquisition operation that were deemed 3675 * to be indistinguishable; must not be {@code null}; must be 3676 * {@linkplain Collections#unmodifiableSet(Set) unmodifiable}; must 3677 * be safe for concurrent read-only access by multiple threads 3678 * 3679 * @return the result of value arbitration as a single {@link 3680 * Value}, or {@code null} if arbitration could not select a single 3681 * {@link Value} 3682 * 3683 * @see Arbiter 3684 * 3685 * @see Arbiter#arbitrate(Set, String, Set, Collection) 3686 * 3687 * @threadsafety This method is safe for concurrent use by multiple 3688 * threads. 3689 * 3690 * @idempotency No guarantees of any kind are made with respect to 3691 * the idempotency of this method. 3692 * 3693 * @nullability This method may return {@code null}. 3694 */ 3695 protected Value arbitrate(final Set<? extends Source> sources, 3696 final String name, 3697 final Set<Annotation> qualifiers, 3698 final Collection<? extends Value> values) { 3699 final Value returnValue; 3700 Value temp = null; 3701 final Iterable<? extends Arbiter> arbiters = this.arbiters; 3702 if (arbiters == null) { 3703 returnValue = null; 3704 } else { 3705 for (final Arbiter arbiter : arbiters) { 3706 if (arbiter != null) { 3707 temp = arbiter.arbitrate(sources, name, qualifiers, values); 3708 if (temp != null) { 3709 break; 3710 } 3711 } 3712 } 3713 returnValue = temp; 3714 } 3715 return returnValue; 3716 } 3717 3718 /** 3719 * Given a {@link Source}, a name of a setting and a (possibly 3720 * {@code null}) {@link Set} of qualifying {@link Annotation}s, 3721 * returns a {@link Value} for the supplied {@code name} originating 3722 * from the supplied {@link Source}. 3723 * 3724 * <p>The default implementation of this method calls the {@link 3725 * Source#getValue(String, Set)} method on the supplied {@link 3726 * Source}, passing the remaining arguments to it, and returns its 3727 * result.</p> 3728 * 3729 * @param source the {@link Source} of the {@link Value} to be 3730 * returned; must not be {@code null} 3731 * 3732 * @param name the name of the setting for which a {@link Value} is 3733 * to be returned; must not be {@code null} 3734 * 3735 * @param qualifiers an {@link Collections#unmodifiableSet(Set) 3736 * unmodifiable} {@link Set} of qualifying {@link Annotation}s; may 3737 * be {@code null} 3738 * 3739 * @return an appropriate {@link Value}, or {@code null} 3740 * 3741 * @exception NullPointerException if {@code source} or {@code name} 3742 * is {@code null} 3743 * 3744 * @exception UnsupportedOperationException if an override of this 3745 * method attempts to modify the {@code qualifiers} parameter 3746 * 3747 * @exception ValueAcquisitionException if there was an exceptional 3748 * problem acquiring a {@link Value}, but not in the relatively 3749 * common case that an appropriate {@link Value} could not be 3750 * located 3751 * 3752 * @nullability This method and its overrides are permitted to 3753 * return {@code null}. 3754 * 3755 * @idempotency No guarantees of any kind are made with respect to 3756 * the idempotency of this method or its overrides. 3757 * 3758 * @threadsafety This method is and its overrides must be safe for 3759 * concurrent use by multiple threads. 3760 * 3761 * @see Source#getValue(String, Set) 3762 */ 3763 protected Value getValue(final Source source, final String name, final Set<Annotation> qualifiers) { 3764 final Value returnValue; 3765 if (source == this) { 3766 returnValue = null; 3767 } else { 3768 returnValue = source.getValue(name, qualifiers); 3769 } 3770 return returnValue; 3771 } 3772 3773 /** 3774 * Processes a {@link Collection} of {@link Value} instances that 3775 * were determined to be malformed in some way during the execution 3776 * of a {@link #get(String, Set, Converter, BiFunction)} operation. 3777 * 3778 * <p>The default implementation of this method does nothing. 3779 * Overrides may consider throwing a {@link 3780 * MalformedValuesException} instead.</p> 3781 * 3782 * <p>Overrides of this method should not call any of this {@link 3783 * Settings} instance's other methods (especially {@link 3784 * #get(String, Set, Converter, BiFunction)}) as undefined behavior 3785 * or infinite loops may result.</p> 3786 * 3787 * <p>{@link Value} instances in the supplied {@link Collection} of 3788 * {@link Value} instances will be discarded after this method 3789 * completes and are for informational purposes only.</p> 3790 * 3791 * @param name the name of the configuration setting for which a 3792 * {@link Value} is being retrieved by an invocation of the {@link 3793 * #get(String, Set, Converter, BiFunction)} method; must not be 3794 * {@code null} 3795 * 3796 * @param qualifiers an {@linkplain Collections#unmodifiableSet(Set) 3797 * unmodifiable} {@link Set} of qualifier {@link Annotation}s 3798 * qualifying the value retrieval operation; may be {@code null} 3799 * 3800 * @param badValues a non-{@code null} {@linkplain 3801 * Collections#unmodifiableCollection(Collection) unmodifiable} 3802 * {@link Collection} of {@link Value}s that have been determined to 3803 * be malformed in some way 3804 * 3805 * @exception NullPointerException if {@code name} or {@code 3806 * badValues} is {@code null} 3807 * 3808 * @exception UnsupportedOperationException if an override attempts 3809 * to modify either of the {@code qualifiers} or the {@code 3810 * badValues} parameters 3811 * 3812 * @exception MalformedValuesException if processing should abort 3813 * 3814 * @threadsafety This method is and its overrides must be safe for 3815 * concurrent use by multiple threads. 3816 * 3817 * @idempotency No guarantees of any kind are made with respect to 3818 * the idempotency of this method or its overrides. 3819 * 3820 * @see #get(String, Set, Converter, BiFunction) 3821 * 3822 * @see Value 3823 */ 3824 protected void handleMalformedValues(final String name, final Set<Annotation> qualifiers, final Collection<? extends Value> badValues) { 3825 3826 } 3827 3828 private final String interpolate(final String value, 3829 final ELContext elContext, 3830 final ExpressionFactory expressionFactory, 3831 final Set<Annotation> qualifiers) { 3832 Objects.requireNonNull(elContext); 3833 Objects.requireNonNull(expressionFactory); 3834 final String returnValue; 3835 if (value == null) { 3836 returnValue = null; 3837 } else { 3838 String temp = null; 3839 try { 3840 final ValueExpression valueExpression = expressionFactory.createValueExpression(elContext, value, String.class); 3841 assert valueExpression != null; 3842 temp = String.class.cast(valueExpression.getValue(elContext)); 3843 } finally { 3844 returnValue = temp; 3845 } 3846 } 3847 return returnValue; 3848 } 3849 3850 3851 /* 3852 * Static methods. 3853 */ 3854 3855 3856 /* 3857 * Inner and nested classes. 3858 */ 3859 3860 3861 private static final class Key { 3862 3863 private final String name; 3864 3865 private final Set<Annotation> qualifiers; 3866 3867 private Key(final String name, final Set<Annotation> qualifiers) { 3868 super(); 3869 this.name = Objects.requireNonNull(name); 3870 if (qualifiers == null || qualifiers.isEmpty()) { 3871 this.qualifiers = Collections.emptySet(); 3872 } else { 3873 this.qualifiers = Collections.unmodifiableSet(new HashSet<>(qualifiers)); 3874 } 3875 } 3876 3877 private final String getName() { 3878 return this.name; 3879 } 3880 3881 private final Set<Annotation> getQualifiers() { 3882 return this.qualifiers; 3883 } 3884 3885 @Override 3886 public final int hashCode() { 3887 int hashCode = 17; 3888 final Object name = this.getName(); 3889 int c = name == null ? 0 : name.hashCode(); 3890 hashCode = 37 * hashCode + c; 3891 final Collection<?> qualifiers = this.getQualifiers(); 3892 c = qualifiers == null || qualifiers.isEmpty() ? 0 : qualifiers.hashCode(); 3893 hashCode = 37 * hashCode + c; 3894 return hashCode; 3895 } 3896 3897 @Override 3898 public boolean equals(final Object other) { 3899 if (other == this) { 3900 return true; 3901 } else if (other instanceof Key) { 3902 final Key her = (Key)other; 3903 final Object name = this.getName(); 3904 if (name == null) { 3905 if (her.getName() != null) { 3906 return false; 3907 } 3908 } else if (!name.equals(her.getName())) { 3909 return false; 3910 } 3911 final Collection<?> qualifiers = this.getQualifiers(); 3912 if (qualifiers == null || qualifiers.isEmpty()) { 3913 final Collection<?> herQualifiers = her.getQualifiers(); 3914 if (herQualifiers != null && !herQualifiers.isEmpty()) { 3915 return false; 3916 } 3917 } else if (!qualifiers.equals(her.getQualifiers())) { 3918 return false; 3919 } 3920 return true; 3921 } else { 3922 return false; 3923 } 3924 } 3925 3926 } 3927 3928 private static final class SourceELResolver extends ELResolver { 3929 3930 private static final Set<String> MAGIC_NAMES; 3931 3932 static { 3933 MAGIC_NAMES = new HashSet<>(); 3934 MAGIC_NAMES.add("s"); 3935 MAGIC_NAMES.add("settings"); 3936 } 3937 3938 private final Settings settings; 3939 3940 private final ExpressionFactory expressionFactory; 3941 3942 private final Set<Annotation> qualifiers; 3943 3944 private SourceELResolver(final Settings settings, 3945 final Set<Annotation> qualifiers) { 3946 this(settings, 3947 ExpressionFactory.newInstance(), 3948 qualifiers); 3949 } 3950 3951 private SourceELResolver(final Settings settings, 3952 final ExpressionFactory expressionFactory, 3953 final Set<Annotation> qualifiers) { 3954 super(); 3955 this.settings = Objects.requireNonNull(settings); 3956 this.expressionFactory = expressionFactory; 3957 if (qualifiers == null) { 3958 this.qualifiers = Collections.emptySet(); 3959 } else { 3960 this.qualifiers = Collections.unmodifiableSet(qualifiers); 3961 } 3962 } 3963 3964 @Override 3965 public final Class<?> getCommonPropertyType(final ELContext elContext, final Object base) { 3966 return Object.class; 3967 } 3968 3969 @Override 3970 public final Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext elContext, final Object base) { 3971 return Collections.emptyIterator(); 3972 } 3973 3974 @Override 3975 public final boolean isReadOnly(final ELContext elContext, final Object base, final Object property) { 3976 if (elContext != null && (property instanceof String || property instanceof Settings)) { 3977 elContext.setPropertyResolved(true); 3978 } 3979 return true; 3980 } 3981 3982 @Override 3983 public final Class<?> getType(final ELContext elContext, final Object base, final Object property) { 3984 Objects.requireNonNull(elContext); 3985 Class<?> returnValue = null; 3986 if (base == null) { 3987 if (MAGIC_NAMES.contains(property)) { 3988 elContext.setPropertyResolved(true); 3989 returnValue = this.settings.getClass(); 3990 } 3991 } else if (base instanceof Settings && property instanceof String) { 3992 final Settings settings = (Settings)base; 3993 final String value = 3994 settings.get((String)property, 3995 this.qualifiers, 3996 elContext, 3997 this.expressionFactory, 3998 settings.converterProvider.getConverter(String.class), 3999 null); 4000 elContext.setPropertyResolved(true); 4001 if (value == null) { 4002 throw new PropertyNotFoundException((String)property); 4003 } 4004 returnValue = String.class; 4005 } 4006 // Note that as currently written returnValue may be null. 4007 return returnValue; 4008 } 4009 4010 @Override 4011 public final Object getValue(final ELContext elContext, final Object base, final Object property) { 4012 Objects.requireNonNull(elContext); 4013 Object returnValue = null; 4014 if (base == null) { 4015 if (MAGIC_NAMES.contains(property)) { 4016 elContext.setPropertyResolved(true); 4017 returnValue = this.settings; 4018 } 4019 } else if (base instanceof Settings && property instanceof String) { 4020 final Settings settings = (Settings)base; 4021 final String value = 4022 settings.get((String)property, 4023 this.qualifiers, 4024 elContext, 4025 this.expressionFactory, 4026 settings.converterProvider.getConverter(String.class), 4027 null); 4028 elContext.setPropertyResolved(true); 4029 if (value == null) { 4030 throw new PropertyNotFoundException((String)property); 4031 } 4032 returnValue = value; 4033 } 4034 // Note that as currently written returnValue may be null. 4035 return returnValue; 4036 } 4037 4038 @Override 4039 public final void setValue(final ELContext elContext, final Object base, final Object property, final Object value) { 4040 if (elContext != null) { 4041 elContext.setPropertyResolved(false); 4042 } 4043 } 4044 4045 } 4046 4047}