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

io.gravitee.gateway.resource.internal.ResourceFactory Maven / Gradle / Ivy

There is a newer version: 4.5.5
Show newest version
/*
 * Copyright © 2015 The Gravitee team (http://gravitee.io)
 *
 * 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.gravitee.gateway.resource.internal;

import static org.reflections.ReflectionUtils.*;

import com.google.common.base.Predicate;
import io.gravitee.resource.api.Resource;
import io.gravitee.resource.api.ResourceConfiguration;
import jakarta.inject.Inject;
import java.lang.reflect.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.reflections.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author David BRASSELY (david at gravitee.io)
 * @author GraviteeSource Team
 */
public class ResourceFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResourceFactory.class);

    public Resource create(Class resourceClass, Map, Object> injectables) throws Exception {
        LOGGER.debug("Create a new resource instance for {}", resourceClass.getName());

        return createResource(resourceClass, injectables);
    }

    private Resource createResource(Class resourceClass, Map, Object> injectables) {
        Resource resourceInst = null;

        Constructor constr = lookingForConstructor(resourceClass);

        if (constr != null) {
            try {
                //    if (constr.getParameterCount() > 0) {
                //        resourceInst = constr.newInstance(injectables.get(policyMetadata.configuration()));
                //    } else {
                resourceInst = constr.newInstance();
                //    }
            } catch (IllegalAccessException | InstantiationException | InvocationTargetException ex) {
                LOGGER.error("Unable to instantiate resource {}", resourceClass, ex);
            }
        }

        if (resourceInst != null) {
            Set fields = lookingForInjectableFields(resourceClass);
            for (Field field : fields) {
                boolean accessible = field.isAccessible();

                Class type = field.getType();
                Optional value = injectables.values().stream().filter(o -> type.isAssignableFrom(o.getClass())).findFirst();

                if (value.isPresent()) {
                    LOGGER.debug("Inject value into field {} [{}] in {}", field.getName(), type.getName(), resourceClass);
                    try {
                        field.setAccessible(true);
                        field.set(resourceInst, value.get());
                    } catch (IllegalAccessException iae) {
                        LOGGER.error("Unable to set field value for {} in {}", field.getName(), resourceClass, iae);
                    } finally {
                        field.setAccessible(accessible);
                    }
                }
            }
        }

        return resourceInst;
    }

    private Constructor lookingForConstructor(Class resourceClass) {
        LOGGER.debug("Looking for a constructor to inject resource configuration");
        Constructor constructor = null;

        Set resourceConstructors = ReflectionUtils.getConstructors(
            resourceClass,
            withModifier(Modifier.PUBLIC),
            withParametersAssignableFrom(ResourceConfiguration.class),
            withParametersCount(1)
        );

        if (resourceConstructors.isEmpty()) {
            LOGGER.debug(
                "No configuration can be injected for {} because there is no valid constructor. " + "Using default empty constructor.",
                resourceClass.getName()
            );
            try {
                constructor = resourceClass.getConstructor();
            } catch (NoSuchMethodException nsme) {
                LOGGER.error("Unable to find default empty constructor for {}", resourceClass.getName(), nsme);
            }
        } else if (resourceConstructors.size() == 1) {
            constructor = resourceConstructors.iterator().next();
        } else {
            LOGGER.info("Too much constructors to instantiate resource {}", resourceClass.getName());
        }

        return constructor;
    }

    private Set lookingForInjectableFields(Class resourceClass) {
        // For now, we still need to support javax.inject waiting for all third-parties to migrate to jakarta.inject.
        final HashSet fields = new HashSet<>(getAllFields(resourceClass, withAnnotation(javax.inject.Inject.class)));
        fields.addAll(ReflectionUtils.getAllFields(resourceClass, withAnnotation(Inject.class)));
        return fields;
    }

    public static Predicate withParametersAssignableFrom(final Class... types) {
        return input -> {
            if (input != null) {
                Class[] parameterTypes = parameterTypes(input);
                if (parameterTypes.length == types.length) {
                    for (int i = 0; i < parameterTypes.length; i++) {
                        if (
                            !types[i].isAssignableFrom(parameterTypes[i]) || (parameterTypes[i] == Object.class && types[i] != Object.class)
                        ) {
                            return false;
                        }
                    }
                    return true;
                }
            }
            return false;
        };
    }

    private static Class[] parameterTypes(Member member) {
        return member != null
            ? member.getClass() == Method.class
                ? ((Method) member).getParameterTypes()
                : member.getClass() == Constructor.class ? ((Constructor) member).getParameterTypes() : null
            : null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy