private void evaluateArray(Object target) throws ModelInterpolationException {
      int len = Array.getLength(target);
      for (int i = 0; i < len; i++) {
        Object value = Array.get(target, i);
        if (value != null) {
          if (String.class == value.getClass()) {
            String interpolated =
                modelInterpolator.interpolateInternal(
                    (String) value, valueSources, postProcessors, debugEnabled);

            if (!interpolated.equals(value)) {
              Array.set(target, i, interpolated);
            }
          } else {
            interpolationTargets.add(value);
          }
        }
      }
    }
    @SuppressWarnings("unchecked")
    private void traverseObjectWithParents(Class<?> cls, Object target)
        throws ModelInterpolationException {
      if (cls == null) {
        return;
      }

      if (cls.isArray()) {
        evaluateArray(target);
      } else if (isQualifiedForInterpolation(cls)) {
        Field[] fields = FIELDS_BY_CLASS.get(cls);
        if (fields == null) {
          fields = cls.getDeclaredFields();
          FIELDS_BY_CLASS.put(cls, fields);
        }

        for (Field field : fields) {
          Class<?> type = field.getType();
          if (isQualifiedForInterpolation(field, type)) {
            boolean isAccessible = field.isAccessible();
            field.setAccessible(true);
            try {
              try {
                if (String.class == type) {
                  String value = (String) field.get(target);
                  if (value != null) {
                    String interpolated =
                        modelInterpolator.interpolateInternal(
                            value, valueSources, postProcessors, debugEnabled);

                    if (!interpolated.equals(value)) {
                      field.set(target, interpolated);
                    }
                  }
                } else if (Collection.class.isAssignableFrom(type)) {
                  Collection<Object> c = (Collection<Object>) field.get(target);
                  if (c != null && !c.isEmpty()) {
                    List<Object> originalValues = new ArrayList<>(c);
                    try {
                      c.clear();
                    } catch (UnsupportedOperationException e) {
                      if (debugEnabled && logger != null) {
                        logger.debug(
                            "Skipping interpolation of field: "
                                + field
                                + " in: "
                                + cls.getName()
                                + "; it is an unmodifiable collection.");
                      }
                      continue;
                    }

                    for (Object value : originalValues) {
                      if (value != null) {
                        if (String.class == value.getClass()) {
                          String interpolated =
                              modelInterpolator.interpolateInternal(
                                  (String) value, valueSources, postProcessors, debugEnabled);

                          if (!interpolated.equals(value)) {
                            c.add(interpolated);
                          } else {
                            c.add(value);
                          }
                        } else {
                          c.add(value);
                          if (value.getClass().isArray()) {
                            evaluateArray(value);
                          } else {
                            interpolationTargets.add(value);
                          }
                        }
                      } else {
                        // add the null back in...not sure what else to do...
                        c.add(value);
                      }
                    }
                  }
                } else if (Map.class.isAssignableFrom(type)) {
                  Map<Object, Object> m = (Map<Object, Object>) field.get(target);
                  if (m != null && !m.isEmpty()) {
                    for (Map.Entry<Object, Object> entry : m.entrySet()) {
                      Object value = entry.getValue();

                      if (value != null) {
                        if (String.class == value.getClass()) {
                          String interpolated =
                              modelInterpolator.interpolateInternal(
                                  (String) value, valueSources, postProcessors, debugEnabled);

                          if (!interpolated.equals(value)) {
                            try {
                              entry.setValue(interpolated);
                            } catch (UnsupportedOperationException e) {
                              if (debugEnabled && logger != null) {
                                logger.debug(
                                    "Skipping interpolation of field: "
                                        + field
                                        + " (key: "
                                        + entry.getKey()
                                        + ") in: "
                                        + cls.getName()
                                        + "; it is an unmodifiable collection.");
                              }
                            }
                          }
                        } else {
                          if (value.getClass().isArray()) {
                            evaluateArray(value);
                          } else {
                            interpolationTargets.add(value);
                          }
                        }
                      }
                    }
                  }
                } else {
                  Object value = field.get(target);
                  if (value != null) {
                    if (field.getType().isArray()) {
                      evaluateArray(value);
                    } else {
                      interpolationTargets.add(value);
                    }
                  }
                }
              } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new ModelInterpolationException(
                    "Failed to interpolate field: " + field + " on class: " + cls.getName(), e);
              }
            } finally {
              field.setAccessible(isAccessible);
            }
          }
        }

        traverseObjectWithParents(cls.getSuperclass(), target);
      }
    }