All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atlasmap.java.core.DocumentJavaFieldWriter Maven / Gradle / Ivy

/**
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.atlasmap.java.core;

import java.beans.beancontext.BeanContext;
import java.beans.beancontext.BeanContextServices;
import java.beans.beancontext.BeanContextServicesSupport;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;

import org.slf4j.LoggerFactory;

import io.atlasmap.api.AtlasConversionService;
import io.atlasmap.api.AtlasException;
import io.atlasmap.core.AtlasPath;
import io.atlasmap.core.AtlasPath.SegmentContext;
import io.atlasmap.core.DefaultAtlasConversionService;
import io.atlasmap.java.inspect.ClassHelper;
import io.atlasmap.java.v2.JavaEnumField;
import io.atlasmap.java.v2.JavaField;
import io.atlasmap.spi.AtlasFieldWriter;
import io.atlasmap.spi.AtlasInternalSession;
import io.atlasmap.v2.Field;
import io.atlasmap.v2.FieldType;
import io.atlasmap.v2.LookupTable;

public class DocumentJavaFieldWriter implements AtlasFieldWriter {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(DocumentJavaFieldWriter.class);

    private Object rootObject = null;
    private Map> classesForFields = new HashMap<>();
    private JavaWriterUtil writerUtil = new JavaWriterUtil(DefaultAtlasConversionService.getInstance());
    private List processedPaths = new LinkedList<>();
    private TargetValueConverter converter;
    private AtlasConversionService conversionService;
    private Map, Class> defaultCollectionImplClasses = new HashMap<>();

    public DocumentJavaFieldWriter(AtlasConversionService conversion) {
        this.conversionService = conversion;
        defaultCollectionImplClasses.put(BeanContext.class, BeanContextServicesSupport.class);
        defaultCollectionImplClasses.put(BeanContextServices.class, BeanContextServicesSupport.class);
        defaultCollectionImplClasses.put(BlockingDeque.class, LinkedBlockingDeque.class);
        defaultCollectionImplClasses.put(BlockingQueue.class, LinkedBlockingQueue.class);
        defaultCollectionImplClasses.put(Collection.class, LinkedList.class);
        defaultCollectionImplClasses.put(ConcurrentMap.class, ConcurrentHashMap.class);
        defaultCollectionImplClasses.put(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
        defaultCollectionImplClasses.put(Deque.class, ArrayDeque.class);
        defaultCollectionImplClasses.put(List.class, LinkedList.class);
        defaultCollectionImplClasses.put(Map.class, HashMap.class);
        defaultCollectionImplClasses.put(NavigableSet.class, TreeSet.class);
        defaultCollectionImplClasses.put(NavigableMap.class, TreeMap.class);
        defaultCollectionImplClasses.put(Queue.class, LinkedList.class);
        defaultCollectionImplClasses.put(Set.class, HashSet.class);
        defaultCollectionImplClasses.put(SortedSet.class, TreeSet.class);
        defaultCollectionImplClasses.put(SortedMap.class, TreeMap.class);
        defaultCollectionImplClasses.put(TransferQueue.class, LinkedTransferQueue.class);
    }

    public void write(AtlasInternalSession session) throws AtlasException {
        LookupTable lookupTable = session.head().getLookupTable();
        Field sourceField = session.head().getSourceField();
        Field targetField = session.head().getTargetField();

        try {
            if (targetField == null) {
                throw new AtlasException(new IllegalArgumentException("Argument 'field' cannot be null"));
            }

            String targetFieldClassName = (targetField instanceof JavaField) ? ((JavaField) targetField).getClassName()
                    : ((JavaEnumField) targetField).getClassName();
            if (LOG.isDebugEnabled()) {
                LOG.debug("Now processing field: " + targetField);
                LOG.debug("Field type: " + targetField.getFieldType());
                LOG.debug("Field path: " + targetField.getPath());
                LOG.debug("Field value: " + targetField.getValue());
                LOG.debug("Field className: " + targetFieldClassName);
            }

            processedPaths.add(targetField.getPath());

            AtlasPath path = new AtlasPath(targetField.getPath());
            Object parentObject = rootObject;
            boolean segmentIsComplexSegment = true;
            for (SegmentContext segmentContext : path.getSegmentContexts(true)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Now processing segment: " + segmentContext);
                    LOG.debug("Parent object is currently: " + writeDocumentToString(false, parentObject));
                }

                if ("/".equals(segmentContext.getSegmentPath())) {
                    if (rootObject == null) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Creating root node: " + segmentContext);
                        }
                        rootObject = createParentObject(targetField, parentObject, segmentContext);
                    } else {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Root node already exists, skipping segment: " + segmentContext);
                        }
                    }
                    parentObject = rootObject;
                    continue;
                }

                // if we're on the last segment, the
                boolean segmentIsLastSegment = (segmentContext.getNext() == null);
                if (segmentIsLastSegment) {
                    // detect field type from class name if exists
                    if (targetField.getFieldType() == null && targetFieldClassName != null
                            && (targetField instanceof JavaField)) {
                        FieldType fieldTypeFromClass = conversionService.fieldTypeFromClass(targetFieldClassName);
                        targetField.setFieldType(fieldTypeFromClass);
                    }
                    if (FieldType.COMPLEX.equals(targetField.getFieldType())) {
                        segmentIsComplexSegment = true;
                    } else {
                        segmentIsComplexSegment = false;
                    }
                    if (targetField instanceof JavaEnumField) {
                        segmentIsComplexSegment = false;
                    }
                }
                if (LOG.isDebugEnabled()) {
                    if (segmentIsComplexSegment) {
                        LOG.debug("Now processing complex segment: " + segmentContext);
                    } else if (targetField instanceof JavaEnumField) {
                        LOG.debug("Now processing field enum value segment: " + segmentContext);
                    } else {
                        LOG.debug("Now processing field value segment: " + segmentContext);
                    }
                }

                if (segmentIsComplexSegment) { // processing parent object
                    Object childObject = findChildObject(targetField, segmentContext, parentObject);

                    if (childObject == null) {
                        childObject = createParentObject(targetField, parentObject, segmentContext);
                    }
                    parentObject = childObject;
                } else { // processing field value
                    if (AtlasPath.isCollectionSegment(segmentContext.getSegment())) {
                        parentObject = findOrCreateOrExpandParentCollectionObject(targetField, parentObject, segmentContext);
                    }
                    Object value = converter.convert(session, lookupTable, sourceField, parentObject, targetField);
                    addChildObject(targetField, segmentContext, parentObject, value);
                }
            }
        } catch (Throwable t) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Error occured while writing field: " + targetField.getPath(), t);
            }
            if (t instanceof AtlasException) {
                throw (AtlasException) t;
            }
            throw new AtlasException(t);
        }
    }

    private Object findChildObject(Field field, SegmentContext segmentContext, Object parentObject)
            throws AtlasException {
        if (parentObject == null) {
            if (this.rootObject != null && segmentContext.getSegmentPath().equals("/")) {
                return this.rootObject;
            }
            return null;
        }

        String segment = segmentContext.getSegment();
        String parentSegment = segmentContext.getPrev() == null ? null : segmentContext.getPrev().getSegment();
        if (LOG.isDebugEnabled()) {
            LOG.debug("Looking for child object '" + segment + "' in parent '" + parentSegment + "': "
                    + writeDocumentToString(false, parentObject));
        }

        // find the child object on the given parent
        Object childObject = writerUtil.getObjectFromParent(field, parentObject, segmentContext);
        if (childObject != null && AtlasPath.isCollectionSegment(segment)) {
            if (!collectionHasRoomForIndex(childObject, segmentContext)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Found child collection '" + segment + "' (" + childObject.getClass().getName()
                            + ") in parent '" + parentSegment
                            + "', but it doesn't have room for the segment's index. Parent Object: "
                            + writeDocumentToString(false, parentObject));
                }
                return null;
            }
            childObject = getCollectionItem(childObject, segmentContext);
        }

        if (LOG.isDebugEnabled()) {
            if (childObject == null) {
                LOG.debug("Could not find child object '" + segment + "' in parent '" + parentSegment + "'.");
            } else {
                LOG.debug("Found child object '" + segment + "' in parent '" + parentSegment + "', class: "
                        + childObject.getClass().getName() + ", child object: "
                        + writeDocumentToString(false, childObject));
            }
        }

        return childObject;
    }

    private Object createParentObject(Field field, Object parentObject, SegmentContext segmentContext)
            throws AtlasException {
        String segment = segmentContext.getSegment();
        if (LOG.isDebugEnabled()) {
            LOG.debug("Creating parent object: " + segmentContext);
        }
        Object childObject = null;
        if (AtlasPath.isCollectionSegment(segment)) {
            // first, let's see if we have the collection object at all
            if (LOG.isDebugEnabled()) {
                LOG.debug("Looking for collection wrapper child for " + segmentContext + " on parent: " + parentObject);
            }
            Object collectionObject = findOrCreateOrExpandParentCollectionObject(field, parentObject, segmentContext);
            childObject = getCollectionItem(collectionObject, segmentContext);

            if (childObject == null) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Could not find child object in collection, creating it.");
                }
                childObject = createObject(field, segmentContext, parentObject, false);
                addChildObject(field, segmentContext, collectionObject, childObject);
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug("Child object inside collection wrapper for segment '" + segment + "': "
                        + writeDocumentToString(false, childObject));
            }
        } else {
            childObject = createObject(field, segmentContext, parentObject, false);
            addChildObject(field, segmentContext, parentObject, childObject);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug(
                    "Created child object for segment '" + segment + "': " + writeDocumentToString(true, childObject));
        }
        return childObject;
    }

    private Object findOrCreateOrExpandParentCollectionObject(Field field, Object parentObject,
            SegmentContext segmentContext) throws AtlasException {
        String segment = segmentContext.getSegment();
        // first, let's see if we have the collection object at all
        if (LOG.isDebugEnabled()) {
            LOG.debug("Looking for collection wrapper child for " + segmentContext + " on parent: " + parentObject);
        }
        Object collectionObject = writerUtil.getObjectFromParent(field, parentObject, segmentContext);
        if (collectionObject == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Cannot find pre-existing child collection for segment '" + segment
                        + "', creating the collection.");
            }
            Class collectionClass = writerUtil.resolveClassFromParent(field, parentObject, segmentContext);
            collectionObject = createCollectionWrapperObject(field, segmentContext, parentObject, collectionClass);
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Collection wrapper child object for segment '" + segment + "': "
                    + writeDocumentToString(false, collectionObject));
        }

        collectionObject = expandCollectionToFitItem(field, collectionObject, segmentContext, parentObject);
        addChildObject(field, segmentContext, parentObject, collectionObject);

        return collectionObject;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private Object expandCollectionToFitItem(Field field, Object obj, SegmentContext segmentContext,
            Object parentObject) throws AtlasException {
        Object collectionObject = obj;
        String segment = segmentContext.getSegment();
        if (!collectionHasRoomForIndex(collectionObject, segmentContext)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Collection is not large enough for segment '" + segment + "', expanding the collection.");
            }
            int index = AtlasPath.indexOfSegment(segment);
            if (collectionObject instanceof Collection) {
                Collection collection = (Collection) collectionObject;
                while (collection.size() < index) {
                    int preSize = collection.size();
                    collection.add(null);
                    if (collection.size() == preSize) {
                        LOG.warn(String.format(
                                "This collection field doesn't allow filling with null - index will be ignored. "
                                + "segment: %s \n\tparentObject: %s",
                                segmentContext, parentObject));
                        break;
                    }
                }
            } else if (collectionObject instanceof Map) {
                throw new AtlasException("FIXME: Cannot yet handle adding children to maps");
            } else if (collectionObject.getClass().isArray()) {
                if (Array.getLength(collectionObject) < (index + 1)) {
                    // resize the array to fit the item
                    Object newArray = createObject(field, segmentContext, parentObject, true);
                    // copy pre-existing items over to new array
                    for (int i = 0; i < Array.getLength(collectionObject); i++) {
                        Array.set(newArray, i, Array.get(collectionObject, i));
                    }
                    collectionObject = newArray;
                }
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug("Finished expanding collection: " + collectionObject);
            }
        }
        return collectionObject;
    }

    private Object createCollectionWrapperObject(Field field, SegmentContext segmentContext, Object parentObject,
            Class collectionClass) throws AtlasException {
        // create the "List" part of List
        String segment = segmentContext.getSegment();
        if (AtlasPath.isArraySegment(segment)) {
            return createObject(field, segmentContext, parentObject, true);
        }

        if (collectionClass == null) {
            throw new AtlasException(String.format(
                    "Null collection class is specified for segment: %s", segmentContext));
        }

        if (AtlasPath.isListSegment(segment)) {
            return writerUtil.instantiateObject(
                    resolveCollectionImplClass(collectionClass), segmentContext, false);
        } else if (AtlasPath.isMapSegment(segment)) {
            return writerUtil.instantiateObject(
                    resolveCollectionImplClass(collectionClass), segmentContext, false);
        }
        throw new AtlasException("Can't create collection object for segment: " + segmentContext);
    }

    private Class resolveCollectionImplClass(Class collectionClass) throws AtlasException {
        if (collectionClass.isInterface() || Modifier.isAbstract(collectionClass.getModifiers())) {
            Class implClass = this.defaultCollectionImplClasses.get(collectionClass);
            if (implClass == null) {
                throw new AtlasException(String.format(
                        "Abstract collection class/interface %s can't be instantiated and default implementation class was not found",
                        collectionClass.getCanonicalName()));
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug("Resolved default impl class: {} -> {}", collectionClass.getCanonicalName(), implClass.getCanonicalName());
            }
            return implClass;
        }
        return collectionClass;
    }

    private Class getClassForField(Field field, SegmentContext segmentContext, Object parentObject,
            boolean unwrapCollectionType) throws AtlasException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Looking up class to use for segment: " + segmentContext + "\n\tparentObject: " + parentObject);
        }
        Class clz = null;

        if (LOG.isDebugEnabled()) {
            LOG.debug("Looking for configured class for field: " + field + ".");
        }
        String className = null;
        if (field instanceof JavaField) {
            className = ((JavaField) field).getClassName();
        } else if (field instanceof JavaEnumField) {
            className = ((JavaEnumField) field).getClassName();
        }
        if (className != null) {
            try {
                clz = className == null ? null : Class.forName(className);
            } catch (Exception e) {
                throw new AtlasException("Could not find class for '" + className + "', for segment: " + segmentContext
                        + ", on field: " + field, e);
            }
        }

        if (clz == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Couldn't find class on field. Looking for configured class for segment: " + segmentContext
                        + ".");
            }
            String normalizedSegment = AtlasPath.removeCollectionIndexes(segmentContext.getSegmentPath());
            clz = this.classesForFields.get(normalizedSegment);
        }
        Type clzType = null;
        if (clz == null) { // attempt to determine it from the parent object.
            if (LOG.isDebugEnabled()) {
                LOG.debug("Couldn't find configured class for segment: " + segmentContext
                        + ", looking up getter method.");
            }
            Method m = null;
            try {
                String methodName = "get"
                        + JavaWriterUtil.capitalizeFirstLetter(AtlasPath.cleanPathSegment(segmentContext.getSegment()));
                m = ClassHelper.detectGetterMethod(parentObject.getClass(), methodName);
            } catch (NoSuchMethodException e) {
                // it's ok, we didnt find a getter.
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Couldn't find getter method for segment: " + segmentContext, e);
                }
            }
            clz = m == null ? null : m.getReturnType();
            clzType = m.getGenericReturnType();
        }
        if (clz == null) {
            throw new AtlasException(
                    "Could not create object, can't find class to instantiate for segment: " + segmentContext);
        }

        if (unwrapCollectionType) {
            clz = unwrapCollectionType(field, segmentContext, parentObject, clz, clzType);
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Found class '" + clz.getName() + "' to use for segment: " + segmentContext);
        }
        return clz;
    }

    private Class unwrapCollectionType(Field field, SegmentContext segmentContext,
            Object parentObject, Class clz, Type clzType) throws AtlasException {
        Class answer = clz;
        if (answer.isArray()) {
            Class oldClass = answer;
            answer = answer.getComponentType();
            if (LOG.isDebugEnabled()) {
                LOG.debug(
                        "Unwrapped type '" + answer.getName() + "' from wrapper array type '" + oldClass.getName() + "'.");
            }
        } else if (Collection.class.isAssignableFrom(answer)) {
            Class oldClass = answer;
            answer = null;
            String cleanedSegment = AtlasPath.cleanPathSegment(segmentContext.getSegment());

            // From return type of getter method
            if (clzType instanceof Class) {
                // No type parameter, use Object
                answer = Object.class;
            } else if (clzType instanceof ParameterizedType){
                ParameterizedType pt = (ParameterizedType) clzType;
                String typeName = pt.getActualTypeArguments()[0].getTypeName();
                try {
                    answer = typeName == null ? null : Class.forName(typeName);
                } catch (Exception e) {
                    throw new AtlasException("Could not find class for '" + typeName + "', for segment: "
                            + segmentContext + ", on field: " + field, e);
                }

            // No getter found - check fields of parent object
            } else if (answer == null) {
                Class parentClass = parentObject.getClass();
                while (parentClass != Object.class && answer == null) {
                    answer = findClassOfNamedField(parentClass, cleanedSegment);
                    parentClass = parentClass.getSuperclass();
                }
            }

            if (answer == null) {
                throw new AtlasException(
                        "Could not unwrap list collection's generic type for segment: " + segmentContext);
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug(
                        "Unwrapped type '" + answer.getName() + "' from wrapper list type '" + oldClass.getName() + "'.");
            }
        }
        return answer;
    }

    private Class findClassOfNamedField(Class clazz, String name) {
        for (java.lang.reflect.Field declaredField : clazz.getDeclaredFields()) {
            if (name.equals(declaredField.getName())) {
                if (declaredField.getGenericType() == null) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Skipping field '{}' on class '{}', the field isn't generic", declaredField.getName(),
                                clazz.getName());
                    }
                    continue;
                }
                ParameterizedType paramType = (ParameterizedType) declaredField.getGenericType();
                String typeName = paramType.getActualTypeArguments()[0].getTypeName();
                try {
                    if (typeName != null) {
                        return Class.forName(typeName);
                    }
                } catch (Exception e) {
                    LOG.warn("Could not load class '{}' for field '{}' on class '{}': {}", typeName, name,
                            clazz.getName(), e.getMessage());
                    LOG.debug(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    private Object createObject(Field javaField, SegmentContext segmentContext, Object parentObject,
            boolean createWrapperArray) throws AtlasException {
        Class clazz = getClassForField(javaField, segmentContext, parentObject, true);
        // TODO https://github.com/atlasmap/atlasmap/issues/48
        // - Allow default implementation for abstract target field
        return writerUtil.instantiateObject(clazz, segmentContext, createWrapperArray);
    }

    private Object getCollectionItem(Object collection, SegmentContext segmentContext) throws AtlasException {
        String segment = segmentContext.getSegment();
        int index = AtlasPath.indexOfSegment(segment);
        if (AtlasPath.isArraySegment(segment)) {
            return Array.get(collection, index);
        } else if (AtlasPath.isListSegment(segment)) {
            if (collection instanceof List) {
                List list = (List)collection;
                return list.size() > index ? list.get(index) : null;
            } else {
                throw new AtlasException(String.format(
                        "%s doesn't support to take an element out by specifying an index, segment: " + segment,
                        collection.getClass().getCanonicalName()));
            }
        } else if (AtlasPath.isMapSegment(segment)) {
            throw new AtlasException("Maps are currently unhandled for segment: " + segment);
        }
        throw new AtlasException("Cannot determine collection type from segment: " + segment);
    }

    private boolean collectionHasRoomForIndex(Object collection, SegmentContext segmentContext) throws AtlasException {
        String segment = segmentContext.getSegment();
        int index = AtlasPath.indexOfSegment(segment);
        int size = getCollectionSize(collection);
        boolean result = size > index;
        if (collection instanceof Collection) {
            // some of Collection doesn't allow indexed insertion, i.e. need to add via Collection.add()
            result = size >= index;
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("collectionHasRoomForIndex: " + result + ", size: " + size + ", index: " + index);
        }
        return result;
    }

    private int getCollectionSize(Object collection) throws AtlasException {
        if (collection instanceof Collection) {
            return ((Collection) collection).size();
        } else if (collection instanceof Map) {
            return ((Map) collection).size();
        } else if (collection.getClass().isArray()) {
            return Array.getLength(collection);
        }
        throw new AtlasException("Cannot determine collection size for: " + collection);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void addChildObject(Field field, SegmentContext segmentContext, Object parentObject, Object childObject)
            throws AtlasException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Adding child object for segment: " + segmentContext + "\n\tparentObject: " + parentObject
                    + "\n\tchild: " + childObject);
        }
        if (this.rootObject == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Setting root object: " + childObject);
            }
            this.rootObject = childObject;
            return;
        }
        boolean parentIsCollection = (parentObject instanceof Collection) || (parentObject.getClass().isArray());
        if (parentIsCollection) {
            String segment = segmentContext.getSegment();
            int index = AtlasPath.indexOfSegment(segment);
            if (parentObject instanceof Collection) {
                Collection collection = (Collection) parentObject;
                if (index == collection.size()) {
                    collection.add(childObject);
                } else if (collection instanceof List) {
                    if (index > collection.size()) {
                        throw new AtlasException("Cannot fit item in list, list size: " + collection.size() + ", item index: "
                                + index + ", segment: " + segmentContext);
                    }
                    List list = (List) collection;
                    list.set(index, childObject);
                } else {
                    LOG.warn(String.format(
                            "Writing into non-List collection - it will be added as a last element anyway. "
                            + "segment: %s \n\tparentObject: %s\n\tchild: %s",
                            segmentContext, parentObject, childObject));
                    collection.add(childObject);
                }
            } else if (parentObject instanceof Map) {
                throw new AtlasException("FIXME: Cannot yet handle adding children to maps");
            } else if (parentObject.getClass().isArray()) {
                if (index >= Array.getLength(parentObject)) {
                    throw new AtlasException("Cannot fit item in array, array size: " + Array.getLength(parentObject)
                            + ", item index: " + index + ", segment: " + segmentContext);
                }
                try {
                    Array.set(parentObject, index, childObject);
                } catch (Exception e) {
                    String parentClass = parentObject == null ? null : parentObject.getClass().getName();
                    String childClass = childObject == null ? null : childObject.getClass().getName();
                    throw new AtlasException("Could not set child class '" + childClass + "' on parent '" + parentClass
                            + "' for: " + segmentContext, e);
                }
            } else {
                throw new AtlasException("Cannot determine collection type for: " + parentObject);
            }
        } else {
            writerUtil.setObjectOnParent(field, segmentContext, parentObject, childObject);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Finished adding child object for segment: " + segmentContext + "\n\tparentObject: "
                    + parentObject + "\n\t: " + childObject);
        }
    }

    private String writeDocumentToString(boolean stripSpaces, Object object) throws AtlasException {
        try {
            if (object == null) {
                return "";
            }

            String result = object.toString();

            if (stripSpaces) {
                result = result.replaceAll("\n|\r", "");
                result = result.replaceAll("> *?<", "><");
            }
            return result;
        } catch (Exception e) {
            throw new AtlasException(e);
        }
    }

    public Object getRootObject() {
        return rootObject;
    }

    public void setRootObject(Object rootObject) {
        this.rootObject = rootObject;
    }

    public void setTargetValueConverter(TargetValueConverter converter) {
        this.converter = converter;
    }

    public Map, Class> getDefaultCollectionImplClasses() {
        return this.defaultCollectionImplClasses;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy