toothpick.ScopeNode Maven / Gradle / Ivy
Show all versions of toothpick-runtime Show documentation
/*
* Copyright 2019 Stephane Nicolas
* Copyright 2019 Daniel Molinero Reguera
*
* 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 toothpick;
import static java.lang.String.format;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.inject.Provider;
import javax.inject.Singleton;
import toothpick.config.Module;
/**
* A scope is one of the most important concept in Toothpick. It is actually important in Dependency
* Injection at large and Toothpick exposes it to developers.
*
* Conceptually a scope contains {@link toothpick.config.Binding}s & scoped instances :
*
*
* - binding
*
- is way to express that a class {@code Foo} is bound to an implementation {@code Bar}. It
* means that writing {@code @Inject Foo a;} will return a {@code Bar}. Bindings are valid for
* the scope where there are defined, and inherited by children scopes. Children scopes can
* override any binding inherited from of a parent. {@link Module}s allow to define {@link
* toothpick.config.Binding}s and are installed in scopes.
*
- scoped instance
*
- a scoped instance is an instance that is reused for all injection of a given class. Not all
* bindings create scoped instances. Bindings {@code Foo} to an instance or to a {@link
* Provider} instance means that those instances will be recycled every time we inject {@code
* Foo} from this scope. Scoped instances are all lazily initialized on first injection
* request.
*
*
* In toothpick, Scopes create a tree (actually a disjoint forest). Each scope can have children
* scopes. Operations on the scope tree (adding / removing children, etc.) are non thread safe. The
* implementation of Toothpick provides a {@code Toothpick} class that wraps these operations in a
* thread safe way.
*
*
Scopes can be support scope annotations: annotation classes qualified by the {@link
* javax.inject.Scope} annotation. All classes annotated by this annotation will automatically be
* scoped by Toothpick in the scope that supports them.
*
*
Classes that are not annotated with a {@link javax.inject.Scope} annotation, also called
* un-scoped classes, are not associated to a particular scope and can be used in all scopes. Their
* instances are not recycled, every injection provides a different instance. Scoping a class by
* annotation is conceptually exactly the same as binding it to itself in a scope.
*
*
Scope resolution : when a class is scoped, either by binding it in a module and then
* installing this module in a scope, or by adding a {@link javax.inject.Scope} annotation, it means
* that all its dependencies must be found in the scope itself or a parent scope. Otherwise,
* Toothpick will crash at runtime when first instantiating this class. The only other allowed
* alternative is to have an un-scoped dependency.
*/
public abstract class ScopeNode implements Scope {
// lock free children. A Concurrent HashMap is better than a list here as
// we need to know atomically which value could be already in the map
protected final ConcurrentHashMap