/**
   * Evaluate the initial keys fromMap the configuration and applyChanges it to the field.
   *
   * @param target the target instance.
   * @throws ConfigException if evaluation or conversion failed.
   */
  public void applyValue(Object target, boolean resolve) throws ConfigException {
    String configValue = InjectionUtils.getConfigValue(this.setterMethod);
    Objects.requireNonNull(target);
    try {
      String evaluatedString =
          resolve && configValue != null ? InjectionUtils.evaluateValue(configValue) : configValue;

      // Check for adapter/filter
      Object value =
          InjectionUtils.adaptValue(
              this.setterMethod,
              TypeLiteral.of(this.setterMethod.getParameterTypes()[0]),
              evaluatedString);

      AccessController.doPrivileged(
          new PrivilegedExceptionAction<Object>() {
            @Override
            public Object run() throws Exception {
              setterMethod.setAccessible(true);
              return setterMethod;
            }
          });

      setterMethod.invoke(target, value);
    } catch (Exception e) {
      throw new ConfigException(
          "Failed to annotation configured method: "
              + this.setterMethod.getDeclaringClass().getName()
              + '.'
              + setterMethod.getName(),
          e);
    }
  }
  @SuppressWarnings("rawtypes")
  public static <T> T adaptValue(
      AnnotatedElement element, TypeLiteral<T> targetType, String key, String configValue) {
    // Check for adapter/filter
    T adaptedValue = null;
    WithPropertyConverter converterAnnot = element.getAnnotation(WithPropertyConverter.class);
    Class<? extends PropertyConverter<T>> converterType;
    if (converterAnnot != null) {
      converterType = (Class<? extends PropertyConverter<T>>) converterAnnot.value();
      if (!converterType.getName().equals(WithPropertyConverter.class.getName())) {
        try {
          // TODO cache here...
          ConversionContext ctx =
              new ConversionContext.Builder(key, targetType).setAnnotatedElement(element).build();

          PropertyConverter<T> converter =
              PropertyConverter.class.cast(converterType.newInstance());
          adaptedValue = converter.convert(configValue, ctx);
        } catch (Exception e) {
          LOG.log(
              Level.SEVERE,
              "Failed to convert using explicit PropertyConverter on "
                  + element
                  + ", trying default conversion.",
              e);
        }
      }
    }
    if (adaptedValue != null) {
      return adaptedValue;
    }
    if (String.class == targetType.getType()) {
      return (T) configValue;
    } else {
      List<PropertyConverter<T>> converters =
          ConfigurationProvider.getConfigurationContext().getPropertyConverters(targetType);
      ConversionContext ctx =
          new ConversionContext.Builder(ConfigurationProvider.getConfiguration(), key, targetType)
              .setAnnotatedElement(element)
              .build();
      for (PropertyConverter<T> converter : converters) {
        adaptedValue = converter.convert(configValue, ctx);
        if (adaptedValue != null) {
          return adaptedValue;
        }
      }
      throw new ConfigException("Non convertible property type: " + element);
    }
  }