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

org.glassfish.jersey.internal.inject.Providers Maven / Gradle / Ivy

Go to download

A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle (jaxrs-ri.jar). Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from the command line.

There is a newer version: 3.1.6
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2012-2015 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.jersey.internal.inject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.core.Feature;

import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.model.ContractProvider;
import org.glassfish.jersey.model.internal.RankedComparator;
import org.glassfish.jersey.model.internal.RankedProvider;
import org.glassfish.jersey.spi.Contract;

import org.glassfish.hk2.api.ActiveDescriptor;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;

import jersey.repackaged.com.google.common.base.Function;
import jersey.repackaged.com.google.common.collect.Collections2;
import jersey.repackaged.com.google.common.collect.Lists;
import jersey.repackaged.com.google.common.collect.Sets;

/**
 * Utility class providing a set of utility methods for easier and more type-safe
 * interaction with HK2 injection layer.
 *
 * @author Marek Potociar (marek.potociar at oracle.com)
 * @author Miroslav Fuksa
 */
public final class Providers {

    private static final Logger LOGGER = Logger.getLogger(Providers.class.getName());

    /**
     * Map of all standard JAX-RS providers and their run-time affinity.
     */
    private static final Map, ProviderRuntime> JAX_RS_PROVIDER_INTERFACE_WHITELIST =
            getJaxRsProviderInterfaces();

    private static Map, ProviderRuntime> getJaxRsProviderInterfaces() {
        final Map, ProviderRuntime> interfaces = new HashMap, ProviderRuntime>();

        interfaces.put(javax.ws.rs.ext.ContextResolver.class, ProviderRuntime.BOTH);
        interfaces.put(javax.ws.rs.ext.ExceptionMapper.class, ProviderRuntime.BOTH);
        interfaces.put(javax.ws.rs.ext.MessageBodyReader.class, ProviderRuntime.BOTH);
        interfaces.put(javax.ws.rs.ext.MessageBodyWriter.class, ProviderRuntime.BOTH);
        interfaces.put(javax.ws.rs.ext.ReaderInterceptor.class, ProviderRuntime.BOTH);
        interfaces.put(javax.ws.rs.ext.WriterInterceptor.class, ProviderRuntime.BOTH);
        interfaces.put(javax.ws.rs.ext.ParamConverterProvider.class, ProviderRuntime.BOTH);

        interfaces.put(javax.ws.rs.container.ContainerRequestFilter.class, ProviderRuntime.SERVER);
        interfaces.put(javax.ws.rs.container.ContainerResponseFilter.class, ProviderRuntime.SERVER);
        interfaces.put(javax.ws.rs.container.DynamicFeature.class, ProviderRuntime.SERVER);

        interfaces.put(javax.ws.rs.client.ClientResponseFilter.class, ProviderRuntime.CLIENT);
        interfaces.put(javax.ws.rs.client.ClientRequestFilter.class, ProviderRuntime.CLIENT);

        return interfaces;
    }

    /**
     * Map of all supported external (i.e. non-Jersey) contracts and their run-time affinity.
     */
    private static final Map, ProviderRuntime> EXTERNAL_PROVIDER_INTERFACE_WHITELIST =
            getExternalProviderInterfaces();

    private static Map, ProviderRuntime> getExternalProviderInterfaces() {
        final Map, ProviderRuntime> interfaces = new HashMap, ProviderRuntime>();

        // JAX-RS
        interfaces.putAll(JAX_RS_PROVIDER_INTERFACE_WHITELIST);
        interfaces.put(javax.ws.rs.core.Feature.class, ProviderRuntime.BOTH);

        // HK2
        interfaces.put(org.glassfish.hk2.utilities.Binder.class, ProviderRuntime.BOTH);

        return interfaces;
    }

    private enum ProviderRuntime {

        BOTH(null), SERVER(RuntimeType.SERVER), CLIENT(RuntimeType.CLIENT);

        private final RuntimeType runtime;

        private ProviderRuntime(final RuntimeType runtime) {
            this.runtime = runtime;
        }

        public RuntimeType getRuntime() {
            return runtime;
        }
    }

    private Providers() {
    }

    /**
     * Wrap an instance into a HK2 service factory.
     *
     * @param       Java type if the contract produced by the provider and factory.
     * @param instance instance to be wrapped into (and provided by) the factory.
     * @return HK2 service factory wrapping and providing the instance.
     */
    public static  Factory factoryOf(final T instance) {
        return new Factory() {

            @Override
            public T provide() {
                return instance;
            }

            @Override
            public void dispose(final T instance) {
                //not used
            }
        };
    }

