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}