Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.glassfish.jersey.client.innate.inject.NonInjectionManager Maven / Gradle / Ivy
/*
* Copyright (c) 2023 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.client.innate.inject;
import org.glassfish.jersey.client.internal.LocalizationMessages;
import org.glassfish.jersey.internal.inject.Binder;
import org.glassfish.jersey.internal.inject.Binding;
import org.glassfish.jersey.internal.inject.ClassBinding;
import org.glassfish.jersey.internal.inject.DisposableSupplier;
import org.glassfish.jersey.internal.inject.ForeignDescriptor;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.inject.InstanceBinding;
import org.glassfish.jersey.internal.inject.PerThread;
import org.glassfish.jersey.internal.inject.ServiceHolder;
import org.glassfish.jersey.internal.inject.ServiceHolderImpl;
import org.glassfish.jersey.internal.inject.SupplierClassBinding;
import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
import org.glassfish.jersey.internal.util.collection.LazyValue;
import org.glassfish.jersey.internal.util.collection.Value;
import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.process.internal.RequestScope;
import org.glassfish.jersey.process.internal.RequestScoped;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.inject.Singleton;
import jakarta.ws.rs.ConstrainedTo;
import jakarta.ws.rs.RuntimeType;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@ConstrainedTo(RuntimeType.CLIENT)
public final class NonInjectionManager implements InjectionManager {
private static final Logger logger = Logger.getLogger(NonInjectionManager.class.getName());
private final MultivaluedMap, InstanceBinding> instanceBindings = new MultivaluedHashMap<>();
private final MultivaluedMap, ClassBinding> contractBindings = new MultivaluedHashMap<>();
private final MultivaluedMap, SupplierInstanceBinding> supplierInstanceBindings = new MultivaluedHashMap<>();
private final MultivaluedMap, SupplierClassBinding> supplierClassBindings = new MultivaluedHashMap<>();
private final MultivaluedMap> instanceTypeBindings = new MultivaluedHashMap<>();
private final MultivaluedMap> contractTypeBindings = new MultivaluedHashMap<>();
private final MultivaluedMap> supplierTypeInstanceBindings = new MultivaluedHashMap<>();
private final MultivaluedMap> supplierTypeClassBindings = new MultivaluedHashMap<>();
private final MultivaluedMap disposableSupplierObjects = new MultivaluedHashMap<>();
private final Instances instances = new Instances();
private final Types types = new Types();
private volatile boolean isRequestScope = false;
private volatile boolean shutdown = false;
/**
* A class that holds singleton instances and thread-scope instances. Provides thread safe access to singletons
* and thread-scope instances. The instances are created for Type (ParametrizedType) and for a Class.
* @param the type for which the instance is created, either Class, or ParametrizedType (for instance
* Provider<SomeClass>).
*/
private class TypedInstances {
private final MultivaluedMap> singletonInstances = new MultivaluedHashMap<>();
private final ThreadLocal>> threadInstances = new ThreadLocal<>();
private final List threadPredestroyables = Collections.synchronizedList(new LinkedList<>());
private List> _getSingletons(TYPE clazz) {
List> si;
synchronized (singletonInstances) {
si = singletonInstances.get(clazz);
}
return si;
}
@SuppressWarnings("unchecked")
T _addSingleton(TYPE clazz, T instance, Binding binding, Annotation[] qualifiers) {
synchronized (singletonInstances) {
// check existing singleton with a qualifier already created by another thread io a meantime
List> values = singletonInstances.get(clazz);
if (values != null) {
List> qualified
= values.stream()
.filter(ctx -> ctx.hasQualifiers(qualifiers))
.collect(Collectors.toList());
if (!qualified.isEmpty()) {
return (T) qualified.get(0).instance;
}
}
singletonInstances.add(clazz, new InstanceContext<>(instance, binding, qualifiers));
threadPredestroyables.add(instance);
return instance;
}
}
@SuppressWarnings("unchecked")
T addSingleton(TYPE clazz, T t, Binding binding, Annotation[] instanceQualifiers) {
T t2 = _addSingleton(clazz, t, binding, instanceQualifiers);
if (t2 == t) {
for (Type contract : binding.getContracts()) {
if (!clazz.equals(contract) && isClass(contract)) {
_addSingleton((TYPE) contract, t, binding, instanceQualifiers);
}
}
}
return t2;
}
private List> _getThreadInstances(TYPE clazz) {
MultivaluedMap> ti = threadInstances.get();
List> list = ti == null ? null : new LinkedList<>();
if (ti != null) {
return ti.get(clazz);
}
return list;
}
private void _addThreadInstance(TYPE clazz, T instance, Binding binding, Annotation[] qualifiers) {
MultivaluedMap> map = threadInstances.get();
if (map == null) {
map = new MultivaluedHashMap<>();
threadInstances.set(map);
}
map.add(clazz, new InstanceContext<>(instance, binding, qualifiers));
threadPredestroyables.add(instance);
}
void addThreadInstance(TYPE clazz, T t, Binding binding, Annotation[] instanceQualifiers) {
_addThreadInstance(clazz, t, binding, instanceQualifiers);
for (Type contract : binding.getContracts()) {
if (!clazz.equals(contract) && isClass(contract)) {
_addThreadInstance((TYPE) contract, t, binding, instanceQualifiers);
}
}
}
private List getInstances(TYPE clazz, Annotation[] annotations) {
List> i = _getContexts(clazz);
return InstanceContext.toInstances(i, annotations);
}
List> getContexts(TYPE clazz, Annotation[] annotations) {
List> i = _getContexts(clazz);
return InstanceContext.filterInstances(i, annotations);
}
private List> _getContexts(TYPE clazz) {
List> si = _getSingletons(clazz);
List> ti = _getThreadInstances(clazz);
if (si == null && ti != null) {
si = ti;
} else if (ti != null) {
si.addAll(ti);
}
return si;
}
T getInstance(TYPE clazz, Annotation[] annotations) {
List i = getInstances(clazz, annotations);
if (i != null) {
checkUnique(i);
return i.get(0);
}
return null;
}
void dispose() {
singletonInstances.forEach((clazz, instances) -> instances.forEach(instance -> preDestroy(instance.getInstance())));
threadPredestroyables.forEach(NonInjectionManager.this::preDestroy);
}
}
private class Instances extends TypedInstances> {
}
private class Types extends TypedInstances {
}
public NonInjectionManager() {
}
public NonInjectionManager(boolean warning) {
if (warning) {
logger.warning(LocalizationMessages.NONINJECT_FALLBACK());
} else {
logger.log(Level.FINER, LocalizationMessages.NONINJECT_FALLBACK());
}
}
@Override
public void completeRegistration() {
instances._addSingleton(InjectionManager.class, this, new InjectionManagerBinding(), null);
}
@Override
public void shutdown() {
shutdown = true;
disposableSupplierObjects.forEach((supplier, objects) -> objects.forEach(supplier::dispose));
disposableSupplierObjects.clear();
instances.dispose();
types.dispose();
}
@Override
public boolean isShutdown() {
return shutdown;
}
private void checkShutdown() {
if (shutdown) {
throw new IllegalStateException(LocalizationMessages.NONINJECT_SHUTDOWN());
}
}
@Override
public void register(Binding binding) {
checkShutdown();
if (InstanceBinding.class.isInstance(binding)) {
InstanceBinding instanceBinding = (InstanceBinding) binding;
Class mainType = binding.getImplementationType();
if (!instanceBindings.containsKey(mainType)) { // the class could be registered twice, for reader & for writer
instanceBindings.add(mainType, (InstanceBinding) binding);
}
for (Type type : (Iterable) instanceBinding.getContracts()) {
if (isClass(type)) {
if (!mainType.equals(type)) {
instanceBindings.add((Class) type, instanceBinding);
}
} else {
instanceTypeBindings.add(type, instanceBinding);
}
}
} else if (ClassBinding.class.isInstance(binding)) {
ClassBinding contractBinding = (ClassBinding) binding;
Class mainType = binding.getImplementationType();
if (!contractBindings.containsKey(mainType)) { // the class could be registered twice, for reader & for writer
contractBindings.add(mainType, contractBinding);
}
for (Type type : contractBinding.getContracts()) {
if (isClass(type)) {
if (!mainType.equals(type)) {
contractBindings.add((Class) type, contractBinding);
}
} else {
contractTypeBindings.add(type, contractBinding);
}
}
} else if (SupplierInstanceBinding.class.isInstance(binding)) {
SupplierInstanceBinding supplierBinding = (SupplierInstanceBinding) binding;
for (Type type : supplierBinding.getContracts()) {
if (isClass(type)) {
supplierInstanceBindings.add((Class) type, supplierBinding);
} else {
supplierTypeInstanceBindings.add(type, supplierBinding);
}
}
} else if (SupplierClassBinding.class.isInstance(binding)) {
SupplierClassBinding supplierBinding = (SupplierClassBinding) binding;
for (Type type : supplierBinding.getContracts()) {
if (isClass(type)) {
supplierClassBindings.add((Class) type, supplierBinding);
} else {
supplierTypeClassBindings.add(type, supplierBinding);
}
}
}
}
@Override
public void register(Iterable descriptors) {
checkShutdown();
for (Binding binding : descriptors) {
register(binding);
}
}
@Override
public void register(Binder binder) {
checkShutdown();
binder.getBindings().stream().iterator().forEachRemaining(this::register);
}
@Override
public void register(Object provider) throws IllegalArgumentException {
throw new UnsupportedOperationException("Register " + provider);
}
@Override
public boolean isRegistrable(Class clazz) {
return false; // for external creators
}
@Override
public List> getAllServiceHolders(Class contractOrImpl, Annotation... qualifiers) {
checkShutdown();
ClassBindings classBindings = classBindings(contractOrImpl, qualifiers);
return classBindings.getAllServiceHolders(qualifiers);
}
@Override
public T getInstance(Class contractOrImpl, Annotation... qualifiers) {
checkShutdown();
ClassBindings classBindings = classBindings(contractOrImpl, qualifiers);
classBindings.matchQualifiers(qualifiers);
return classBindings.getInstance();
}
@Override
public T getInstance(Class contractOrImpl, String classAnalyzer) {
throw new UnsupportedOperationException("getInstance(Class, String)");
}
@Override
public T getInstance(Class contractOrImpl) {
checkShutdown();
T instance = instances.getInstance(contractOrImpl, null);
if (instance != null) {
return instance;
}
return create(contractOrImpl);
}
@Override
@SuppressWarnings("unchecked")
public T getInstance(Type contractOrImpl) {
checkShutdown();
if (ParameterizedType.class.isInstance(contractOrImpl)) {
T instance = types.getInstance(contractOrImpl, null);
if (instance != null) {
return instance;
}
TypeBindings typeBindings = typeBindings(contractOrImpl);
return typeBindings.getInstance();
} else if (isClass(contractOrImpl)) {
return getInstance((Class) contractOrImpl);
}
throw new IllegalStateException(LocalizationMessages.NONINJECT_UNSATISFIED(contractOrImpl));
}
private static boolean isClass(Type type) {
return Class.class.isAssignableFrom(type.getClass());
}
@Override
public Object getInstance(ForeignDescriptor foreignDescriptor) {
throw new UnsupportedOperationException("getInstance(ForeignDescriptor foreignDescriptor) ");
}
@Override
public ForeignDescriptor createForeignDescriptor(Binding binding) {
throw new UnsupportedOperationException("createForeignDescriptor(Binding binding) ");
}
@Override
public List getAllInstances(Type contractOrImpl) {
checkShutdown();
if (!isClass(contractOrImpl)) {
TypeBindings typeBindings = typeBindings(contractOrImpl);
return typeBindings.allInstances();
}
@SuppressWarnings("unchecked")
ClassBindings classBindings = classBindings((Class) contractOrImpl);
return classBindings.allInstances();
}
@SuppressWarnings("unchecked")
@Override
public T create(Class createMe) {
checkShutdown();
if (InjectionManager.class.equals(createMe)) {
return (T) this;
}
if (RequestScope.class.equals(createMe)) {
if (!isRequestScope) {
isRequestScope = true;
return (T) new NonInjectionRequestScope();
} else {
throw new IllegalStateException(LocalizationMessages.NONINJECT_REQUESTSCOPE_CREATED());
}
}
ClassBindings classBindings = classBindings(createMe);
return classBindings.create();
}
private T justCreate(Class createMe) {
T result = null;
try {
Constructor mostArgConstructor = findConstructor(createMe);
if (mostArgConstructor != null) {
int argCount = mostArgConstructor.getParameterCount();
if (argCount == 0) {
ensureAccessible(mostArgConstructor);
result = mostArgConstructor.newInstance();
} else if (argCount > 0) {
Object[] args = getArguments(mostArgConstructor, argCount);
if (args != null) {
ensureAccessible(mostArgConstructor);
result = mostArgConstructor.newInstance(args);
}
}
}
if (result == null) {
throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_CONSTRUCTOR(createMe.getName()));
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
inject(result);
return result;
}
private static Constructor findConstructor(Class forClass) {
Constructor[] constructors = (Constructor[]) forClass.getDeclaredConstructors();
Constructor mostArgConstructor = null;
int argCount = -1;
for (Constructor constructor : constructors) {
if (constructor.isAnnotationPresent(Inject.class) || constructor.getParameterCount() == 0) {
if (constructor.getParameterCount() > argCount) {
mostArgConstructor = constructor;
argCount = constructor.getParameterCount();
}
}
}
return mostArgConstructor;
}
private Object[] getArguments(Executable executable, int argCount) {
if (executable == null) {
return null;
}
Object[] args = new Object[argCount];
for (int i = 0; i != argCount; i++) {
Type type = executable.getAnnotatedParameterTypes()[i].getType();
args[i] = isClass(type) ? getInstance((Class) type) : getInstance(type);
}
return args;
}
private static void ensureAccessible(Executable executable) {
try {
if (!executable.isAccessible()) {
executable.setAccessible(true);
}
} catch (Exception e) {
// consume. It will fail later with invoking the executable
}
}
private void checkUnique(List list) {
if (list.size() != 1) {
throw new IllegalStateException(LocalizationMessages.NONINJECT_AMBIGUOUS_SERVICES(list.get(0)));
}
}
@Override
public T createAndInitialize(Class createMe) {
return justCreate(createMe);
}
@Override
public void inject(Object injectMe) {
Method postConstruct = getAnnotatedMethod(injectMe, PostConstruct.class);
if (postConstruct != null) {
ensureAccessible(postConstruct);
try {
postConstruct.invoke(injectMe);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
@Override
public void inject(Object injectMe, String classAnalyzer) {
throw new UnsupportedOperationException("inject(Object injectMe, String classAnalyzer)");
}
@Override
public void preDestroy(Object preDestroyMe) {
Method preDestroy = getAnnotatedMethod(preDestroyMe, PreDestroy.class);
if (preDestroy != null) {
ensureAccessible(preDestroy);
try {
preDestroy.invoke(preDestroyMe);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
private static Method getAnnotatedMethod(Object object, Class annotation) {
Class clazz = object.getClass();
for (Method method : clazz.getMethods()) {
if (method.isAnnotationPresent(annotation)
&& /* do not invoke interceptors */ method.getParameterCount() == 0) {
return method;
}
}
return null;
}
/**
* Some {@link Binding} requires the proxy to be created rather than just the instance,
* for instance a proxy of an instance supplied by a supplier that is not known at a time of the proxy creation.
* @param createProxy the nullable {@link Binding#isProxiable()} information
* @param iface the type of which the proxy is created
* @param supplier the reference to the supplier
* @param the type the supplier should supply
* @return The proxy for the instance supplied by a supplier or the instance if not required to be proxied.
*/
@SuppressWarnings("unchecked")
private T createSupplierProxyIfNeeded(Boolean createProxy, Class iface, Supplier supplier) {
if (createProxy != null && createProxy && iface.isInterface()) {
T proxy = (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, new InvocationHandler() {
final SingleRegisterSupplier singleSupplierRegister = new SingleRegisterSupplier<>(supplier);
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
T t = singleSupplierRegister.get();
Object ret = method.invoke(t, args);
return ret;
}
});
return proxy;
} else {
return registerDisposableSupplierAndGet(supplier);
}
}
/**
* A holder class making sure the Supplier (especially the {@link DisposableSupplier}) supplying the instance
* supplies (and is registered for being disposed at the end of the lifecycle) only once.
* @param
*/
private class SingleRegisterSupplier {
private final LazyValue once;
private SingleRegisterSupplier(Supplier supplier) {
once = Values.lazy((Value) () -> registerDisposableSupplierAndGet(supplier));
}
T get() {
return once.get();
}
}
private T registerDisposableSupplierAndGet(Supplier supplier) {
T instance = supplier.get();
if (DisposableSupplier.class.isInstance(supplier)) {
disposableSupplierObjects.add((DisposableSupplier) supplier, instance);
}
return instance;
}
/**
* Create {@link ClassBindings} instance containing bindings and instances for the given Type.
* @param clazz the given class.
* @param instancesQualifiers The qualifiers the expected instances of the given class should have.
* @param Expected return class type.
* @return the {@link ClassBindings}.
*/
@SuppressWarnings("unchecked")
private ClassBindings classBindings(Class clazz, Annotation... instancesQualifiers) {
ClassBindings classBindings = new ClassBindings<>(clazz, instancesQualifiers);
List> ib = instanceBindings.get(clazz);
if (ib != null) {
ib.forEach(binding -> classBindings.instanceBindings.add((InstanceBinding) binding));
}
List> sib = supplierInstanceBindings.get(clazz);
if (sib != null) {
sib.forEach(binding -> classBindings.supplierInstanceBindings.add((SupplierInstanceBinding) binding));
}
List> cb = contractBindings.get(clazz);
if (cb != null) {
cb.forEach(binding -> classBindings.classBindings.add((ClassBinding) binding));
}
List> scb = supplierClassBindings.get(clazz);
if (scb != null) {
scb.forEach(binding -> classBindings.supplierClassBindings.add((SupplierClassBinding) binding));
}
return classBindings;
}
/**
* Create {@link TypeBindings} instance containing bindings and instances for the given Type.
* @param type the given type.
* @param Expected return type.
* @return the {@link TypeBindings}.
*/
@SuppressWarnings("unchecked")
private TypeBindings typeBindings(Type type) {
TypeBindings typeBindings = new TypeBindings<>(type);
List> ib = instanceTypeBindings.get(type);
if (ib != null) {
ib.forEach(binding -> typeBindings.instanceBindings.add((InstanceBinding) binding));
}
List> sib = supplierTypeInstanceBindings.get(type);
if (sib != null) {
sib.forEach(binding -> typeBindings.supplierInstanceBindings.add((SupplierInstanceBinding) binding));
}
List> cb = contractTypeBindings.get(type);
if (cb != null) {
cb.forEach(binding -> typeBindings.classBindings.add((ClassBinding) binding));
}
List> scb = supplierTypeClassBindings.get(type);
if (scb != null) {
scb.forEach(binding -> typeBindings.supplierClassBindings.add((SupplierClassBinding) binding));
}
return typeBindings;
}
/**
*
* A class that contains relevant bindings for a given TYPE, filtered from all registered bindings.
* The TYPE is either Type (ParametrizedType) or Class.
*
*
* The class also filters any bindings for which the singleton or thread-scoped instance already is created.
* The class either provides the existing instance, or all instances of the TYPE, or {@link ServiceHolder}s.
*
* @param The expected return type for the TYPE.
* @param The Type for which a {@link Binding} has been created.
*/
private abstract class XBindings {
protected final List> instanceBindings = new LinkedList<>();
protected final List> supplierInstanceBindings = new LinkedList<>();
protected final List> classBindings = new LinkedList<>();
protected final List> supplierClassBindings = new LinkedList<>();
protected final TYPE type;
protected final Annotation[] instancesQualifiers;
protected final TypedInstances instances;
protected XBindings(TYPE type, Annotation[] instancesQualifiers, TypedInstances instances) {
this.type = type;
this.instancesQualifiers = instancesQualifiers;
this.instances = instances;
}
int size() {
return instanceBindings.size()
+ supplierInstanceBindings.size()
+ classBindings.size()
+ supplierClassBindings.size();
}
private void _checkUnique() {
if (size() > 1) {
throw new IllegalStateException(LocalizationMessages.NONINJECT_AMBIGUOUS_SERVICES(type));
}
}
void filterBinding(Binding binding) {
if (InstanceBinding.class.isInstance(binding)) {
instanceBindings.remove(binding);
} else if (ClassBinding.class.isInstance(binding)) {
classBindings.remove(binding);
} else if (SupplierInstanceBinding.class.isInstance(binding)) {
supplierInstanceBindings.remove(binding);
} else if (SupplierClassBinding.class.isInstance(binding)) {
supplierClassBindings.remove(binding);
}
}
/**
* Match the binging qualifiers
* @param bindingQualifiers the qualifiers registered with the bindings
*/
void matchQualifiers(Annotation... bindingQualifiers) {
if (bindingQualifiers != null) {
_filterRequested(instanceBindings, bindingQualifiers);
_filterRequested(classBindings, bindingQualifiers);
_filterRequested(supplierInstanceBindings, bindingQualifiers);
_filterRequested(supplierClassBindings, bindingQualifiers);
}
}
@SuppressWarnings("unchecked")
private void _filterRequested(List> bindingList, Annotation... requestedQualifiers) {
for (Iterator bindingIterator = bindingList.iterator(); bindingIterator.hasNext();) {
Binding binding = bindingIterator.next();
classLoop:
for (Annotation requestedQualifier : requestedQualifiers) {
for (Annotation bindingQualifier : binding.getQualifiers()) {
if (requestedQualifier.annotationType().isInstance(bindingQualifier)) {
continue classLoop;
}
}
bindingIterator.remove();
}
}
}
protected boolean _isPerThread(Class scope) {
return RequestScoped.class.equals(scope) || PerThread.class.equals(scope);
}
private X _getInstance(InstanceBinding instanceBinding) {
return instanceBinding.getService();
}
private X _create(SupplierInstanceBinding binding) {
Supplier supplier = binding.getSupplier();
X t = registerDisposableSupplierAndGet(supplier);
if (Singleton.class.equals(binding.getScope())) {
_addInstance(t, binding);
} else if (_isPerThread(binding.getScope())) {
_addThreadInstance(t, binding);
}
return t;
}
X create() {
_checkUnique();
if (!instanceBindings.isEmpty()) {
return _getInstance(instanceBindings.get(0));
} else if (!supplierInstanceBindings.isEmpty()) {
return _create(supplierInstanceBindings.get(0));
} else if (!classBindings.isEmpty()) {
return _createAndStore(classBindings.get(0));
} else if (!supplierClassBindings.isEmpty()) {
return _create(supplierClassBindings.get(0));
}
throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_BINDING(type));
}
protected X getInstance() {
X instance = instances.getInstance(type, instancesQualifiers);
if (instance != null) {
return instance;
}
return create();
}
List allInstances() {
List list = new LinkedList<>();
List> instanceContextList;
instanceContextList = instances.getContexts(type, instancesQualifiers);
if (instanceContextList != null) {
instanceContextList.forEach(instanceContext -> filterBinding(instanceContext.getBinding()));
instanceContextList.forEach(instanceContext -> list.add((X) instanceContext.getInstance()));
}
list.addAll(instanceBindings.stream()
.map(this::_getInstance)
.collect(Collectors.toList()));
list.addAll(classBindings.stream()
.map(this::_createAndStore)
.collect(Collectors.toList()));
list.addAll(supplierInstanceBindings.stream()
.map(this::_create)
.collect(Collectors.toList()));
list.addAll(supplierClassBindings.stream()
.map(this::_create)
.collect(Collectors.toList()));
return list;
}
protected abstract X _create(SupplierClassBinding binding);
protected abstract X _createAndStore(ClassBinding binding);
protected T _addInstance(TYPE type, T instance, Binding binding) {
return instances.addSingleton(type, instance, binding, instancesQualifiers);
}
protected void _addThreadInstance(TYPE type, Object instance, Binding binding) {
instances.addThreadInstance(type, instance, binding, instancesQualifiers);
}
protected T _addInstance(T instance, Binding binding) {
return instances.addSingleton(type, instance, binding, instancesQualifiers);
}
protected void _addThreadInstance(Object instance, Binding binding) {
instances.addThreadInstance(type, instance, binding, instancesQualifiers);
}
}
private class ClassBindings extends XBindings> {
private ClassBindings(Class clazz, Annotation[] instancesQualifiers) {
super(clazz, instancesQualifiers, NonInjectionManager.this.instances);
}
@SuppressWarnings("unchecked")
List> getAllServiceHolders(Annotation... qualifiers) {
matchQualifiers(qualifiers);
List> holders = new LinkedList<>();
List> instanceContextList;
instanceContextList = instances.getContexts(type, qualifiers);
if (instanceContextList != null) {
instanceContextList.forEach(instanceContext -> filterBinding(instanceContext.getBinding()));
instanceContextList.forEach(instanceContext -> holders.add(new ServiceHolderImpl(
(T) instanceContext.getInstance(),
(Class) instanceContext.getInstance().getClass(),
instanceContext.getBinding().getContracts(),
instanceContext.getBinding().getRank() == null ? 0 : instanceContext.getBinding().getRank())
));
}
List> instanceBindingHolders = instanceBindings.stream()
.map(this::_serviceHolder)
.collect(Collectors.toList());
holders.addAll(instanceBindingHolders);
List> classBindingHolders = classBindings.stream()
.filter(binding -> NonInjectionManager.this.findConstructor(binding.getService()) != null)
.map(this::_serviceHolder)
.collect(Collectors.toList());
holders.addAll(classBindingHolders);
return holders;
}
private ServiceHolderImpl _serviceHolder(InstanceBinding binding) {
return new ServiceHolderImpl(
binding.getService(),
binding.getImplementationType(),
binding.getContracts(),
binding.getRank() == null ? 0 : binding.getRank());
}
private ServiceHolderImpl _serviceHolder(ClassBinding binding) {
return new ServiceHolderImpl(
NonInjectionManager.this.create(binding.getService()),
binding.getImplementationType(),
binding.getContracts(),
binding.getRank() == null ? 0 : binding.getRank());
}
protected T _create(SupplierClassBinding binding) {
Supplier supplier = instances.getInstance(binding.getSupplierClass(), null);
if (supplier == null) {
supplier = justCreate(binding.getSupplierClass());
if (Singleton.class.equals(binding.getSupplierScope())) {
supplier = instances.addSingleton(binding.getSupplierClass(), supplier, binding, null);
} else if (_isPerThread(binding.getSupplierScope())) {
instances.addThreadInstance(binding.getSupplierClass(), supplier, binding, null);
}
}
T t = createSupplierProxyIfNeeded(binding.isProxiable(), (Class) type, supplier);
if (Singleton.class.equals(binding.getScope())) {
t = _addInstance(type, t, binding);
} else if (_isPerThread(binding.getScope())) {
_addThreadInstance(type, t, binding);
}
return t;
}
protected T _createAndStore(ClassBinding binding) {
T result = justCreate(binding.getService());
result = _addInstance(binding.getService(), result, binding);
return result;
}
}
private class TypeBindings extends XBindings {
private TypeBindings(Type type) {
super(type, null, types);
}
protected T _create(SupplierClassBinding binding) {
Supplier supplier = justCreate(binding.getSupplierClass());
T t = registerDisposableSupplierAndGet(supplier);
if (Singleton.class.equals(binding.getScope())) {
t = _addInstance(type, t, binding);
} else if (_isPerThread(binding.getScope())) {
_addThreadInstance(type, t, binding);
}
return t;
}
@Override
protected T _createAndStore(ClassBinding binding) {
T result = justCreate(binding.getService());
result = _addInstance(type, result, binding);
return result;
}
@SuppressWarnings("unchecked")
@Override
T create() {
if (ParameterizedType.class.isInstance(type)) {
ParameterizedType pt = (ParameterizedType) type;
if (Provider.class.equals(pt.getRawType())) {
return (T) new Provider() {
final SingleRegisterSupplier supplier = new SingleRegisterSupplier<>(new Supplier() {
@Override
public Object get() {
Type actualTypeArgument = pt.getActualTypeArguments()[0];
if (isClass(actualTypeArgument)) {
return NonInjectionManager.this.getInstance((Class) actualTypeArgument);
} else {
return NonInjectionManager.this.getInstance(actualTypeArgument);
}
}
});
@Override
public Object get() {
return supplier.get(); //Not disposable
}
};
}
}
return super.create();
}
}
/**
* A triplet of created instance, the registered {@link Binding} that prescribed the creation of the instance
* and {@link Annotation qualifiers} the instance was created with.
* @param type of the instance.
* @see NonInjectionManager#getInstance(Class, Annotation[])
*/
private static class InstanceContext {
private final T instance;
private final Binding binding;
private final Annotation[] createdWithQualifiers;
private InstanceContext(T instance, Binding binding, Annotation[] qualifiers) {
this.instance = instance;
this.binding = binding;
this.createdWithQualifiers = qualifiers;
}
public Binding getBinding() {
return binding;
}
public T getInstance() {
return instance;
}
@SuppressWarnings("unchecked")
static List toInstances(List> instances, Annotation[] qualifiers) {
return instances != null
? instances.stream()
.filter(instance -> instance.hasQualifiers(qualifiers))
.map(pair -> (T) pair.getInstance())
.collect(Collectors.toList())
: null;
}
private static List> filterInstances(List> instances, Annotation... qualifiers) {
return instances != null
? instances.stream()
.filter(instance -> instance.hasQualifiers(qualifiers))
.collect(Collectors.toList())
: null;
}
private boolean hasQualifiers(Annotation[] requested) {
if (requested != null) {
classLoop:
for (Annotation req : requested) {
if (createdWithQualifiers != null) {
for (Annotation cur : createdWithQualifiers) {
if (cur.annotationType().isInstance(req)) {
continue classLoop;
}
}
return false;
}
}
}
return true;
}
}
/**
* Singleton Binding this {@link NonInjectionManager} was supposed to be created based upon.
*/
private static final class InjectionManagerBinding extends Binding> {
}
}