    /**
     * Get the set of default providers registered for the given service provider contract
     * in the underlying {@link ServiceLocator HK2 service locator} container.
     *
     * @param       service provider contract Java type.
     * @param locator  underlying HK2 service locator.
     * @param contract service provider contract.
     * @return set of all available default service provider instances for the contract.
     */
    public static  Set getProviders(final ServiceLocator locator, final Class contract) {
        final Collection> hk2Providers = getServiceHandles(locator, contract);
        return getClasses(hk2Providers);
    }

    /**
     * Get the set of all custom providers registered for the given service provider contract
     * in the underlying {@link ServiceLocator HK2 service locator} container.
     *
     * @param       service provider contract Java type.
     * @param locator  underlying HK2 service locator.
     * @param contract service provider contract.
     * @return set of all available service provider instances for the contract.
     */
    public static  Set getCustomProviders(final ServiceLocator locator, final Class contract) {
        final Collection> hk2Providers = getServiceHandles(locator, contract, new CustomAnnotationImpl());
        return getClasses(hk2Providers);
    }

    /**
     * Get the iterable of all providers (custom and default) registered for the given service provider contract
     * in the underlying {@link ServiceLocator HK2 service locator} container.
     *
     * @param       service provider contract Java type.
     * @param locator  underlying HK2 service locator.
     * @param contract service provider contract.
     * @return iterable of all available service provider instances for the contract. Return value is never null.
     */
    public static  Iterable getAllProviders(final ServiceLocator locator, final Class contract) {
        return getAllProviders(locator, contract, (Comparator) null);
    }

    /**
     * Get the iterable of all {@link RankedProvider providers} (custom and default) registered for the given service provider
     * contract in the underlying {@link ServiceLocator HK2 service locator} container.
     *
     * @param       service provider contract Java type.
     * @param locator  underlying HK2 service locator.
     * @param contract service provider contract.
     * @return iterable of all available ranked service providers for the contract. Return value is never null.
     */
    public static  Iterable> getAllRankedProviders(final ServiceLocator locator, final Class contract) {
        final List> providers = getServiceHandles(locator, contract, new CustomAnnotationImpl());
        providers.addAll(getServiceHandles(locator, contract));

        final LinkedHashMap, RankedProvider> providerMap =
                new LinkedHashMap, RankedProvider>();

        for (final ServiceHandle provider : providers) {
            final ActiveDescriptor key = provider.getActiveDescriptor();
            if (!providerMap.containsKey(key)) {
                final Set contractTypes = key.getContractTypes();
                final Class implementationClass = key.getImplementationClass();
                boolean proxyGenerated = true;
                for (Type ct : contractTypes) {
                    if (((Class) ct).isAssignableFrom(implementationClass)) {
                        proxyGenerated = false;
                        break;
                    }
                }
                providerMap.put(key,
                        new RankedProvider(provider.getService(), key.getRanking(), proxyGenerated ? contractTypes : null));
            }
        }

        return providerMap.values();
    }

    /**
     * Sort given providers with {@link RankedComparator ranked comparator}.
     *
     * @param comparator comparator to sort the providers with.
     * @param providers  providers to be sorted.
     * @param         service provider contract Java type.
     * @return sorted {@link Iterable iterable} instance containing given providers.
     *         The returned value is never {@code null}.
     */
    @SuppressWarnings("TypeMayBeWeakened")
    public static  Iterable sortRankedProviders(final RankedComparator comparator,
                                                      final Iterable> providers) {
        final List> rankedProviders = Lists.newArrayList(providers);

        Collections.sort(rankedProviders, comparator);

        return Collections2.transform(rankedProviders, new Function, T>() {
            @Override
            public T apply(final RankedProvider input) {
                return input.getProvider();
            }
        });
    }

    /**
     * Merge and sort given providers with {@link RankedComparator ranked comparator}.
     *
     * @param comparator        comparator to sort the providers with.
     * @param providerIterables providers to be sorted.
     * @param                service provider contract Java type.
     * @return merged and sorted {@link Iterable iterable} instance containing given providers.
     *         The returned value is never {@code null}.
     */
    @SuppressWarnings("TypeMayBeWeakened")
    public static  Iterable mergeAndSortRankedProviders(final RankedComparator comparator,
                                                              final Iterable>> providerIterables) {
        final List> rankedProviders = Lists.newArrayList();

        for (final Iterable> providers : providerIterables) {
            rankedProviders.addAll(Lists.>newLinkedList(providers));
        }

        Collections.sort(rankedProviders, comparator);

        return Collections2.transform(rankedProviders, new Function, T>() {
            @Override
            public T apply(final RankedProvider input) {
                return input.getProvider();
            }
        });
    }

