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

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

package io.atlasmap.java.core;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.slf4j.LoggerFactory;

import io.atlasmap.api.AtlasException;
import io.atlasmap.core.AtlasPath;
import io.atlasmap.core.AtlasPath.SegmentContext;
import io.atlasmap.core.AtlasUtil;
import io.atlasmap.java.v2.JavaEnumField;
import io.atlasmap.java.v2.JavaField;
import io.atlasmap.spi.AtlasConversionService;
import io.atlasmap.spi.AtlasFieldReader;
import io.atlasmap.spi.AtlasInternalSession;
import io.atlasmap.v2.AtlasModelFactory;
import io.atlasmap.v2.AuditStatus;
import io.atlasmap.v2.CollectionType;
import io.atlasmap.v2.Field;
import io.atlasmap.v2.FieldGroup;

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

    private AtlasConversionService conversionService;
    private Object sourceDocument;

    @Override
    public Field read(AtlasInternalSession session) throws AtlasException {
        try {
            Field sourceField = session.head().getSourceField();
            Method getter = null;
            if (sourceField.getFieldType() == null
                    && (sourceField instanceof JavaField || sourceField instanceof JavaEnumField)) {
                getter = resolveGetMethod(session, sourceDocument, sourceField);
                if (getter == null) {
                    AtlasUtil.addAudit(session, sourceField.getDocId(), String.format(
                            "Unable to auto-detect sourceField type path=%s docId=%s",
                            sourceField.getPath(), sourceField.getDocId()),
                            sourceField.getPath(), AuditStatus.WARN, null);
                    return sourceField;
                }
                Class returnType = getter.getReturnType();
                sourceField.setFieldType(conversionService.fieldTypeFromClass(returnType));
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Auto-detected sourceField type p=" + sourceField.getPath() + " t="
                            + sourceField.getFieldType());
                }
            }

            populateSourceFieldValue(session, sourceField, sourceDocument, getter);

            if (LOG.isDebugEnabled()) {
                LOG.debug("Processed input field sPath=" + sourceField.getPath() + " sV=" + sourceField.getValue()
                + " sT=" + sourceField.getFieldType() + " docId: " + sourceField.getDocId());
            }
            return session.head().getSourceField();
        } catch (Exception e) {
            throw new AtlasException(e);
        }
    }

    private void populateSourceFieldValue(AtlasInternalSession session, Field field, Object source, Method m) throws Exception {
        Method getter = m;
        AtlasPath atlasPath = new AtlasPath(field.getPath());
        FieldGroup fieldGroup = null;
        if (atlasPath.hasCollection() && !atlasPath.isIndexedCollection()) {
            fieldGroup = AtlasModelFactory.createFieldGroupFrom(field);
            session.head().setSourceField(fieldGroup);
        }

        List parents = Arrays.asList(source);
        if (atlasPath.isRoot()) {
            if (atlasPath.getLastSegment().getCollectionType() == CollectionType.NONE) {
                processField(fieldGroup, field, source);
            } else {
                if (atlasPath.getLastSegment().getCollectionIndex() != null) {
                    processField(fieldGroup, field, extractFromCollection(session, source, atlasPath));
                } else {
                    if (source instanceof Collection) {
                        for (Object item : ((Collection)source).toArray()) {
                            processField(fieldGroup, field, item);
                        }
                    } else if (source.getClass().isArray()) {
                        for (int i=0; i)child).toArray()) {
                            processField(fieldGroup, field, item);
                        }
                    } else if (child.getClass().isArray()) {
                        for (int i=0; i parents = ClassHelper.getParentObjectsForPath(session, sourceObject, atlasPath);
            parentObject = parents != null && parents.size() > 0 ? parents.get(0) : null;
        }
        if (parentObject == null) {
            return null;
        }

        List> classTree = resolveMappableClasses(parentObject.getClass());

        for (Class clazz : classTree) {
            try {
                if (field instanceof JavaField && ((JavaField) field).getGetMethod() != null) {
                    getter = clazz.getMethod(((JavaField) field).getGetMethod());
                    getter.setAccessible(true);
                    return getter;
                }
            } catch (NoSuchMethodException e) {
                // no getter method specified in mapping file
            }

            for (String m : Arrays.asList("get", "is")) {
                String getterMethod = m + capitalizeFirstLetter(atlasPath.getLastSegment().getName());
                try {
                    getter = clazz.getMethod(getterMethod);
                    getter.setAccessible(true);
                    return getter;
                } catch (NoSuchMethodException e) {
                    // method does not exist
                }
            }
        }
        return null;
    }

    private Object getValueFromMemberField(AtlasInternalSession session, Object source, String fieldName) throws IllegalArgumentException, IllegalAccessException {
        java.lang.reflect.Field reflectField = lookupJavaField(source, fieldName);
        if (reflectField != null) {
            reflectField.setAccessible(true);
            return reflectField.get(source);
        }
        Field sourceField = session.head().getSourceField();
        AtlasUtil.addAudit(session, sourceField.getDocId(), String.format(
                "Field '%s' not found on object '%s'", fieldName, source),
                sourceField.getPath(), AuditStatus.ERROR, null);
        return null;
    }

    private List> resolveMappableClasses(Class className) {
        List> classTree = new ArrayList<>();
        classTree.add(className);

        Class superClazz = className.getSuperclass();
        while (superClazz != null) {
            if (JdkPackages.contains(superClazz.getPackage().getName())) {
                superClazz = null;
            } else {
                classTree.add(superClazz);
                superClazz = superClazz.getSuperclass();
            }
        }

        return classTree;
    }

    private java.lang.reflect.Field lookupJavaField(Object source, String fieldName) {
        Class targetClazz = source != null ? source.getClass() : null;
        while (targetClazz != null && targetClazz != Object.class) {
            try {
                return targetClazz.getDeclaredField(fieldName);
            } catch (Exception e) {
                e.getMessage(); // ignore
                targetClazz = targetClazz.getSuperclass();
            }
        }
        return null;
    }

    private String capitalizeFirstLetter(String sentence) {
        if (StringUtil.isEmpty(sentence)) {
            return sentence;
        }
        if (sentence.length() == 1) {
            return String.valueOf(sentence.charAt(0)).toUpperCase();
        }
        return String.valueOf(sentence.charAt(0)).toUpperCase() + sentence.substring(1);
    }

    private Object extractFromCollection(AtlasInternalSession session, Object source, AtlasPath atlasPath) {
        if (source == null) {
            return null;
        }

        SegmentContext lastSegment = atlasPath.getLastSegment();
        CollectionType collectionType = lastSegment.getCollectionType();
        Integer index = lastSegment.getCollectionIndex();
        if (collectionType == CollectionType.NONE || index == null) {
            return source;
        }

        if (collectionType == CollectionType.ARRAY) {
            return Array.get(source, index);
        } else if (collectionType == CollectionType.LIST) {
            return Collection.class.cast(source).toArray()[index];
        } else if (collectionType == CollectionType.MAP) {
            // TODO support map key
            String key = index.toString();
            return Map.class.cast(source).get(key);
        } else {
            Field sourceField = session.head().getSourceField();
            AtlasUtil.addAudit(session, sourceField.getDocId(), String.format(
                    "Ignoring unknown collection type in path '%s'", sourceField.getPath()),
                    sourceField.getPath(), AuditStatus.WARN, null);
            return source;
        }
    }

    public void setDocument(Object sourceDocument) {
        this.sourceDocument = sourceDocument;
    }

    public void setConversionService(AtlasConversionService conversionService) {
        this.conversionService = conversionService;
    }
}