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

io.atlasmap.java.core.DocumentJavaFieldReader 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.AtlasConversionService;
import io.atlasmap.api.AtlasException;
import io.atlasmap.core.AtlasPath;
import io.atlasmap.core.AtlasUtil;
import io.atlasmap.java.inspect.ClassHelper;
import io.atlasmap.java.inspect.JdkPackages;
import io.atlasmap.java.inspect.StringUtil;
import io.atlasmap.java.v2.JavaEnumField;
import io.atlasmap.java.v2.JavaField;
import io.atlasmap.spi.AtlasFieldReader;
import io.atlasmap.spi.AtlasInternalSession;
import io.atlasmap.v2.AuditStatus;
import io.atlasmap.v2.Field;

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

    private AtlasConversionService conversionService;
    private Object sourceDocument;

    @Override
    public void 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(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;
                }
                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());
            }
        } catch (Exception e) {
            throw new AtlasException(e);
        }
    }

    private void populateSourceFieldValue(AtlasInternalSession session, Field field, Object source, Method m) throws Exception {
        Method getter = m;
        Object parentObject = source;
        AtlasPath atlasPath = new AtlasPath(field.getPath());

        Object sourceValue = null;
        if (atlasPath.isRoot()) {
            sourceValue = source;
        } else {
            if (atlasPath.hasParent()) {
                parentObject = ClassHelper.parentObjectForPath(source, atlasPath, true);
            }
            getter = (getter == null) ? resolveGetMethod(source, field) : getter;
            if (getter != null) {
                sourceValue = getter.invoke(parentObject);
            }
        }

        // TODO: support doing parent stuff at field level vs getter
        if (sourceValue == null) {
            String cleanedLastSegment = AtlasPath.cleanPathSegment(atlasPath.getLastSegment());
            sourceValue = getValueFromMemberField(session, parentObject, cleanedLastSegment);
        }

        if (sourceValue != null) {
            sourceValue = extractFromCollection(session, sourceValue, atlasPath);
            if (conversionService.isPrimitive(sourceValue.getClass())
                || conversionService.isBoxedPrimitive(sourceValue.getClass())) {
                sourceValue = conversionService.copyPrimitive(sourceValue);
            }
        }

        field.setValue(sourceValue);
    }

    private Method resolveGetMethod(Object sourceObject, Field field)
            throws AtlasException {
        Object parentObject = sourceObject;
        AtlasPath atlasPath = new AtlasPath(field.getPath());
        Method getter = null;

        if (atlasPath.hasParent()) {
            parentObject = ClassHelper.parentObjectForPath(sourceObject, atlasPath, true);
        }
        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 cleanedLastSegment = AtlasPath.cleanPathSegment(atlasPath.getLastSegment());
                String getterMethod = m + capitalizeFirstLetter(cleanedLastSegment);
                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;
        }

        String lastSegment = atlasPath.getLastSegment();
        if (!AtlasPath.isCollectionSegment(lastSegment) || !atlasPath.isIndexedCollection()) {
            return source;
        }

        Integer index = atlasPath.getCollectionIndex(atlasPath.getLastSegment());
        if (AtlasPath.isArraySegment(lastSegment)) {
            return Array.get(source, index);
        } else if (AtlasPath.isListSegment(lastSegment)) {
            return Collection.class.cast(source).toArray()[index];
        } else if (AtlasPath.isMapSegment(lastSegment)) {
            // 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;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy