public static List<String> getCLIOptions(final Object currOptions, final Object defaults) {
    final List<String> cliOpts = new ArrayList<>();
    final Field[] fields = currOptions.getClass().getDeclaredFields();
    for (Field field : fields) {
      field.setAccessible(true);
      Annotation ann = field.getAnnotation(CommandLine.Option.class);
      if (ann != null) {
        try {
          var optVal = field.get(currOptions);
          if (!Objects.equals(optVal, field.get(defaults))) {
            var optAnn = CommandLine.Option.class.cast(ann);
            final var optConverter = optAnn.converter();
            cliOpts.add(optAnn.names()[0] + "=" + formatValue(optConverter, optVal));
          }
        } catch (IllegalAccessException e) {
          throw new RuntimeException(e);
        }
      } else {
        ann = field.getAnnotation(CommandLine.ArgGroup.class);
        if (ann != null) {
          try {
            cliOpts.addAll(getCLIOptions(field.get(currOptions), field.get(defaults)));
          } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
          }
        }
      }
    }
    return cliOpts;
  }
Converts the runtime options into their CLI representation. Options with a value equals to its
default are not included in the result since redundant. Note this will recursively check in any
inner option class if present.

@param currOptions the actual runtime options
@param defaults the default option values
@return a list of CLI arguments
app/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java