private static void merge(
            final DocumentProperty parent,
            final String key,
            final List<Document> proposed,
            final DocumentConstructor constructor) {

        requireNonNull(parent);
        requireNonNull(key);
        requireNonNull(proposed);
        requireNonNull(constructor);
        
        // Create a list of tasks that should be executed to merge the lists.
        final MergeTaskManager tasks = new MergeTaskManager();
        final ObservableList<DocumentProperty> existing = parent.observableListOf(key);
        
        // Go through every item and create a task for every document
        for (int i = 0; i < Math.max(existing.size(), proposed.size()); i++) {
            
            // If both lists have remaining elements
            if (i < existing.size() && i < proposed.size()) {
                final DocumentProperty first = existing.get(i);
                final Document second = proposed.get(i);
                
                // If they are mentioning the same element, simply merge them 
                // into the same position.
                if (isSame(first, second)) {
                    tasks.add(first.getId(), new MergeWithoutMovingTask(first, second, constructor));
                    
                // if they are mentioning different elements, find the 
                // entities in the other list and create a task for each.
                } else {
                    tasks.add(first.getId(), new MergeIntoExistingTask(first, constructor));
                    tasks.add(HasId.of(second).getId(), new MergeByMovingTask(parent, second, key, constructor));
                }
            } else {
                if (i < existing.size()) {
                    final DocumentProperty first = existing.get(i);
                    tasks.add(first.getId(), new MergeIntoExistingTask(first, constructor));
                } else {
                    final Document second = proposed.get(i);
                    tasks.add(HasId.of(second).getId(), new MergeByMovingTask(parent, second, key, constructor));
                }
            }
        }
        
        // Execute merge
        tasks.execute(existing);
    }
Merges the specified document on the specified key with a specified list
of proposed children. If a new {@link DocumentProperty} needs to be
created, the specified constructor is used.

@param parent       the parent to merge into
@param key          the key to merge on
@param proposed     the documents to merge with
@param constructor  used to create new {@link DocumentProperty}
tool-parent/tool-config/src/main/java/com/speedment/tool/config/util/DocumentMerger.java