    /**
     * Get the sorted iterable of all {@link RankedProvider providers} (custom and default) registered for the given service
     * provider contract in the underlying {@link ServiceLocator HK2 service locator} container.
     *
     * @param         service provider contract Java type.
     * @param locator    underlying HK2 service locator.
     * @param contract   service provider contract.
     * @param comparator comparator to sort the providers with.
     * @return set of all available ranked service providers for the contract. Return value is never null.
     */
    public static  Iterable getAllProviders(final ServiceLocator locator,
                                                  final Class contract,
                                                  final RankedComparator comparator) {
        //noinspection unchecked
        return sortRankedProviders(comparator, getAllRankedProviders(locator, contract));
    }

    /**
     * Get collection of all {@link ServiceHandle}s bound for providers (custom and default) registered for the given service
     * provider contract in the underlying {@link ServiceLocator HK2 service locator} container.
     *
     * @param         service provider contract Java type.
     * @param locator    underlying HK2 service locator.
     * @param contract   service provider contract.
     * @return set of all available service provider instances for the contract
     */
    public static  Collection> getAllServiceHandles(final ServiceLocator locator, final Class contract) {
        final List> providers = getServiceHandles(locator, contract, new CustomAnnotationImpl());
        providers.addAll(getServiceHandles(locator, contract));

        final LinkedHashMap> providerMap =
                new LinkedHashMap>();

        for (final ServiceHandle provider : providers) {
            final ActiveDescriptor key = provider.getActiveDescriptor();
            if (!providerMap.containsKey(key)) {
                providerMap.put(key, provider);
            }
        }

        return providerMap.values();
    }

    private static  List> getServiceHandles(final ServiceLocator locator, final Class contract,
                                                                final Annotation... qualifiers) {

        final List> allServiceHandles = qualifiers == null
                ? locator.getAllServiceHandles(contract)
                : locator.getAllServiceHandles(contract, qualifiers);

        final ArrayList> serviceHandles = new ArrayList>();
        for (final ServiceHandle handle : allServiceHandles) {
            //noinspection unchecked
            serviceHandles.add((ServiceHandle) handle);
        }
        return serviceHandles;
    }

    /**
     * Get the iterable of all providers (custom and default) registered for the given service provider contract
     * in the underlying {@link ServiceLocator HK2 service locator} container ordered based on the given {@code comparator}.
     *
     * @param         service provider contract Java type.
     * @param locator    underlying HK2 service locator.
     * @param contract   service provider contract.
     * @param comparator comparator to be used for sorting the returned providers.
     * @return set of all available service provider instances for the contract ordered using the given
     * {@link Comparator comparator}.
     */
    public static  Iterable getAllProviders(final ServiceLocator locator,
                                                  final Class contract,
                                                  final Comparator comparator) {

        final List providerList = new ArrayList(getClasses(getAllServiceHandles(locator, contract)));

        if (comparator != null) {
            Collections.sort(providerList, comparator);
        }

        return providerList;
    }

    private static  Set getClasses(final Collection> hk2Providers) {
        if (hk2Providers.isEmpty()) {
            return Sets.newLinkedHashSet();
        } else {
            return Sets.newLinkedHashSet(Collections2.transform(hk2Providers, new ProviderToService()));
        }
    }

    /**
     * Get the set of all providers registered for the given service provider contract
     * in the underlying {@link ServiceLocator HK2 locator} container.
     *
     * @param         service provider contract Java type.
     * @param locator    underlying HK2 service locator.
     * @param contract   service provider contract.
     * @param comparator contract comparator used for ordering contracts in the
     *                   set.
     * @return set of all available service provider instances for the contract.
     */
    public static  SortedSet getProviders(final ServiceLocator locator,
                                                final Class contract,
                                                final Comparator comparator) {
        final Collection> hk2Providers = getServiceHandles(locator, contract);
        if (hk2Providers.isEmpty()) {
            return Sets.newTreeSet(comparator);
        } else {
            final TreeSet set = Sets.newTreeSet(comparator);
            set.addAll(Collections2.transform(hk2Providers, new ProviderToService()));
            return set;
        }
    }

    /**
     * Returns provider contracts recognized by Jersey that are implemented by the {@code clazz}.
     * Recognized provider contracts include all JAX-RS providers as well as all Jersey SPI
     * components annotated with {@link Contract @Contract} annotation.
     *
     * @param clazz class to extract the provider interfaces from.
     * @return set of provider contracts implemented by the given class.
     */
    public static Set> getProviderContracts(final Class clazz) {
        final Set> contracts = Sets.newIdentityHashSet();
        computeProviderContracts(clazz, contracts);
        return contracts;
    }

    private static void computeProviderContracts(final Class clazz, final Set> contracts) {
        for (final Class contract : getImplementedContracts(clazz)) {
            if (isSupportedContract(contract)) {
                contracts.add(contract);
            }
            computeProviderContracts(contract, contracts);
        }
    }

    /**
     * Check the {@code component} whether it is appropriate correctly configured for client or server
     * {@link RuntimeType runtime}.
     *
     * If a problem occurs a warning is logged and if the component is not usable at all in the current runtime
     * {@code false} is returned. For classes found during component scanning (scanned=true) certain warnings are
     * completely ignored (e.g. components {@link ConstrainedTo constrained to} the client runtime and found by
     * server-side class path scanning will be silently ignored and no warning will be logged).
     *
     * @param component         the class of the component being checked.
     * @param model             model of the component.
     * @param runtimeConstraint current runtime (client or server).
     * @param scanned           {@code false} if the component type has been registered explicitly;
     *                          {@code true} if the class has been discovered during any form of component scanning.
     * @param isResource        {@code true} if the component is also a resource class.
     * @return {@code true} if component is acceptable for use in the given runtime type, {@code false} otherwise.
     */
    public static boolean checkProviderRuntime(final Class component,
                                               final ContractProvider model,
                                               final RuntimeType runtimeConstraint,
                                               final boolean scanned,
                                               final boolean isResource) {
        final Set> contracts = model.getContracts();
        final ConstrainedTo constrainedTo = component.getAnnotation(ConstrainedTo.class);
        final RuntimeType componentConstraint = constrainedTo == null ? null : constrainedTo.value();
        if (Feature.class.isAssignableFrom(component)) {
            // TODO: solve after implementation
            return true;
        }

        final StringBuilder warnings = new StringBuilder();
        try {
            /**
             * Indicates that the provider implements at least one contract compatible
             * with it's implementation class constraint.
             */
            boolean foundComponentCompatible = componentConstraint == null;
            boolean foundRuntimeCompatibleContract = isResource && runtimeConstraint == RuntimeType.SERVER;
            for (final Class contract : contracts) {
                // if the contract is common/not constrained, default to provider constraint
                final RuntimeType contractConstraint = getContractConstraint(contract, componentConstraint);
                foundRuntimeCompatibleContract |= contractConstraint == null || contractConstraint == runtimeConstraint;

                if (componentConstraint != null) {
                    if (contractConstraint != componentConstraint) {
                        warnings.append(LocalizationMessages.WARNING_PROVIDER_CONSTRAINED_TO_WRONG_PACKAGE(
                                component.getName(),
                                componentConstraint.name(),
                                contract.getName(),
                                contractConstraint.name()))
                                .append(" ");
                    } else {
                        foundComponentCompatible = true;
                    }
                }
            }

            if (!foundComponentCompatible) {
                warnings.append(LocalizationMessages.ERROR_PROVIDER_CONSTRAINED_TO_WRONG_PACKAGE(
                        component.getName(),
                        componentConstraint.name()))
                        .append(" ");
                logProviderSkipped(warnings, component, isResource);
                return false;
            }

            final boolean isProviderRuntimeCompatible;
            // runtimeConstraint vs. providerConstraint
            isProviderRuntimeCompatible = componentConstraint == null || componentConstraint == runtimeConstraint;
            if (!isProviderRuntimeCompatible && !scanned) {
                // log failure for manually registered providers
                warnings.append(LocalizationMessages.ERROR_PROVIDER_CONSTRAINED_TO_WRONG_RUNTIME(
                        component.getName(),
                        componentConstraint.name(),
                        runtimeConstraint.name()))
                        .append(" ");

                logProviderSkipped(warnings, component, isResource);
            }

            // runtimeConstraint vs contractConstraint
            if (!foundRuntimeCompatibleContract && !scanned) {
                warnings.append(LocalizationMessages.ERROR_PROVIDER_REGISTERED_WRONG_RUNTIME(
                        component.getName(),
                        runtimeConstraint.name()))
                        .append(" ");
                logProviderSkipped(warnings, component, isResource);
                return false;
            }

            return isProviderRuntimeCompatible && foundRuntimeCompatibleContract;
        } finally {
            if (warnings.length() > 0) {
                LOGGER.log(Level.WARNING, warnings.toString());
            }
        }
    }

