org.glassfish.jersey.inject.hk2.Hk2Helper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxrs-ri Show documentation
Show all versions of jaxrs-ri Show documentation
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.
/*
* Copyright (c) 2017, 2024 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.inject.hk2;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.glassfish.hk2.api.Factory;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.inject.AliasBinding;
import org.glassfish.jersey.internal.inject.Binding;
import org.glassfish.jersey.internal.inject.Bindings;
import org.glassfish.jersey.internal.inject.ClassBinding;
import org.glassfish.jersey.internal.inject.DisposableSupplier;
import org.glassfish.jersey.internal.inject.InjectionResolverBinding;
import org.glassfish.jersey.internal.inject.InstanceBinding;
import org.glassfish.jersey.internal.inject.PerLookup;
import org.glassfish.jersey.internal.inject.PerThread;
import org.glassfish.jersey.internal.inject.SupplierClassBinding;
import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
import org.glassfish.hk2.api.ActiveDescriptor;
import org.glassfish.hk2.api.DynamicConfiguration;
import org.glassfish.hk2.api.DynamicConfigurationService;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
import org.glassfish.hk2.utilities.ActiveDescriptorBuilder;
import org.glassfish.hk2.utilities.Binder;
import org.glassfish.hk2.utilities.BuilderHelper;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.hk2.utilities.binding.ServiceBindingBuilder;
import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl;
/**
* This class contains the convenient methods for translation from jersey classes to HK2 and visa versa, then contains methods
* for binding structures such as {@link org.glassfish.jersey.internal.inject.Binder} or {@link Binding} to a provided service
* locator.
*/
class Hk2Helper {
/**
* Bind a translated Jersey-like {@link org.glassfish.jersey.internal.inject.Binder} to HK2-like {@link Binder}.
*
* @param injectionManager HK2 injection manager.
* @param jerseyBinder Jersey-like binder.
*/
static void bind(AbstractHk2InjectionManager injectionManager, org.glassfish.jersey.internal.inject.Binder jerseyBinder) {
bind(injectionManager.getServiceLocator(), Bindings.getBindings(injectionManager, jerseyBinder));
}
/**
* Bind descriptors to Hk2-like {@link Binder}.
*
* @param locator HK2 locator.
* @param binding single descriptor.
*/
static void bind(ServiceLocator locator, Binding binding) {
bindBinding(locator, binding);
}
/**
* Bind descriptors to Hk2-like {@link Binder}.
*
* @param locator HK2 locator.
* @param descriptors collection of descriptors.
*/
static void bind(ServiceLocator locator, Iterable descriptors) {
DynamicConfiguration dc = getDynamicConfiguration(locator);
for (Binding binding : descriptors) {
bindBinding(locator, dc, binding);
}
dc.commit();
}
/**
* Gets {@link DynamicConfigurationService} object from {@link ServiceLocator HK2 Locator} and creates a new object of
* {@link DynamicConfiguration} to bind new services.
*
* @param locator HK2 locator.
* @return new instance of {@code DynamicConfiguration} to bind new services.
*/
private static DynamicConfiguration getDynamicConfiguration(ServiceLocator locator) {
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
return dcs.createDynamicConfiguration();
}
/**
* Binds the single descriptor using a single {@link DynamicConfiguration}.
*
* @param locator HK2 injection manager.
* @param binding Jersey descriptor as a holder of information about an injection point.
*/
private static void bindBinding(ServiceLocator locator, Binding, ?> binding) {
DynamicConfiguration dc = getDynamicConfiguration(locator);
bindBinding(locator, dc, binding);
dc.commit();
}
/**
* Binds the single descriptor using an external {@link DynamicConfiguration}.
*
* @param locator HK2 injection manager.
* @param dc HK2 Dynamic configuration to bind the object.
* @param binding Jersey descriptor as a holder of information about an injection point.
*/
private static void bindBinding(ServiceLocator locator, DynamicConfiguration dc, Binding binding) {
if (ClassBinding.class.isAssignableFrom(binding.getClass())) {
final Class> implClass = binding.getImplementationType();
if (Factory.class.isAssignableFrom(implClass)) {
final Class extends Factory> factoryClass = (Class extends Factory>) implClass;
bindFactory(locator, binding, (binder) -> binder.bindFactory(factoryClass));
} else {
ActiveDescriptor> activeDescriptor = translateToActiveDescriptor((ClassBinding>) binding);
bindBinding(locator, dc, activeDescriptor, binding.getAliases());
}
} else if (InstanceBinding.class.isAssignableFrom(binding.getClass())) {
if (Factory.class.isAssignableFrom(binding.getImplementationType())) {
final Factory> factory = (Factory) ((InstanceBinding) binding).getService();
bindFactory(locator, binding, (binder) -> binder.bindFactory(factory));
} else {
ActiveDescriptor> activeDescriptor = translateToActiveDescriptor((InstanceBinding>) binding);
bindBinding(locator, dc, activeDescriptor, binding.getAliases());
}
} else if (InjectionResolverBinding.class.isAssignableFrom(binding.getClass())) {
InjectionResolverBinding resolverDescriptor = (InjectionResolverBinding) binding;
bindBinding(locator, dc, wrapInjectionResolver(resolverDescriptor), binding.getAliases());
bindBinding(locator, dc, translateToActiveDescriptor(resolverDescriptor), binding.getAliases());
} else if (SupplierClassBinding.class.isAssignableFrom(binding.getClass())) {
bindSupplierClassBinding(locator, (SupplierClassBinding>) binding);
} else if (SupplierInstanceBinding.class.isAssignableFrom(binding.getClass())) {
bindSupplierInstanceBinding(locator, (SupplierInstanceBinding>) binding);
} else {
throw new RuntimeException(LocalizationMessages.UNKNOWN_DESCRIPTOR_TYPE(binding.getClass().getSimpleName()));
}
}
@SuppressWarnings("unchecked")
private static ActiveDescriptor> wrapInjectionResolver(InjectionResolverBinding resolverDescriptor) {
InjectionResolverWrapper> wrappedResolver = new InjectionResolverWrapper<>(resolverDescriptor.getResolver());
return translateToActiveDescriptor(Bindings.service(wrappedResolver),
new ParameterizedTypeImpl(InjectionResolver.class, resolverDescriptor.getResolver().getAnnotation()));
}
/**
* Registers a new instance {@link Binder} using the information from the Jersey binding {@link SupplierInstanceBinding}.
*
* @param locator HK2 instance manager.
* @param binding Jersey descriptor as a holder of information about an injection point.
*/
private static void bindSupplierInstanceBinding(ServiceLocator locator, SupplierInstanceBinding> binding) {
Consumer bindConsumer = binder -> {
Supplier> supplier = binding.getSupplier();
boolean disposable = DisposableSupplier.class.isAssignableFrom(supplier.getClass());
// Bind the Supplier itself to be able to inject - Supplier or DisposableSupplier;
// The contract of the supplier is not registered that means that the instance of the supplier can be retrieved
// only using Supplier interface and not using implementation class itself. Supplier can be registered only once with
// all provided contracts.
AbstractActiveDescriptor extends Supplier>> supplierBuilder = BuilderHelper.createConstantDescriptor(supplier);
binding.getContracts().forEach(contract -> {
supplierBuilder.addContractType(new ParameterizedTypeImpl(Supplier.class, contract));
if (disposable) {
supplierBuilder.addContractType(new ParameterizedTypeImpl(DisposableSupplier.class, contract));
}
});
// Always call SupplierFactoryBridge.
supplierBuilder.setName(binding.getName());
binding.getQualifiers().forEach(supplierBuilder::addQualifierAnnotation);
binder.bind(supplierBuilder);
// Register wrapper for factory functionality, wrapper automatically call service locator which is able to retrieve
// the service in the proper context and scope. Bridge is registered for all contracts but is able to lookup from
// service locator only using the first contract.
ServiceBindingBuilder> builder = binder.bindFactory(new InstanceSupplierFactoryBridge<>(supplier, disposable));
setupSupplierFactoryBridge(binding, builder);
};
ServiceLocatorUtilities.bind(locator, createBinder(bindConsumer));
}
/**
* Registers a new instance {@link Binder} using the information from the Jersey binding {@link SupplierClassBinding}.
*
* @param locator HK2 instance manager.
* @param binding Jersey descriptor as a holder of information about an injection point.
*/
private static void bindSupplierClassBinding(ServiceLocator locator, SupplierClassBinding> binding) {
Consumer bindConsumer = binder -> {
boolean disposable = DisposableSupplier.class.isAssignableFrom(binding.getSupplierClass());
// Bind the Supplier itself to be able to inject - Supplier supplier;
// The contract of the supplier is not registered that means that the instance of the supplier can be retrieved
// only using Supplier interface and not using implementation class itself. Supplier can be registered only once with
// all provided contracts.
ServiceBindingBuilder> supplierBuilder = binder.bind(binding.getSupplierClass());
binding.getContracts().forEach(contract -> {
supplierBuilder.to(new ParameterizedTypeImpl(Supplier.class, contract));
if (disposable) {
supplierBuilder.to(new ParameterizedTypeImpl(DisposableSupplier.class, contract));
}
});
binding.getQualifiers().forEach(supplierBuilder::qualifiedBy);
supplierBuilder.named(binding.getName());
supplierBuilder.in(transformScope(binding.getSupplierScope()));
binder.bind(supplierBuilder);
// Register wrapper for factory functionality, wrapper automatically call service locator which is able to retrieve
// the service in the proper context and scope. Bridge is registered for all contracts but is able to lookup from
// service locator only using the first contract.
Type contract = null;
if (binding.getContracts().iterator().hasNext()) {
contract = binding.getContracts().iterator().next();
}
ServiceBindingBuilder> builder = binder.bindFactory(
new SupplierFactoryBridge<>(locator, contract, binding.getName(), disposable));
setupSupplierFactoryBridge(binding, builder);
if (binding.getImplementationType() != null) {
builder.asType(binding.getImplementationType());
}
};
ServiceLocatorUtilities.bind(locator, createBinder(bindConsumer));
}
private static void bindFactory(ServiceLocator locator,
Binding binding,
Function builder) {
ServiceLocatorUtilities
.bind(locator, createBinder((binder) -> setupSupplierFactoryBridge(binding, builder.apply(binder))));
}
private static void setupSupplierFactoryBridge(Binding, ?> binding, ServiceBindingBuilder> builder) {
builder.named(binding.getName());
binding.getContracts().forEach(builder::to);
binding.getQualifiers().forEach(builder::qualifiedBy);
builder.in(transformScope(binding.getScope()));
if (binding.getRank() != null) {
builder.ranked(binding.getRank());
}
if (binding.isProxiable() != null) {
builder.proxy(binding.isProxiable());
}
if (binding.isProxiedForSameScope() != null) {
builder.proxyForSameScope(binding.isProxiedForSameScope());
}
}
static ActiveDescriptor> translateToActiveDescriptor(ClassBinding> desc) {
ActiveDescriptorBuilder binding = BuilderHelper.activeLink(desc.getService()).named(desc.getName())
.analyzeWith(desc.getAnalyzer());
if (desc.getScope() != null) {
binding.in(transformScope(desc.getScope()));
}
if (desc.getRank() != null) {
binding.ofRank(desc.getRank());
}
for (Annotation annotation : desc.getQualifiers()) {
binding.qualifiedBy(annotation);
}
for (Type contract : desc.getContracts()) {
binding.to(contract);
}
if (desc.isProxiable() != null) {
binding.proxy(desc.isProxiable());
}
if (desc.isProxiedForSameScope() != null) {
binding.proxyForSameScope(desc.isProxiedForSameScope());
}
if (desc.getImplementationType() != null) {
binding.asType(desc.getImplementationType());
}
return binding.build();
}
/**
* Binds a new instance {@link Binding} using the information from the Jersey descriptor {@link InstanceBinding}.
*
* Along with a new instance, the method is able to register aliases belonging to the new service.
*
* @param locator HK2 injection manager.
* @param dc HK2 Dynamic configuration to bind the object.
* @param activeDescriptor HK2 active descriptor.
* @param aliases aliases belonging to the given descriptor.
*/
private static void bindBinding(ServiceLocator locator, DynamicConfiguration dc, ActiveDescriptor> activeDescriptor,
Set aliases) {
ActiveDescriptor