class InterpolateObjectAction implements PrivilegedAction<ModelInterpolationException> {

        private final boolean debugEnabled;
        private final LinkedList<Object> interpolationTargets;
        private final StringSearchModelInterpolator modelInterpolator;
        private final Logger logger;
        private final List<ValueSource> valueSources;
        private final List<InterpolationPostProcessor> postProcessors;

        InterpolateObjectAction(
                Object target,
                List<ValueSource> valueSources,
                List<InterpolationPostProcessor> postProcessors,
                boolean debugEnabled,
                StringSearchModelInterpolator modelInterpolator,
                Logger logger) {
            this.valueSources = valueSources;
            this.postProcessors = postProcessors;
            this.debugEnabled = debugEnabled;

            this.interpolationTargets = new LinkedList<>();
            interpolationTargets.add(target);

            this.modelInterpolator = modelInterpolator;
            this.logger = logger;
        }

        public ModelInterpolationException run() {
            while (!interpolationTargets.isEmpty()) {
                Object obj = interpolationTargets.removeFirst();

                try {
                    traverseObjectWithParents(obj.getClass(), obj);
                } catch (ModelInterpolationException e) {
                    return e;
                }
            }

            return null;
        }

        @SuppressWarnings({"unchecked", "checkstyle:methodlength"})
        private void traverseObjectWithParents(Class<?> cls, Object target) throws ModelInterpolationException {<FILL_FUNCTION_BODY>}

        private boolean isQualifiedForInterpolation(Class<?> cls) {
            return !cls.getPackage().getName().startsWith("java")
                    && !cls.getPackage().getName().startsWith("sun.nio.fs");
        }

        private boolean isQualifiedForInterpolation(Field field, Class<?> fieldType) {
            if (!PRIMITIVE_BY_CLASS.containsKey(fieldType)) {
                PRIMITIVE_BY_CLASS.put(fieldType, fieldType.isPrimitive());
            }

            if (PRIMITIVE_BY_CLASS.get(fieldType)) {
                return false;
            }

            //            if ( fieldType.isPrimitive() )
            //            {
            //                return false;
            //            }

            return !"parent".equals(field.getName());
        }

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

            if (cls == null) {
                return;
            }

            if (cls.isArray()) {
                evaluateArray(target);
            } else if (isQualifiedForInterpolation(cls)) {
                Field[] fields = FIELDS_BY_CLASS.computeIfAbsent(cls, k -> cls.getDeclaredFields());

                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);
            }
        
<methods>public void initialize() throws org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException,public Model interpolate(Model, Map<java.lang.String,?>) throws org.apache.maven.project.interpolation.ModelInterpolationException,public Model interpolate(Model, Map<java.lang.String,?>, boolean) throws org.apache.maven.project.interpolation.ModelInterpolationException,public Model interpolate(Model, java.io.File, org.apache.maven.project.ProjectBuilderConfiguration, boolean) throws org.apache.maven.project.interpolation.ModelInterpolationException,public java.lang.String interpolate(java.lang.String, Model, java.io.File, org.apache.maven.project.ProjectBuilderConfiguration, boolean) throws org.apache.maven.project.interpolation.ModelInterpolationException<variables>private static final List<java.lang.String> PROJECT_PREFIXES,private static final non-sealed List<java.lang.String> TRANSLATED_PATH_EXPRESSIONS,private Interpolator interpolator,private org.apache.maven.project.path.PathTranslator pathTranslator,private RecursionInterceptor recursionInterceptor