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); } }