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

io.github.karlatemp.mxlib.common.injector.SimpleMethodCallerWithBeans Maven / Gradle / Ivy

/*
 * Copyright (c) 2018-2021 Karlatemp. All rights reserved.
 * @author Karlatemp  
 *
 * MXLib/MXLib.mxlib-common.main/SimpleMethodCallerWithBeans.java
 *
 * Use of this source code is governed by the MIT license that can be found via the following link.
 *
 * https://github.com/Karlatemp/MxLib/blob/master/LICENSE
 */

package io.github.karlatemp.mxlib.common.injector;

import io.github.karlatemp.mxlib.annotations.injector.Inject;
import io.github.karlatemp.mxlib.bean.IBeanManager;
import io.github.karlatemp.mxlib.exception.InjectException;
import io.github.karlatemp.mxlib.injector.MethodCallerWithBeans;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Optional;

public class SimpleMethodCallerWithBeans implements MethodCallerWithBeans {
    private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];

    @Override
    public Object call(
            @NotNull IBeanManager beanManager,
            @NotNull Executable method,
            @Nullable Object instance
    ) throws IllegalAccessException, InvocationTargetException, InjectException, InstantiationException {

        Class[] types = method.getParameterTypes();
        Annotation[][] annotations = method.getParameterAnnotations();

        if (annotations.length + 1 == types.length) {
            Annotation[][] tmp = new Annotation[types.length][];
            System.arraycopy(annotations, 0, tmp, 1, annotations.length);
            tmp[0] = EMPTY_ANNOTATION_ARRAY;
            annotations = tmp;
        }

        Inject[] injectFlags = new Inject[annotations.length];
        for (int i = 0; i < annotations.length; i++) {
            for (Annotation ano : annotations[i]) {
                if (ano instanceof Inject) {
                    injectFlags[i] = (Inject) ano;
                    break;
                }
            }
        }
        Object[] arguments = new Object[annotations.length];
        for (int i = 0; i < arguments.length; i++) {
            Inject inject = injectFlags[i];
            if (inject != null) {
                Class type = inject.value();
                if (type == Void.class) {
                    type = types[i];
                }
                if (!types[i].isAssignableFrom(type)) {
                    throw new InjectException("Exception in inject parameter " + i + " of method " + method + ", " + type + " cannot cast to " + types[i]);
                }
                String name = inject.name();
                if (name.equals(Inject.NAME_UNSET)) {
                    name = null;
                }
                Optional optional = beanManager.getBy(type, name);
                if (optional.isPresent()) {
                    arguments[i] = optional.get();
                } else if (!inject.nullable()) {
                    throw new InjectException("Failed inject parameter " + i + " of method " + method + ", Bean[" + type + ", named " + name + "] not found.");
                }
            } else {
                arguments[i] = safelyValue(types[i]);
            }
        }
        if (method instanceof Method) {
            return ((Method) method).invoke(instance, arguments);
        } else if (method instanceof Constructor) {
            return ((Constructor) method).newInstance(arguments);
        } else {
            throw new IllegalArgumentException("Unknown how to execute " + method);
        }
    }

    private static final Integer ZERO_INT = 0;
    private static final Long ZERO_LONG = 0L;
    private static final Double ZERO_DOUBLE = 0d;
    private static final Float ZERO_FLOAT = 0f;
    private static final Byte ZERO_BYTE = (byte) 0;
    private static final Short ZERO_SHORT = (short) 0;
    private static final Character ZERO_CHAR = '\u0000';

    private static Object safelyValue(Class type) {
        if (type == int.class) return ZERO_INT;
        if (type == long.class) return ZERO_LONG;
        if (type == double.class) return ZERO_DOUBLE;
        if (type == float.class) return ZERO_FLOAT;
        if (type == byte.class) return ZERO_BYTE;
        if (type == short.class) return ZERO_SHORT;
        if (type == boolean.class) return Boolean.FALSE;
        if (type == char.class) return ZERO_CHAR;
        return null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy