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

org.glassfish.jersey.internal.inject.ProviderBinder 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.9
Show newest version
/*
 * Copyright (c) 2010, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jersey.internal.inject;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import javax.ws.rs.RuntimeType;

import javax.inject.Singleton;

import org.glassfish.jersey.model.ContractProvider;
import org.glassfish.jersey.model.internal.ComponentBag;
import org.glassfish.jersey.spi.ComponentProvider;

/**
 * Class used for registration of the custom providers into injection manager.
 * 

* Custom providers are classes that implements specific JAX-RS or Jersey * SPI interfaces (e.g. {@link javax.ws.rs.ext.MessageBodyReader}) and are * supplied by the user. These providers will be bound into the injection manager * annotated by a {@link Custom @Custom} qualifier annotation. *

*

* Use the {@code @Custom} qualifier annotation to retrieve these providers * from injection manager. You may also use a one of the provider accessor utility * method defined in {@link Providers} class. *

* * @author Miroslav Fuksa * @author Marek Potociar * @author Michal Gajdos */ public class ProviderBinder { private final InjectionManager injectionManager; /** * Create new provider binder instance. * * @param injectionManager the binder will use to bind the providers into. */ public ProviderBinder(final InjectionManager injectionManager) { this.injectionManager = injectionManager; } /** * Bind contract provider model to a provider class using the supplied injection manager. * * @param providerClass provider class. * @param model contract provider model. */ public static void bindProvider(Class providerClass, ContractProvider model, InjectionManager injectionManager) { final T instance = injectionManager.getInstance(providerClass); if (instance != null) { injectionManager.register(createInstanceBinder(instance, model)); } else { injectionManager.register(createClassBinder(model)); } } private static Binder createInstanceBinder(T instance, ContractProvider model) { return new AbstractBinder() { @Override protected void configure() { final InstanceBinding binding = bind(instance) .in(model.getScope()) .qualifiedBy(CustomAnnotationLiteral.INSTANCE); binding.to(model.getContracts()); int priority = model.getPriority(model.getImplementationClass()); if (priority > ContractProvider.NO_PRIORITY) { binding.ranked(priority); } } }; } private static Binder createClassBinder(ContractProvider model) { return new AbstractBinder() { @Override protected void configure() { final ClassBinding binding = bind(model.getImplementationClass()) .in(model.getScope()) .qualifiedBy(CustomAnnotationLiteral.INSTANCE); binding.to(model.getContracts()); int priority = model.getPriority(model.getImplementationClass()); if (priority > ContractProvider.NO_PRIORITY) { binding.ranked(priority); } } }; } private static Collection createProviderBinders(Class providerClass, ContractProvider model) { /* Create a Binder of the Provider with the concrete contract. */ Function binderFunction = contract -> new AbstractBinder() { @Override @SuppressWarnings("unchecked") protected void configure() { ClassBinding builder = bind(providerClass) .in(model.getScope()) .qualifiedBy(CustomAnnotationLiteral.INSTANCE) .to(contract); int priority = model.getPriority(contract); if (priority > ContractProvider.NO_PRIORITY) { builder.ranked(priority); } } }; /* Create Binders with all contracts and return their collection. */ return model.getContracts().stream() .map(binderFunction) .collect(Collectors.toList()); } /** * Bind contract provider model to a provider instance using the supplied injection manager. *

* Scope value specified in the {@link ContractProvider contract provider model} * is ignored as instances can only be bound as "singletons". * * @param providerInstance provider instance. * @param model contract provider model. */ public static void bindProvider(Object providerInstance, ContractProvider model, InjectionManager injectionManager) { injectionManager.register(createInstanceBinder(providerInstance, model)); } private static Collection createProviderBinders(Object providerInstance, ContractProvider model) { /* Create a Binder of the Provider with the concrete contract. */ Function binderFunction = contract -> new AbstractBinder() { @Override @SuppressWarnings("unchecked") protected void configure() { InstanceBinding builder = bind(providerInstance) .qualifiedBy(CustomAnnotationLiteral.INSTANCE) .to(contract); int priority = model.getPriority(contract); if (priority > ContractProvider.NO_PRIORITY) { builder.ranked(priority); } } }; /* Create Binders with all contracts and return their collection. */ return model.getContracts().stream() .map(binderFunction) .collect(Collectors.toList()); } /** * Bind all providers contained in {@code providerBag} (classes and instances) using injection manager. Configuration is * also committed. * * @param componentBag bag of provider classes and instances. * @param injectionManager injection manager the binder will use to bind the providers into. */ public static void bindProviders(final ComponentBag componentBag, final InjectionManager injectionManager) { bindProviders(componentBag, null, null, injectionManager, null); } /** * Bind all providers contained in {@code providerBag} (classes and instances) using injection manager. Configuration is * also committed. * * @param componentBag bag of provider classes and instances. * @param constrainedTo current runtime (client or server). * @param registeredClasses classes which are manually registered by the user (not found by the classpath scanning). * @param injectionManager injection manager the binder will use to bind the providers into. */ @Deprecated // backward compatibility until JPMS public static void bindProviders(ComponentBag componentBag, RuntimeType constrainedTo, Set> registeredClasses, InjectionManager injectionManager) { bindProviders(componentBag, constrainedTo, registeredClasses, injectionManager, null); } /** * Bind all providers contained in {@code providerBag} (classes and instances) using injection manager. Configuration is * also committed. * * @param componentBag bag of provider classes and instances. * @param constrainedTo current runtime (client or server). * @param registeredClasses classes which are manually registered by the user (not found by the classpath scanning). * @param injectionManager injection manager the binder will use to bind the providers into. * @param componentProviders available component providers capable of registering the classes */ public static void bindProviders(ComponentBag componentBag, RuntimeType constrainedTo, Set> registeredClasses, InjectionManager injectionManager, Collection componentProviders) { Predicate filter = ComponentBag.EXCLUDE_EMPTY .and(ComponentBag.excludeMetaProviders(injectionManager)); /* * Check the {@code component} whether it is correctly configured for client or server {@link RuntimeType runtime}. */ Predicate> correctlyConfigured = componentClass -> Providers.checkProviderRuntime( componentClass, componentBag.getModel(componentClass), constrainedTo, registeredClasses == null || !registeredClasses.contains(componentClass), false); /* * These binder will be registered to InjectionManager at the end of method because of a bulk registration to avoid a * registration each binder alone. */ Collection binderToRegister = new ArrayList<>(); // Bind provider classes except for pure meta-providers and providers with empty contract models (e.g. resources) Set> classes = new LinkedHashSet<>(componentBag.getClasses(filter)); if (constrainedTo != null) { classes = classes.stream() .filter(correctlyConfigured) .collect(Collectors.toSet()); } for (final Class providerClass : classes) { final ContractProvider model = componentBag.getModel(providerClass); if (componentProviders == null || !bindWithComponentProvider(providerClass, model, componentProviders)) { binderToRegister.addAll(createProviderBinders(providerClass, model)); } } // Bind provider instances except for pure meta-providers and providers with empty contract models (e.g. resources) Set instances = componentBag.getInstances(filter); if (constrainedTo != null) { instances = instances.stream() .filter(component -> correctlyConfigured.test(component.getClass())) .collect(Collectors.toSet()); } for (final Object provider : instances) { final ContractProvider model = componentBag.getModel(provider.getClass()); binderToRegister.addAll(createProviderBinders(provider, model)); } injectionManager.register(CompositeBinder.wrap(binderToRegister)); } private static boolean bindWithComponentProvider( Class component, ContractProvider providerModel, Iterable componentProviders) { for (ComponentProvider provider : componentProviders) { if (provider.bind(component, providerModel)) { return true; } } return false; } @SuppressWarnings("unchecked") private static Collection createInstanceBinders(T instance) { Function binderFunction = contract -> new AbstractBinder() { @Override protected void configure() { bind(instance).to(contract).qualifiedBy(CustomAnnotationLiteral.INSTANCE); } }; return Providers.getProviderContracts(instance.getClass()).stream() .map(binderFunction) .collect(Collectors.toList()); } /** * Register/bind custom provider instances. Registered providers will be handled * always as Singletons. * * @param instances custom provider instances. */ public void bindInstances(final Iterable instances) { List instancesList = new ArrayList<>(); instances.forEach(instancesList::add); bindInstances(instancesList); } /** * Register/bind custom provider instances. Registered providers will be handled * always as Singletons. * * @param instances custom provider instances. */ public void bindInstances(final Collection instances) { List binders = instances.stream() .map(ProviderBinder::createInstanceBinders) .flatMap(Collection::stream) .collect(Collectors.toList()); injectionManager.register(CompositeBinder.wrap(binders)); } /** * Register/bind custom provider classes. Registered providers will be handled * always as Singletons unless annotated by {@link PerLookup}. * * @param classes custom provider classes. */ public void bindClasses(final Class... classes) { bindClasses(Arrays.asList(classes), false); } /** * Register/bind custom provider classes. Registered providers will be handled * always as Singletons unless annotated by {@link PerLookup}. * * @param classes custom provider classes. */ public void bindClasses(final Iterable> classes) { List> classesList = new ArrayList<>(); classes.forEach(classesList::add); bindClasses(classesList, false); } /** * Register/bind custom provider classes. Registered providers will be handled * always as Singletons unless annotated by {@link PerLookup}. * * @param classes custom provider classes. */ public void bindClasses(final Collection> classes) { bindClasses(classes, false); } /** * Register/bind custom provider classes that may also be resources. Registered * providers/resources will be handled always as Singletons unless annotated by * {@link PerLookup}. *

*

* If {@code bindAsResources} is set to {@code true}, the providers will also be bound * as resources. *

* * @param classes custom provider classes. * @param bindResources if {@code true}, the provider classes will also be bound as * resources. */ public void bindClasses(Collection> classes, boolean bindResources) { List binders = classes.stream() .map(clazz -> createClassBinders(clazz, bindResources)) .collect(Collectors.toList()); injectionManager.register(CompositeBinder.wrap(binders)); } @SuppressWarnings("unchecked") private Binder createClassBinders(Class clazz, boolean isResource) { final Class scope = getProviderScope(clazz); if (isResource) { return new AbstractBinder() { @Override protected void configure() { ClassBinding descriptor = bindAsContract(clazz).in(scope); for (Class contract : Providers.getProviderContracts(clazz)) { descriptor.addAlias(contract) .in(scope.getName()) .qualifiedBy(CustomAnnotationLiteral.INSTANCE); } } }; } else { return new AbstractBinder() { @Override protected void configure() { ClassBinding builder = bind(clazz).in(scope).qualifiedBy(CustomAnnotationLiteral.INSTANCE); Providers.getProviderContracts(clazz).forEach(contract -> builder.to((Class) contract)); } }; } } private Class getProviderScope(final Class clazz) { Class scope = Singleton.class; if (clazz.isAnnotationPresent(PerLookup.class)) { scope = PerLookup.class; } return scope; } }