uk.ac.starlink.util

## Class BeanConfig

- java.lang.Object
- - uk.ac.starlink.util.BeanConfig

-     public class BeanConfig
      extends java.lang.Object

  Utility class for configuring dynamically loaded objects.

  The idea is that objects can be configured from user-supplied text strings that configure bean-like properties. For instance an object may be specified on the command line or using a system property with a syntax like:

          "java.util.Date(year=212,day=1)"

  which would construct a Date object using its no-arg constructor, and then configure the bean-like "year" property by reflectively invoking the `setYear` and `setDay` methods of the Date class.

  Where present, a `ConfigMethod` annotation on the relevant mutator methods is used to provide aliased property names, as well as to improve LoadException error messages when property setting fails.

  The configuration syntax is fairly straightforward; the format is a comma-separated list of `name=value` settings within a pair of parentheses. Supplied string values are interpreted using the following rules:

  - Obvious serializations are supported for numeric and boolean values.
  - Hexadecimal representations (0xNNN) are allowed for integers.
  - Numeric and boolean wrapper types are supported in the same way as primitives (though null is permitted).
  - String values are unquoted; commas may be backslash-escaped.
  - The empty string or "`null`" represents null.
  - Enum instances are matched case-insensitively.
  - Static public members of a required class implementing that class are matched case-insensitively
  - If a static public `valueOf(String)` method returning instances of the required class is present on that class, the supplied value string is fed to it.
  - If a static public `to<ReqClass>Instance(String)` method, where `<ReqClass>` is the unqualified name of the required class, exists on the context class, the supplied value string is fed to it.
  If none of these succeeds in producing a non-null value, and a null value has not been explicitly requested, an error results.
  Since:
    11 Sep 2020
  See Also:
    `ConfigMethod`

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class and Description
    --- | ---
    `static class` | `BeanConfig.Setting` Represents an object configuration operation.

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `BeanConfig(java.lang.String baseTxt, java.lang.String configTxt)` Constructs a BeanConfig with a basic object representation and a string providing configuration information.

  - ### Method Summary

    All Methods Static Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `static void` | `applySetting(java.lang.Object target, BeanConfig.Setting setting)` Applies a given setting to an object.
    `void` | `configBean(java.lang.Object target)` Attempts to apply this object's configuration setttings to a supplied target object.
    `static <T> T` | `decodeTypedValue(java.lang.Class<T> clazz, java.lang.String txt, java.lang.Object target)` Attempts to interpret a string as an instance of a given class.
    `java.lang.String` | `getBaseText()` Returns the basic object name for this object.
    `java.lang.String` | `getConfigText()` Returns configuration specification.
    `static java.lang.String` | `getMethodUsage(java.lang.reflect.Method configMethod)` Returns a usage string corresponding to a given configuration method.
    `BeanConfig.Setting[]` | `getSettings()` Returns the parsed settings for this object, as extracted from the configuration text.
    `static void` | `main(java.lang.String[] args)`
    `static BeanConfig` | `parseSpec(java.lang.String txt)` Parses an object specification to produce a BeanConfig instance.

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### BeanConfig

          public BeanConfig(java.lang.String baseTxt,
                            java.lang.String configTxt)

      Constructs a BeanConfig with a basic object representation and a string providing configuration information. The baseTxt could be a classname or something else. The configTxt should normally be of the form `name1=value1,name2=value2,...`; if other forms are used, a LoadException with a helpful error message will be generated as appropriate by relevant method invocations.
      Parameters:
        `baseTxt` - basic object name or representation
        `configTxt` - configuration text, normally as supplied in trailing parenthesis

  - ### Method Detail

    - #### getBaseText

          public java.lang.String getBaseText()

      Returns the basic object name for this object. May be a classname or something else. This should not be null.
      Returns:
        basic representation

    - #### getConfigText

          public java.lang.String getConfigText()

      Returns configuration specification. May be null if there was no trailing parenthesis.
      Returns:
        configuration text, nominally of the form "n1=v1,n2=v2,...",

    - #### getSettings

          public BeanConfig.Setting[] getSettings()
                                           throws LoadException

      Returns the parsed settings for this object, as extracted from the configuration text. The list may be empty.
      Returns:
        configuration settings
      Throws:
        `LoadException` - if the config text was badly-formed

    - #### configBean

          public void configBean(java.lang.Object target)
                          throws LoadException

      Attempts to apply this object's configuration setttings to a supplied target object.
      Parameters:
        `target` - object to configure
      Throws:
        `LoadException` - with a helpful error message if the settings don't work

    - #### parseSpec

          public static BeanConfig parseSpec(java.lang.String txt)

      Parses an object specification to produce a BeanConfig instance. The specification is of the form `base-name(n1=v1,n2=v2,...)`. If there is no well-formed parenthesised config-string at the end, the returned object has a base-name that is the whole of the input string, and no config text.
      Parameters:
        `txt` - input text
      Returns:
        BaseConfig object, which may or may not have configuration information

    - #### applySetting

          public static void applySetting(java.lang.Object target,
                                          BeanConfig.Setting setting)
                                   throws java.lang.ReflectiveOperationException

      Applies a given setting to an object.
      Parameters:
        `target` - object to configure
        `setting` - setting to apply
      Throws:
        `java.lang.RuntimeException` - in case of various problems with converting the supplied string to the required type
        `java.lang.ReflectiveOperationException` - in case of some reflection trouble

    - #### getMethodUsage

          public static java.lang.String getMethodUsage(java.lang.reflect.Method configMethod)

      Returns a usage string corresponding to a given configuration method.
      Parameters:
        `configMethod` - mutator method
      Returns:
        short user-directed usage text

    - #### decodeTypedValue

          public static <T> T decodeTypedValue(java.lang.Class<T> clazz,
                                               java.lang.String txt,
                                               java.lang.Object target)

      Attempts to interpret a string as an instance of a given class.
      Parameters:
        `clazz` - required output class
        `txt` - text representation of value
        `target` - object in the context of which interpretation is done
      Returns:
        value of required type, or null
      Throws:
        `java.lang.RuntimeException` - if decoding is unsuccessful

    - #### main

          public static void main(java.lang.String[] args)
                           throws java.lang.ReflectiveOperationException,
                                  LoadException

      Throws:
        `java.lang.ReflectiveOperationException`
        `LoadException`