    private static void logProviderSkipped(final StringBuilder sb, final Class provider, final boolean alsoResourceClass) {
        sb.append(alsoResourceClass
                ? LocalizationMessages.ERROR_PROVIDER_AND_RESOURCE_CONSTRAINED_TO_IGNORED(provider.getName())
                : LocalizationMessages.ERROR_PROVIDER_CONSTRAINED_TO_IGNORED(provider.getName())).append(" ");
    }

    /**
     * Check if the given Java type is a Jersey-supported contract.
     *
     * @param type contract type.
     * @return {@code true} if given type is a Jersey-supported contract, {@code false} otherwise.
     */
    public static boolean isSupportedContract(final Class type) {
        return (EXTERNAL_PROVIDER_INTERFACE_WHITELIST.get(type) != null || type.isAnnotationPresent(Contract.class));
    }

    private static RuntimeType getContractConstraint(final Class clazz, final RuntimeType defaultConstraint) {
        final ProviderRuntime jaxRsProvider = EXTERNAL_PROVIDER_INTERFACE_WHITELIST.get(clazz);

        RuntimeType result = null;
        if (jaxRsProvider != null) {
            result = jaxRsProvider.getRuntime();
        } else if (clazz.getAnnotation(Contract.class) != null) {
            final ConstrainedTo constrainedToAnnotation = clazz.getAnnotation(ConstrainedTo.class);
            if (constrainedToAnnotation != null) {
                result = constrainedToAnnotation.value();
            }
        }

        return (result == null) ? defaultConstraint : result;
    }

    private static Iterable> getImplementedContracts(final Class clazz) {
        final Collection> list = new LinkedList>();

        Collections.addAll(list, clazz.getInterfaces());

        final Class superclass = clazz.getSuperclass();
        if (superclass != null) {
            list.add(superclass);
        }

        return list;
    }

    /**
     * Returns {@code true} if the given component class is a provider (implements specific interfaces).
     * See {@link #getProviderContracts}.
     *
     * @param clazz class to test.
     * @return {@code true} if the class is provider, {@code false} otherwise.
     */
    public static boolean isProvider(final Class clazz) {
        return findFirstProviderContract(clazz);
    }

    /**
     * Returns {@code true} if given component class is a JAX-RS provider.
     *
     * @param clazz class to check.
     * @return {@code true} if the class is a JAX-RS provider, {@code false} otherwise.
     */
    public static boolean isJaxRsProvider(final Class clazz) {
        for (final Class providerType : JAX_RS_PROVIDER_INTERFACE_WHITELIST.keySet()) {
            if (providerType.isAssignableFrom(clazz)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Ensure the supplied implementation classes implement the expected contract.
     *
     * @param contract        contract that is expected to be implemented by the implementation classes.
     * @param implementations contract implementations.
     * @throws java.lang.IllegalArgumentException in case any of the implementation classes does not
     *                                            implement the expected contract.
     */
    public static void ensureContract(final Class contract, final Class... implementations) {
        if (implementations == null || implementations.length <= 0) {
            return;
        }

        final StringBuilder invalidClassNames = new StringBuilder();
        for (final Class impl : implementations) {
            if (!contract.isAssignableFrom(impl)) {
                if (invalidClassNames.length() > 0) {
                    invalidClassNames.append(", ");
                }
                invalidClassNames.append(impl.getName());
            }
        }

        if (invalidClassNames.length() > 0) {
            throw new IllegalArgumentException(LocalizationMessages.INVALID_SPI_CLASSES(
                    contract.getName(),
                    invalidClassNames.toString()));
        }

    }

    /**
     * Inject {@code providerInstances}. The method iterates through {@code providerInstances}
     * and initializes injectable fields of each instance using {@code serviceLocator}.
     *
     * @param providerInstances Iterable of provider instances to be injected.
     * @param serviceLocator    Service locator.
     */
    public static  void injectProviders(final Iterable providerInstances, final ServiceLocator serviceLocator) {
        for (final T providerInstance : providerInstances) {
            serviceLocator.inject(providerInstance);
        }

    }

    private static boolean findFirstProviderContract(final Class clazz) {
        for (final Class contract : getImplementedContracts(clazz)) {
            if (isSupportedContract(contract)) {
                return true;
            }
            if (findFirstProviderContract(contract)) {
                return true;
            }
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy